From 3217ac7d51b8f40b37973c3356597c120407a0dc Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Fri, 28 Jul 2023 12:09:51 +0300 Subject: [PATCH] Add method for cert&key generation --- .../xmlsec/src/include/CertificateCommon.h | 2 + .../xmlsec/src/include/openssl_config.h | 1 + .../xmlsec/src/src/CertificateCommon.cpp | 15 ++ .../xmlsec/src/src/Certificate_openssl.h | 144 ++++++++++++++++++ DesktopEditor/xmlsec/src/test/main.cpp | 74 +++++---- 5 files changed, 203 insertions(+), 33 deletions(-) diff --git a/DesktopEditor/xmlsec/src/include/CertificateCommon.h b/DesktopEditor/xmlsec/src/include/CertificateCommon.h index 644d9a423d..079efbfcb2 100644 --- a/DesktopEditor/xmlsec/src/include/CertificateCommon.h +++ b/DesktopEditor/xmlsec/src/include/CertificateCommon.h @@ -42,6 +42,8 @@ namespace NSCertificate OPENSSL_DECL std::wstring GetSignatureMethod(const int& nAlg); OPENSSL_DECL ICertificate* CreateInstance(const int& type = CERTIFICATE_ENGINE_TYPE_DEFAULT); + + OPENSSL_DECL ICertificate* GenerateByAlg(const std::string& key_alg, const std::map& props = std::map()); }; #endif // _XML_CERTIFICATE_COMMON_H_ diff --git a/DesktopEditor/xmlsec/src/include/openssl_config.h b/DesktopEditor/xmlsec/src/include/openssl_config.h index 0221ea206d..49e5500d9a 100644 --- a/DesktopEditor/xmlsec/src/include/openssl_config.h +++ b/DesktopEditor/xmlsec/src/include/openssl_config.h @@ -3,6 +3,7 @@ #include #include +#include #include "../../../common/base_export.h" #ifdef COMMON_OPENSSL_BUILDING_INTERNAL diff --git a/DesktopEditor/xmlsec/src/src/CertificateCommon.cpp b/DesktopEditor/xmlsec/src/src/CertificateCommon.cpp index 20ab7a8885..5091110b65 100644 --- a/DesktopEditor/xmlsec/src/src/CertificateCommon.cpp +++ b/DesktopEditor/xmlsec/src/src/CertificateCommon.cpp @@ -317,6 +317,21 @@ namespace NSCertificate return NULL; } + + ICertificate* GenerateByAlg(const std::string& key_alg, const std::map& props) + { +#ifdef SUPPORT_OPENSSL + CCertificate_openssl* pCert = new CCertificate_openssl(); + bool bIsGenerated = pCert->Generate(key_alg, props); + if (!bIsGenerated) + { + delete pCert; + return NULL; + } + return pCert; +#endif + return NULL; + } }; #ifdef SUPPORT_OPENSSL diff --git a/DesktopEditor/xmlsec/src/src/Certificate_openssl.h b/DesktopEditor/xmlsec/src/src/Certificate_openssl.h index d0e369a339..180dc93a1a 100644 --- a/DesktopEditor/xmlsec/src/src/Certificate_openssl.h +++ b/DesktopEditor/xmlsec/src/src/Certificate_openssl.h @@ -24,6 +24,8 @@ #include #include +#include + const EVP_MD* Get_EVP_MD(int nAlg) { switch (nAlg) @@ -121,6 +123,148 @@ public: EVP_PKEY_FREE(m_key); } + bool Generate(const std::string& key_alg, const std::map& props = std::map()) + { + EVP_PKEY_CTX* pctx = nullptr; + int nRsaKeyLen = 0; + + if (key_alg == "ed25519") + { + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); + m_alg = OOXML_HASH_ALG_ED25519; + } + else if (key_alg == "x25519") + { + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + m_alg = OOXML_HASH_ALG_ED448; + } + else if (0 == key_alg.find("rsa")) + { + pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + std::string sKeyLen = key_alg.substr(3); + nRsaKeyLen = 2048; + if (!sKeyLen.empty()) + nRsaKeyLen = std::stoi(sKeyLen); + + m_alg = OOXML_HASH_ALG_SHA256; + } + else + return false; + + EVP_PKEY_keygen_init(pctx); + + if (0 != nRsaKeyLen && EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, nRsaKeyLen) <= 0) + return false; + + EVP_PKEY_keygen(pctx, &m_key); + + m_cert = X509_new(); + X509_set_version(m_cert, 2); + + ASN1_STRING* serialNumber = X509_get_serialNumber(m_cert); + if (serialNumber) + { + const int nBytesCount = 16; + unsigned char pSerialNumber[nBytesCount]; + RAND_bytes(pSerialNumber, nBytesCount); + + if (1 != ASN1_STRING_set(serialNumber, pSerialNumber, nBytesCount) == 1) + ASN1_INTEGER_set(serialNumber, 1); + } + + X509_gmtime_adj(X509_get_notBefore(m_cert), 0); + X509_gmtime_adj(X509_get_notAfter(m_cert), 31536000L); + + if (X509_set_pubkey(m_cert, m_key) == 0) + { + if (NULL != m_cert) + X509_free(m_cert); + m_cert = NULL; + + if (NULL != m_key) + EVP_PKEY_free(m_key); + m_key = NULL; + + EVP_PKEY_CTX_free(pctx); + return false; + } + + X509_NAME* name_record = X509_get_subject_name(m_cert); + + std::wstring sC = L"US"; + std::wstring sO = L"Ascensio System SIA"; + std::wstring sCN = L"AOSign Certificate"; + + std::map::const_iterator iter_prop = props.find(L"C"); + if (iter_prop != props.end()) + sC = iter_prop->second; + + iter_prop = props.find(L"O"); + if (iter_prop != props.end()) + sO = iter_prop->second; + + iter_prop = props.find(L"CN"); + if (iter_prop != props.end()) + sCN = iter_prop->second; + + std::string sC_A = U_TO_UTF8(sC); + std::string sO_A = U_TO_UTF8(sO); + std::string sCN_A = U_TO_UTF8(sCN); + + X509_NAME_add_entry_by_txt(name_record, "C", MBSTRING_ASC, (unsigned char *)sC_A.c_str(), -1, -1, 0); + X509_NAME_add_entry_by_txt(name_record, "O", MBSTRING_ASC, (unsigned char *)sO_A.c_str(), -1, -1, 0); + X509_NAME_add_entry_by_txt(name_record, "CN", MBSTRING_ASC, (unsigned char *)sCN_A.c_str(), -1, -1, 0); + + X509_set_issuer_name(m_cert, name_record); + + if (!props.empty()) + { + std::string sAdditions = ""; + for (std::map::const_iterator iter = props.begin(); iter != props.end(); iter++) + { + std::string sKey = U_TO_UTF8(iter->first); + std::string sValue = U_TO_UTF8(iter->second); + + string_replace(sKey, ";", ";"); + string_replace(sKey, "=", "="); + string_replace(sValue, ";", ";"); + + sAdditions += (sKey + "=" + sValue + ";"); + } + + if (!sAdditions.empty()) + { + //const int nid_user = OBJ_create("1.2.3", "key", "value"); + ASN1_OCTET_STRING* oDataAdditions = ASN1_OCTET_STRING_new(); + int nError = ASN1_OCTET_STRING_set(oDataAdditions, (unsigned const char*)sAdditions.c_str(), (int)sAdditions.length()); + X509_EXTENSION* ext = X509_EXTENSION_create_by_NID(nullptr, NID_subject_alt_name, false, oDataAdditions); + nError = X509_add_ext(m_cert, ext, -1); + X509_EXTENSION_free(ext); + } + } + + const EVP_MD* pDigest = Get_EVP_MD(this->GetHashAlg()); + if (NULL == pDigest) + pDigest = EVP_md_null(); + + if (X509_sign(m_cert, m_key, pDigest) == 0) + { + if (NULL != m_cert) + X509_free(m_cert); + m_cert = NULL; + + if (NULL != m_key) + EVP_PKEY_free(m_key); + m_key = NULL; + + EVP_PKEY_CTX_free(pctx); + return false; + } + + EVP_PKEY_CTX_free(pctx); + return true; + } + virtual int GetType() { return CERTIFICATE_ENGINE_TYPE_OPENSSL; diff --git a/DesktopEditor/xmlsec/src/test/main.cpp b/DesktopEditor/xmlsec/src/test/main.cpp index 1c109413b4..9ae245cf86 100644 --- a/DesktopEditor/xmlsec/src/test/main.cpp +++ b/DesktopEditor/xmlsec/src/test/main.cpp @@ -1,5 +1,5 @@ #include "../../../common/File.h" -#include "../include/XmlCertificate.h" +#include "../include/CertificateCommon.h" #include "../include/OOXMLSigner.h" #include "../include/OOXMLVerifier.h" @@ -12,56 +12,64 @@ int main() { - std::wstring sTestDir = NSFile::GetProcessDirectory() + L"/../../"; - ICertificate* pCertificate = NULL; + std::wstring sTestDir = NSFile::GetProcessDirectory() + L"/../../"; -#ifdef USE_MS_CRYPTO + //ICertificate* pCertificate = NSCertificate::FromFiles(sTestDir + L"keys/key.key", "", sTestDir + L"keys/cert.crt", ""); - // TODO: Load sertificate from store + std::map properties; + properties.insert(std::make_pair(L"email", L"sign@onlyoffice.com")); + properties.insert(std::make_pair(L"phone", L"+00000000000")); + std::wstring sNameTest = L"NameTest"; + std::wstring sValueTest = L"ValueTest"; + properties.insert(std::make_pair(sNameTest, sValueTest)); -#else + //ICertificate* pCertificate = NSCertificate::GenerateByAlg("rsa2048", properties); + ICertificate* pCertificate = NSCertificate::GenerateByAlg("ed25519", properties); - pCertificate = ICertificate::CreateInstance(); - pCertificate->FromFiles(sTestDir + L"keys/key.key", "", sTestDir + L"keys/cert.crt", ""); -#endif + unsigned char* pSignData = NULL; + unsigned int nSignDataLen = 0; + std::string sSignData = "Hello world!"; + bool bRes = pCertificate->SignPKCS7((unsigned char*)sSignData.c_str(), (unsigned int)sSignData.length(), pSignData, nSignDataLen); - BYTE* pDataDst = NULL; - unsigned long nLenDst = 0; + RELEASEARRAYOBJECTS(pSignData); + + BYTE* pDataDst = NULL; + unsigned long nLenDst = 0; #ifdef USE_SIGN #if 0 - COOXMLSigner oSigner(sTestDir + L"file", pCertificate); - oSigner.Sign(pDataDst, nLenDst); + COOXMLSigner oSigner(sTestDir + L"file", pCertificate); + oSigner.Sign(pDataDst, nLenDst); #else - BYTE* pDataSrc = NULL; - unsigned long nLenSrc = 0; - NSFile::CFileBinary::ReadAllBytes(sTestDir + L"/file.docx", &pDataSrc, nLenSrc); + BYTE* pDataSrc = NULL; + unsigned long nLenSrc = 0; + NSFile::CFileBinary::ReadAllBytes(sTestDir + L"/file.docx", &pDataSrc, nLenSrc); - COOXMLSigner oSigner(pDataSrc, nLenSrc, pCertificate); - oSigner.Sign(pDataDst, nLenDst); - RELEASEARRAYOBJECTS(pDataSrc); + COOXMLSigner oSigner(pDataSrc, nLenSrc, pCertificate); + oSigner.Sign(pDataDst, nLenDst); + RELEASEARRAYOBJECTS(pDataSrc); - NSFile::CFileBinary oFileDst; - oFileDst.CreateFileW(sTestDir + L"/file2.docx"); - oFileDst.WriteFile(pDataDst, nLenDst); - oFileDst.CloseFile(); + NSFile::CFileBinary oFileDst; + oFileDst.CreateFileW(sTestDir + L"/file2.docx"); + oFileDst.WriteFile(pDataDst, nLenDst); + oFileDst.CloseFile(); #endif #endif - RELEASEARRAYOBJECTS(pDataDst); + RELEASEARRAYOBJECTS(pDataDst); #ifdef USE_VERIFY #if 1 - COOXMLVerifier oVerifier(sTestDir + L"file"); - int nCount = oVerifier.GetSignatureCount(); - for (int i = 0; i < nCount; i++) - { - COOXMLSignature* pSign = oVerifier.GetSignature(i); - pSign->Check(); - } + COOXMLVerifier oVerifier(sTestDir + L"file"); + int nCount = oVerifier.GetSignatureCount(); + for (int i = 0; i < nCount; i++) + { + COOXMLSignature* pSign = oVerifier.GetSignature(i); + pSign->Check(); + } #endif #endif - delete pCertificate; - return 0; + delete pCertificate; + return 0; }