Files

529 lines
11 KiB
C
Raw Permalink Normal View History

2026-03-28 16:54:11 +11:00
#pragma once
#include <memory>
#include <map>
#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<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_dataFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::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<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_validationFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::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<Certificate>(base64Certificate);
ValidateCertificate();
unsigned char keyBuf[256]; int keyLen = 256;
m_certificate->GetPublicKey(keyBuf, &keyLen);
m_verificationKey = make_unique<ECC::Key>(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<string, FieldInfo> m_dataFields;
int m_defaultDataOffset;
map<string, FieldInfo> m_validationFields;
int m_defaultValidationOffset;
// key signature
unique_ptr<ECC::Key> m_verificationKey;
unique_ptr<ECC::Key> m_signingKey;
unique_ptr<Certificate> 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<Certificate> validationCertificate = make_unique<Certificate>("AE4vDQELjMGgCJew5QSVMBWSAN2PaBa0zzYpjSYe0rcu88lYggE=");
if (!Certificate::VerifySignature(m_certificate.get(), validationCertificate.get()))
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signature is not valid");
}
};