#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 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& 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 issuedCert = std::make_unique(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 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& 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