452 lines
13 KiB
C
452 lines
13 KiB
C
|
|
#ifndef __CERTIFICATE_H
|
||
|
|
#define __CERTIFICATE_H
|
||
|
|
|
||
|
|
#include "ecc.h"
|
||
|
|
#include "bitstruct.h"
|
||
|
|
#include "except.h"
|
||
|
|
#include "base64.h"
|
||
|
|
#include "sdkregistration.h"
|
||
|
|
#include "download.h"
|
||
|
|
|
||
|
|
#include <time.h>
|
||
|
|
|
||
|
|
using namespace ECC;
|
||
|
|
|
||
|
|
class Certificate
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
Certificate()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
Certificate(const char * base64Certificate)
|
||
|
|
{
|
||
|
|
|
||
|
|
BASE64 base64;
|
||
|
|
int len;
|
||
|
|
|
||
|
|
auto buf = base64.decode(base64Certificate, strlen(base64Certificate), &len);
|
||
|
|
|
||
|
|
if (buf.empty())
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 encoding for certificate");
|
||
|
|
|
||
|
|
Attach(buf, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
Certificate(vector<unsigned char>& buf, int len)
|
||
|
|
{
|
||
|
|
Attach(buf, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
void* GetBuffer(int * len)
|
||
|
|
{
|
||
|
|
int size;
|
||
|
|
void * buf = m_certBits.GetBuffer(&size);
|
||
|
|
size = (size + 7) >> 3;
|
||
|
|
*len = size;
|
||
|
|
return buf;
|
||
|
|
}
|
||
|
|
|
||
|
|
const char * ToString()
|
||
|
|
{
|
||
|
|
|
||
|
|
BASE64 base64;
|
||
|
|
int len;
|
||
|
|
static string base64cert;
|
||
|
|
unsigned char * buf = (unsigned char *)m_certBits.GetBuffer(&len);
|
||
|
|
len = (len + 7) >> 3;
|
||
|
|
|
||
|
|
auto base64Buf = base64.encode(buf, len, true);
|
||
|
|
|
||
|
|
if (base64Buf.empty())
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
|
||
|
|
|
||
|
|
base64cert = base64Buf.c_str();
|
||
|
|
|
||
|
|
return base64cert.c_str();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
static Certificate * Generate(int signatureSize, time_t expirationDate = 0)
|
||
|
|
{
|
||
|
|
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, NULL, expirationDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
static Certificate * Generate(int signatureSize, Certificate * signingCertificate, time_t expirationDate = 0)
|
||
|
|
{
|
||
|
|
return Generate(signatureSize, NULL, NULL, signingCertificate, NULL, expirationDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
static Certificate * Generate(int signatureSize, const char * certificateAuthorityUrl, time_t expirationDate = 0)
|
||
|
|
{
|
||
|
|
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, certificateAuthorityUrl, expirationDate);
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
|
||
|
|
static bool VerifySignature(Certificate * cert, Certificate * validationCert)
|
||
|
|
{
|
||
|
|
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
|
||
|
|
|
||
|
|
if (validationCert == NULL || cert->m_certBits.GetInt("IsSelfSigned") != 0)
|
||
|
|
cert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
|
||
|
|
else
|
||
|
|
validationCert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
|
||
|
|
|
||
|
|
Key key(rawPublicKey, rawPublicKeyLen);
|
||
|
|
|
||
|
|
Verifier verifier;
|
||
|
|
|
||
|
|
verifier.SetPublicKey(&key);
|
||
|
|
|
||
|
|
unsigned char * certBuffer = (unsigned char *)cert->m_certBits.GetBuffer();
|
||
|
|
|
||
|
|
int signedPartLen = 4 + cert->m_certBits.GetInt("PublicKeyLen"),
|
||
|
|
signatureOffset = 2 + signedPartLen,
|
||
|
|
signatureBitLen = cert->m_certBits.GetInt("SignatureSizeBits");
|
||
|
|
|
||
|
|
if (!verifier.Verify(certBuffer, signedPartLen, certBuffer + signatureOffset, (signatureBitLen + 7) >> 3, signatureBitLen))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GetPublicKey(void * buf, int * len)
|
||
|
|
{
|
||
|
|
m_certBits.Get("PublicKey", buf, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
static Certificate * Generate(int signatureSize, const char * base64PrivateKey, const char * base64PublicKey, const char * base64SigningPrivateKey, const char * base64SigningCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||
|
|
{
|
||
|
|
Key * privateKey = NULL,
|
||
|
|
* publicKey = NULL,
|
||
|
|
* privateSigningKey;
|
||
|
|
|
||
|
|
Certificate * signingCertificate = NULL;
|
||
|
|
Certificate * result;
|
||
|
|
|
||
|
|
try {
|
||
|
|
if (base64PublicKey != NULL)
|
||
|
|
publicKey = new Key(base64PublicKey);
|
||
|
|
|
||
|
|
if (base64PrivateKey != NULL)
|
||
|
|
privateKey = new Key(base64PrivateKey);
|
||
|
|
|
||
|
|
if (base64SigningPrivateKey != NULL)
|
||
|
|
privateSigningKey = new Key(base64SigningPrivateKey);
|
||
|
|
|
||
|
|
if (base64SigningCertificate != NULL)
|
||
|
|
signingCertificate = new Certificate(base64SigningCertificate);
|
||
|
|
|
||
|
|
result = Generate(signatureSize, privateKey, publicKey, privateSigningKey, signingCertificate, certificateAuthorityUrl, expirationDate);
|
||
|
|
} catch (...)
|
||
|
|
{
|
||
|
|
if (privateKey) delete privateKey;
|
||
|
|
if (publicKey) delete publicKey;
|
||
|
|
if (privateSigningKey) delete privateSigningKey;
|
||
|
|
if (signingCertificate) delete signingCertificate;
|
||
|
|
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (privateKey) delete privateKey;
|
||
|
|
if (publicKey) delete publicKey;
|
||
|
|
if (privateSigningKey) delete privateSigningKey;
|
||
|
|
if (signingCertificate) delete signingCertificate;
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
static Certificate * Generate(int signatureSize, Key * privateKey, Key * publicKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||
|
|
{
|
||
|
|
|
||
|
|
|
||
|
|
if (publicKey == NULL)
|
||
|
|
{
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "public key must be provided for the certificate");
|
||
|
|
}
|
||
|
|
|
||
|
|
Key * signingKey = NULL;
|
||
|
|
bool selfSigned;
|
||
|
|
|
||
|
|
if (signingPrivateKey == NULL && certificateAuthorityUrl == NULL)
|
||
|
|
{
|
||
|
|
selfSigned = true;
|
||
|
|
signingKey = privateKey;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
selfSigned = false;
|
||
|
|
if (signingPrivateKey != NULL)
|
||
|
|
signingKey = signingPrivateKey;
|
||
|
|
// else use certificate authority url for signing
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
|
||
|
|
publicKey->Store(rawPublicKey, &rawPublicKeyLen);
|
||
|
|
|
||
|
|
// unsigned char rawPrivateKey[256]; int rawPrivateKeyLen = 256;
|
||
|
|
// signingKey->Store(rawPrivateKey, &rawPrivateKeyLen);
|
||
|
|
|
||
|
|
int certBitsLen = 4 * 8 + rawPublicKeyLen * 8;
|
||
|
|
|
||
|
|
BitStruct certBits(certBitsLen);
|
||
|
|
|
||
|
|
certBits.ResetFieldOffset();
|
||
|
|
|
||
|
|
certBits.AddField("Version", BitStruct::INTEGER, 4);
|
||
|
|
certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
|
||
|
|
certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
|
||
|
|
certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
|
||
|
|
certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
|
||
|
|
certBits.AddField("PublicKey", BitStruct::RAW, rawPublicKeyLen * 8);
|
||
|
|
|
||
|
|
certBits.Set("Version", 0);
|
||
|
|
certBits.Set("IsSelfSigned", (selfSigned) ? 1 : 0);
|
||
|
|
certBits.Set("ReservedFlags", 0);
|
||
|
|
|
||
|
|
expirationDate = time(NULL);
|
||
|
|
|
||
|
|
struct tm * t = gmtime(&expirationDate);
|
||
|
|
|
||
|
|
certBits.Set("ExpirationDate", t->tm_year + 1900, t->tm_mon, t->tm_mday);
|
||
|
|
certBits.Set("PublicKeyLen", rawPublicKeyLen);
|
||
|
|
certBits.Set("PublicKey", rawPublicKey, rawPublicKeyLen);
|
||
|
|
|
||
|
|
unsigned char certSignature[256];
|
||
|
|
int sigSizeBytes = 256;
|
||
|
|
int sigSizeBits;
|
||
|
|
|
||
|
|
if (signingKey != NULL)
|
||
|
|
{
|
||
|
|
Signer signer;
|
||
|
|
signer.SetPrivateKey(signingKey);
|
||
|
|
signer.Sign(certBits.GetBuffer(), (certBitsLen + 7) >> 3, certSignature, &sigSizeBytes, &sigSizeBits);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#ifndef LICENSING_NO_NETWORKING
|
||
|
|
if (!certificateAuthorityUrl)
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "no means for certificate signing were provided");
|
||
|
|
|
||
|
|
string certificateAuthorityRequest(certificateAuthorityUrl);
|
||
|
|
certificateAuthorityRequest.append("?csr=");
|
||
|
|
BASE64 base64;
|
||
|
|
int len = 4096;
|
||
|
|
char buffer[4096];
|
||
|
|
|
||
|
|
auto base64csr = base64.encode((unsigned char *)certBits.GetBuffer(), (certBits.GetSize() + 7) >> 3, true);
|
||
|
|
string escapedBase64csr(base64csr.c_str());
|
||
|
|
|
||
|
|
StrReplace(escapedBase64csr, "+", "%2B");
|
||
|
|
StrReplace(escapedBase64csr, "/", "%2F");
|
||
|
|
StrReplace(escapedBase64csr, "=", "%3D");
|
||
|
|
|
||
|
|
certificateAuthorityRequest.append(escapedBase64csr);
|
||
|
|
|
||
|
|
const char * sdkLicenseKey = SDKRegistrationImpl::GetLicenseKey();
|
||
|
|
|
||
|
|
if (sdkLicenseKey && strlen(sdkLicenseKey) > 0)
|
||
|
|
{
|
||
|
|
certificateAuthorityRequest.append("&sdklicensekey=");
|
||
|
|
certificateAuthorityRequest.append(sdkLicenseKey);
|
||
|
|
}
|
||
|
|
|
||
|
|
UrlDownloadToString(certificateAuthorityRequest.c_str(), buffer, &len);
|
||
|
|
|
||
|
|
auto rawBuffer = base64.decode(buffer, len, &len);
|
||
|
|
|
||
|
|
if (rawBuffer.empty())
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 string");
|
||
|
|
|
||
|
|
auto certBuffer = rawBuffer;
|
||
|
|
|
||
|
|
unique_ptr<Certificate> issuedCert = std::make_unique<Certificate>(certBuffer, len);
|
||
|
|
|
||
|
|
sigSizeBits = issuedCert->m_certBits.GetInt("SignatureSizeBits");
|
||
|
|
sigSizeBytes = (sigSizeBits + 7) >> 3;
|
||
|
|
issuedCert->m_certBits.Get("Signature", certSignature, &sigSizeBytes);
|
||
|
|
|
||
|
|
memcpy(certBits.GetBuffer(), rawBuffer.data(), 4 + rawPublicKeyLen);
|
||
|
|
#else
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signing private key not provided");
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
int certBufLen = ((certBitsLen + 7) >> 3) // header + public key
|
||
|
|
+ 2 // signature size in bits
|
||
|
|
+ ((sigSizeBits + 7) >> 3); // signature
|
||
|
|
|
||
|
|
vector<unsigned char> certBuf;
|
||
|
|
certBuf.resize(certBufLen);
|
||
|
|
|
||
|
|
memcpy(certBuf.data(), certBits.GetBuffer(), (certBitsLen + 7) >> 3);
|
||
|
|
|
||
|
|
certBits.Attach(certBuf, certBufLen * 8);
|
||
|
|
|
||
|
|
certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
|
||
|
|
certBits.AddField("Signature", BitStruct::RAW, ((sigSizeBits + 7) >> 3) << 3);
|
||
|
|
|
||
|
|
certBits.Set("SignatureSizeBits", sigSizeBits);
|
||
|
|
certBits.Set("Signature", certSignature, (sigSizeBits + 7) >> 3);
|
||
|
|
|
||
|
|
Certificate * cert = new Certificate();
|
||
|
|
|
||
|
|
cert->m_certBits = std::move(certBits);
|
||
|
|
|
||
|
|
return cert;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const char * Sign(const char * csr, const char * privateKey, const char * signingPrivateKey, const char * signingCertificate, const char * certificateAuthorityUrl, int expYear, int expMonth, int expDay)
|
||
|
|
{
|
||
|
|
Certificate * _csr = new Certificate(csr);
|
||
|
|
Key * _privateKey = (privateKey) ? new Key(privateKey) : NULL;
|
||
|
|
Key * _signingPrivateKey = (signingPrivateKey) ? new Key(signingPrivateKey) : NULL;
|
||
|
|
Certificate * _signingCertificate = (signingCertificate) ? new Certificate(signingCertificate) : NULL;
|
||
|
|
struct tm _expTm;
|
||
|
|
time_t _expTime = 0;
|
||
|
|
|
||
|
|
if (expYear >= 1900 && expMonth >= 1 && expMonth <= 12 && expDay >= 1 && expDay <= 31)
|
||
|
|
{
|
||
|
|
memset(&_expTm, 0, sizeof(_expTm));
|
||
|
|
|
||
|
|
_expTm.tm_year = expYear - 1900;
|
||
|
|
_expTm.tm_mon = expMonth - 1;
|
||
|
|
_expTm.tm_mday = expDay;
|
||
|
|
|
||
|
|
_expTime = mktime(&_expTm);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
if (expYear != 0 || expMonth != 0 || expDay != 0)
|
||
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "Invalid certificate expiration date");
|
||
|
|
|
||
|
|
Certificate * _signedCert = Sign(_csr, _privateKey, _signingPrivateKey, _signingCertificate, certificateAuthorityUrl, 0);
|
||
|
|
|
||
|
|
if (_csr) delete _csr;
|
||
|
|
if (_privateKey) delete _privateKey;
|
||
|
|
if (_signingPrivateKey) delete _signingPrivateKey;
|
||
|
|
if (_signingCertificate) delete _signingCertificate;
|
||
|
|
|
||
|
|
const char * signedCert = _signedCert->ToString();
|
||
|
|
|
||
|
|
delete _signedCert;
|
||
|
|
|
||
|
|
return signedCert;
|
||
|
|
}
|
||
|
|
|
||
|
|
static Certificate * Sign(Certificate * csr, Key * privateKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
|
||
|
|
{
|
||
|
|
unsigned char buf[1024];
|
||
|
|
int len = 1024;
|
||
|
|
Key * publicKey;
|
||
|
|
|
||
|
|
csr->GetPublicKey(buf, &len);
|
||
|
|
publicKey = new Key(buf, len);
|
||
|
|
|
||
|
|
Certificate * cert = Certificate::Generate(0, privateKey, publicKey, signingPrivateKey, signingCertificate, certificateAuthorityUrl, expirationDate);
|
||
|
|
|
||
|
|
delete publicKey;
|
||
|
|
|
||
|
|
return cert;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
void Attach(vector<unsigned char>& buf, int len)
|
||
|
|
{
|
||
|
|
m_certBits.Attach(buf, len << 3);
|
||
|
|
|
||
|
|
m_certBits.ResetFieldOffset();
|
||
|
|
|
||
|
|
m_certBits.AddField("Version", BitStruct::INTEGER, 4);
|
||
|
|
m_certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
|
||
|
|
m_certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
|
||
|
|
m_certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
|
||
|
|
m_certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
|
||
|
|
m_certBits.AddField("PublicKey", BitStruct::RAW, m_certBits.GetInt("PublicKeyLen") * 8);
|
||
|
|
|
||
|
|
int signedPartLen = (m_certBits.GetCurrentFieldOffset() + 7) >> 3;
|
||
|
|
|
||
|
|
if (len <= signedPartLen)
|
||
|
|
return;
|
||
|
|
|
||
|
|
m_certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
|
||
|
|
|
||
|
|
int signatureBitLen = m_certBits.GetInt("SignatureSizeBits");
|
||
|
|
int signatureLen = (signatureBitLen + 7) >> 3;
|
||
|
|
|
||
|
|
int signatureOffset = m_certBits.GetCurrentFieldOffset() >> 3;
|
||
|
|
|
||
|
|
m_certBits.AddField("Signature", BitStruct::RAW, signatureLen << 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
static ECC::KEY_TYPE GetKeyType(int sigSize)
|
||
|
|
{
|
||
|
|
if (sigSize < 76 || sigSize > 322)
|
||
|
|
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
|
||
|
|
|
||
|
|
ECC::KEY_TYPE keyType;
|
||
|
|
int keySize;
|
||
|
|
|
||
|
|
if (sigSize <= 108)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_54;
|
||
|
|
keySize = 54;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 146)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_73;
|
||
|
|
keySize = 73;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 158)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_79;
|
||
|
|
keySize = 79;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 182)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_91;
|
||
|
|
keySize = 91;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 200)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_100;
|
||
|
|
keySize = 100;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 240)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_120;
|
||
|
|
keySize = 120;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 262)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_131;
|
||
|
|
keySize = 131;
|
||
|
|
} else
|
||
|
|
if (sigSize <= 282)
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_141;
|
||
|
|
keySize = 141;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
keyType = ECC::ECC_161;
|
||
|
|
keySize = 161;
|
||
|
|
}
|
||
|
|
|
||
|
|
return keyType;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void StrReplace(string& str, const string& oldStr, const string& newStr)
|
||
|
|
{
|
||
|
|
size_t pos = 0;
|
||
|
|
while((pos = str.find(oldStr, pos)) != std::string::npos)
|
||
|
|
{
|
||
|
|
str.replace(pos, oldStr.length(), newStr);
|
||
|
|
pos += newStr.length();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BitStruct m_certBits;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif
|