#pragma once #include #include #include "ecc.h" #include "base64.h" #include "uniconv.h" #include "except.h" #include "sdkregistration.h" #include "certificate.h" #include "propertycollection.h" using namespace std; class LicenseTemplateImpl { friend LicenseTemplate; struct FieldInfo { FieldInfo(int _type, int _size, int _offset) { type = (BitStruct::FIELD_TYPE)_type; size = _size; offset = _offset; } BitStruct::FIELD_TYPE type; int size; int offset; }; public: LicenseTemplateImpl(const char * xmlTemplate = NULL): m_defaultDataOffset(0), m_defaultValidationOffset(0) { Init(); if (xmlTemplate) LoadXml(xmlTemplate); } void SetVersion(int version) { if (version > 3) throw new LicensingException(STATUS_UNSUPPORTED_VERSION); m_version = version; } unsigned GetVersion() const { return m_version; } void SetNumberOfGroups(int numGroups) { m_numGroups = numGroups; } unsigned GetNumberOfGroups() const { return m_numGroups; } void SetCharactersPerGroup(int charsPerGroup) { m_charsPerGroup = charsPerGroup; } unsigned GetCharactersPerGroup() const { return m_charsPerGroup; } void SetGroupSeparator(const char * groupSep) { m_groupSeparator = groupSep; } const char * GetGroupSeparator() const { return m_groupSeparator.c_str(); } void SetEncoding(int encoding) { m_keyEncoding = encoding; } int GetEncoding() const { return m_keyEncoding; } void SetHeader(const char * header) { m_header = header; } const char * GetHeader() const { return m_header.c_str(); } void SetFooter(const char * footer) { m_footer = footer; } const char * GetFooter() const { return m_footer.c_str(); } void SetDataSize(int sizeInBits) { m_dataSize = sizeInBits; } unsigned GetDataSize() const { return m_dataSize; } void AddDataField(const char * fieldName, int fieldType, int fieldSizeInBits, int fieldOffset = -1) { if (fieldOffset < 0) fieldOffset = m_defaultDataOffset; m_dataFields.emplace(std::piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldSizeInBits, fieldOffset)); m_defaultDataOffset += fieldSizeInBits; } bool GetDataField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const { auto info = m_dataFields.find(fieldName); if (info == m_dataFields.end()) return false; *fieldType = info->second.type; *fieldSizeInBits = info->second.size; *fieldOffset = info->second.offset; return true; } bool EnumDataFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const { map::const_iterator* pIter; static string name; if (*enumHandle == NULL) { pIter = new map::const_iterator(m_dataFields.begin()); if (!pIter) return false; } else pIter = (map::const_iterator*)(*enumHandle); if (*pIter == m_dataFields.end()) { delete pIter; return false; } name = (*pIter)->first; *fieldName = name.c_str(); *fieldType = (*pIter)->second.type; *fieldSizeInBits = (*pIter)->second.size; *fieldOffset = (*pIter)->second.offset; pIter->operator ++(); // *Iter++ does not work. Think why :) *enumHandle = pIter; return true; } void SetValidationDataSize(int sizeInBits) { m_validationDataSize = sizeInBits; } unsigned GetValidationDataSize() const { return m_validationDataSize; } void AddValidationField(const char * fieldName, int fieldType, int fieldBitSize, int fieldOffset = 0) { if (fieldOffset < 0) fieldOffset = m_defaultValidationOffset; m_validationFields.emplace(piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldBitSize, fieldOffset)); m_defaultValidationOffset += fieldBitSize; } bool GetValidationField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const { auto info = m_validationFields.find(fieldName); if (info == m_validationFields.end()) return false; *fieldType = info->second.type; *fieldSizeInBits = info->second.size; *fieldOffset = info->second.offset; return true; } bool EnumValidationFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSize, int * fieldOffset) const { map::const_iterator* pIter; static string name; if (*enumHandle == NULL) { pIter = new map::const_iterator(m_validationFields.begin()); if (!pIter) return false; } else pIter = (map::const_iterator*)(*enumHandle); if (*pIter == m_validationFields.end()) { delete pIter; return false; } name = (*pIter)->first; *fieldName = name.c_str(); *fieldType = (*pIter)->second.type; *fieldSize = (*pIter)->second.size; *fieldOffset = (*pIter)->second.offset; pIter->operator ++(); // *Iter++ does not work. Think why :) *enumHandle = pIter; return true; } void SetSignatureSize(int sizeInBits) { if (sizeInBits < 76 || sizeInBits > 322) throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE); m_signatureSize = sizeInBits; if (sizeInBits <= 108) { m_signatureKeyType = ECC::ECC_54; m_signatureKeySize = 54; } else if (sizeInBits <= 146) { m_signatureKeyType = ECC::ECC_73; m_signatureKeySize = 73; } else if (sizeInBits <= 158) { m_signatureKeyType = ECC::ECC_79; m_signatureKeySize = 79; } else if (sizeInBits <= 182) { m_signatureKeyType = ECC::ECC_91; m_signatureKeySize = 91; } else if (sizeInBits <= 200) { m_signatureKeyType = ECC::ECC_100; m_signatureKeySize = 100; } else if (sizeInBits <= 240) { m_signatureKeyType = ECC::ECC_120; m_signatureKeySize = 120; } else if (sizeInBits <= 262) { m_signatureKeyType = ECC::ECC_131; m_signatureKeySize = 131; } else if (sizeInBits <= 282) { m_signatureKeyType = ECC::ECC_141; m_signatureKeySize = 141; } else { m_signatureKeyType = ECC::ECC_161; m_signatureKeySize = 161; } } unsigned GetSignatureSize() const { return m_signatureSize; } void LoadXml(const char * xmlTemplate); const char * SaveXml(bool savePrivateKey); void LoadJson(const char * jsonTemplate); const char * SaveJson(bool savePrivateKey); void SetLicensingServiceUrl(const char * url) { m_licensingServiceUrl = url; } const char * GetLicensingServiceUrl() const { return m_licensingServiceUrl.c_str(); } void SetTemplateId(const char * templateId) { m_templateId = templateId; } const char * GetTemplateId() const { return m_templateId.c_str(); } void SetLicensingServiceParameters(const char * params) { m_licensingServiceParameters = params; } void SetLicenseGracePeriod(int days) { m_licenseGracePeriod = days; } int GetLicenseGracePeriod() const { return m_licenseGracePeriod; } void SetPublicKeyCertificate(const char * base64Certificate) { m_certificate = make_unique(base64Certificate); ValidateCertificate(); unsigned char keyBuf[256]; int keyLen = 256; m_certificate->GetPublicKey(keyBuf, &keyLen); m_verificationKey = make_unique(keyBuf, keyLen); } const char * GetPublicKeyCertificate() const { if (!m_certificate) throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a certificate"); return m_certificate->ToString(); } void SetPrivateKey(const char * base64Key) { BASE64 base64; int keyLen; int keyLenSizeT; auto keyData = base64.decode(base64Key, (unsigned)strlen(base64Key), &keyLenSizeT); if (keyData.empty()) throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 private key"); keyLen = (unsigned)keyLenSizeT; SetPrivateKey(keyData.data(), keyLen); } const char * GetPrivateKey() const { if (!m_signingKey) throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a private key"); return m_signingKey->ToString(); } void GenerateSigningKeyPair() { Key * privateKey = NULL, * publicKey = NULL; if (!SDKRegistrationImpl::IsRegistered()) { privateKey = new Key(); privateKey->Load(&m_demoPrivateKeys[m_signatureKeyType][1], m_demoPrivateKeys[m_signatureKeyType][0], m_signatureKeyType); publicKey = new Key(); publicKey->Load(&m_demoPublicKeys[m_signatureKeyType][1], m_demoPublicKeys[m_signatureKeyType][0], m_signatureKeyType); } else { ECC::GenerateKeyPair(m_signatureKeyType, &privateKey, &publicKey); } m_certificate.reset(Certificate::Generate(m_signatureSize, privateKey, publicKey, NULL, NULL, NULL, 0)); ValidateCertificate(); m_signingKey.reset(privateKey); m_verificationKey.reset(publicKey); } void SetProperty(const char * path, const char * name, const char * value) { m_properties.SetProperty(path, name, value); } const char * GetProperty(const char * path, const char * name) const { return m_properties.GetProperty(path, name); } public: // general int m_version; // key format int m_numGroups; int m_charsPerGroup; int m_keyEncoding; string m_groupSeparator; string m_header; string m_footer; string m_licensingServiceUrl; string m_templateId; string m_licensingServiceParameters; map m_dataFields; int m_defaultDataOffset; map m_validationFields; int m_defaultValidationOffset; // key signature unique_ptr m_verificationKey; unique_ptr m_signingKey; unique_ptr m_certificate; bool m_hasPrivateKey; ECC::KEY_TYPE m_signatureKeyType; int m_signatureKeySize; int m_signatureSize; int m_dataSize; int m_validationDataSize; // buffer used to hold the xml representation of the template string m_xmlTemplate; // other stuff int m_licenseGracePeriod; PropertyCollection m_properties; protected: static const unsigned char m_demoPublicKeys[10][23]; static const unsigned char m_demoPrivateKeys[10][23]; private: void Init() { SetVersion(3); SetLicenseGracePeriod(0); SetGroupSeparator("-"); SetNumberOfGroups(6); SetCharactersPerGroup(6); SetEncoding(ENCODING_BASE32X); SetSignatureSize(158); SetDataSize(22); // 6 groups * 6 chars per group * 5 bits per char - 158 signature size = 22 data size SetValidationDataSize(0); m_hasPrivateKey = false; } void SetPrivateKey(const void * keyBuf, int keyLen) { ValidatePrivateKey(keyBuf, keyLen); m_signingKey.reset(new Key(keyBuf, keyLen)); m_hasPrivateKey = true; } void ValidatePrivateKey(const void * keyBuf, int keyLen) { if (keyLen <= 2) { throw new LicensingException(STATUS_INVALID_PARAM, "Invalid private key length"); } keyLen -= 2; keyBuf = (unsigned char *)keyBuf + 2; if (!SDKRegistrationImpl::IsRegistered()) { if (keyLen != m_demoPrivateKeys[m_signatureKeyType][0] || memcmp(keyBuf, &m_demoPrivateKeys[m_signatureKeyType][1], keyLen) != 0) { m_signingKey.reset(); throw new LicensingException(STATUS_INVALID_PARAM, "Invalid public/private key. The SDK is in DEMO mode because a SDK license key was not set. In this mode, only certain public/private keys can be set. Did you set a valid SDK license key via ANSCENTER::Licensing::SDKRegistration::SetLicenseKey() ?"); } } } void ValidateCertificate() { unique_ptr validationCertificate = make_unique("AE4vDQELjMGgCJew5QSVMBWSAN2PaBa0zzYpjSYe0rcu88lYggE="); if (!Certificate::VerifySignature(m_certificate.get(), validationCertificate.get())) throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signature is not valid"); } };