Refactor project structure
This commit is contained in:
528
core/anslicensing/template.h
Normal file
528
core/anslicensing/template.h
Normal file
@@ -0,0 +1,528 @@
|
||||
#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");
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user