From 227d4f18d6c823ddc488ea288a93d748d7243f58 Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Thu, 8 Jun 2017 17:24:17 +0300 Subject: [PATCH] . --- .gitignore | 1 + Common/3dParty/openssl/build.sh | 12 + Common/3dParty/openssl/fetch.sh | 8 + .../xmlsec/src/include/XmlCertificate.h | 23 + DesktopEditor/xmlsec/src/ooxmlsignature.pro | 10 + .../xmlsec/src/src/XmlSigner_openssl.h | 469 +++++++++++++++++- .../OpenSSL_gui_test/OpenSSL_gui_test.pro | 6 +- .../xmlsec/test/openssl_linux/main.cpp | 4 +- 8 files changed, 513 insertions(+), 20 deletions(-) create mode 100644 Common/3dParty/openssl/build.sh create mode 100644 Common/3dParty/openssl/fetch.sh diff --git a/.gitignore b/.gitignore index a0543c9d69..d28b442eda 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ Common/3dParty/v8/win_32 Common/3dParty/v8/linux_64 Common/3dParty/v8/linux_32 Common/3dParty/v8/mac_64 +Common/3dParty/openssl/openssl **/core_build **/Release **/Debug diff --git a/Common/3dParty/openssl/build.sh b/Common/3dParty/openssl/build.sh new file mode 100644 index 0000000000..683cf9d21d --- /dev/null +++ b/Common/3dParty/openssl/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +export PATH=`pwd`/depot_tools:"$PATH" + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") + +cd "$SCRIPTPATH"/openssl + +perl ./Configure linux-64 +./config +make diff --git a/Common/3dParty/openssl/fetch.sh b/Common/3dParty/openssl/fetch.sh new file mode 100644 index 0000000000..da6e2c3b7f --- /dev/null +++ b/Common/3dParty/openssl/fetch.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +SCRIPT=$(readlink -f "$0") +SCRIPTPATH=$(dirname "$SCRIPT") + +cd "$SCRIPTPATH" + +git clone https://github.com/openssl/openssl.git diff --git a/DesktopEditor/xmlsec/src/include/XmlCertificate.h b/DesktopEditor/xmlsec/src/include/XmlCertificate.h index 9f94712bc7..52ea64d5e0 100644 --- a/DesktopEditor/xmlsec/src/include/XmlCertificate.h +++ b/DesktopEditor/xmlsec/src/include/XmlCertificate.h @@ -8,6 +8,27 @@ #define OOXML_HASH_ALG_SHA1 0 #define OOXML_HASH_ALG_INVALID 1 +class Q_DECL_EXPORT ICertificateSelectDialogOpenSsl +{ +public: + ICertificateSelectDialogOpenSsl() + { + } + virtual ~ICertificateSelectDialogOpenSsl() + { + } + +public: + virtual std::wstring GetCertificatePath() = 0; + virtual std::wstring GetCertificatePassword() = 0; + + virtual std::wstring GetKeyPath() = 0; + virtual std::wstring GetKeyPassword() = 0; + + virtual bool ShowSelectDialog() = 0; + virtual int ShowCertificate() = 0; +}; + class Q_DECL_EXPORT CCertificateInfo { public: @@ -58,6 +79,8 @@ public: virtual bool ShowSelectDialog() = 0; virtual int ShowCertificate() = 0; + virtual void SetOpenSslDialog(ICertificateSelectDialogOpenSsl* pDialog) {} + static CCertificateInfo GetDefault(); static ICertificate* GetById(const std::string& id); diff --git a/DesktopEditor/xmlsec/src/ooxmlsignature.pro b/DesktopEditor/xmlsec/src/ooxmlsignature.pro index d8c9106504..aa573de915 100644 --- a/DesktopEditor/xmlsec/src/ooxmlsignature.pro +++ b/DesktopEditor/xmlsec/src/ooxmlsignature.pro @@ -46,3 +46,13 @@ core_windows { LIBS += -lAdvapi32 } + +core_linux { + +DEFINES += XMLSEC_OPENSSL_110 +INCLUDEPATH += $$CORE_ROOT_DIR/Common/3dParty/openssl/openssl/include + +LIBS += -L$$CORE_ROOT_DIR/Common/3dParty/openssl/openssl -lssl +LIBS += -L$$CORE_ROOT_DIR/Common/3dParty/openssl/openssl -lcrypto + +} diff --git a/DesktopEditor/xmlsec/src/src/XmlSigner_openssl.h b/DesktopEditor/xmlsec/src/src/XmlSigner_openssl.h index f0a71aa763..d3dadfd7d4 100644 --- a/DesktopEditor/xmlsec/src/src/XmlSigner_openssl.h +++ b/DesktopEditor/xmlsec/src/src/XmlSigner_openssl.h @@ -4,65 +4,204 @@ #include "./include/XmlCertificate.h" #include "../../../common/File.h" +#include "../../../common/String.h" #include "../../../common/BigInteger.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define OPEN_SSL_WARNING_OK 0 +#define OPEN_SSL_WARNING_ERR 1 +#define OPEN_SSL_WARNING_ALL_OK 2 +#define OPEN_SSL_WARNING_PASS 4 + class CCertificate_openssl : public ICertificate { -public: - protected: + ICertificateSelectDialogOpenSsl* m_pDialog; + BYTE* m_rawData; int m_rawDataLen; + X509* m_cert; + EVP_PKEY* m_key; + public: CCertificate_openssl() : ICertificate() { + m_pDialog = NULL; + m_rawData = NULL; m_rawDataLen = 0; + + m_cert = NULL; + m_key = NULL; } virtual ~CCertificate_openssl() - { + { + if (NULL != m_cert) + X509_free(m_cert); + if (NULL != m_key) + EVP_PKEY_free(m_key); } public: virtual std::string GetNumber() { - return ""; + if (NULL == m_cert) + return ""; + + ASN1_INTEGER* asn1_serial = X509_get_serialNumber(m_cert); + if (asn1_serial == NULL) + return ""; + + BIGNUM* bn = ASN1_INTEGER_to_BN(asn1_serial, NULL); + if (!bn) + { + ASN1_INTEGER_free(asn1_serial); + return ""; + } + + char *tmp = BN_bn2dec(bn); + std::string sReturn(tmp); + + BN_free(bn); + ASN1_INTEGER_free(asn1_serial); + + return sReturn; } virtual std::wstring GetSignerName() { - return L""; + if (NULL == m_cert) + return L""; + + X509_NAME* name = X509_get_issuer_name(m_cert); + char* utf_8_name = X509_NAME_oneline(name, NULL, 0); + + std::string sName(utf_8_name); + std::wstring sNameW = UTF8_TO_U(sName); + + OPENSSL_free(utf_8_name); + + return sNameW; } virtual std::string GetCertificateBase64() { - return ""; + if (NULL == m_cert) + return ""; + + BIO* bio = BIO_new(BIO_s_mem()); + PEM_write_bio_X509_AUX(bio, m_cert); + + unsigned char *data; + unsigned int len = 0; + len = BIO_get_mem_data(bio, &data); + + std::string sReturn((char*)data, (size_t)len); + + BIO_free(bio); + return sReturn; } virtual std::string GetCertificateHash() { + std::string sBase64 = GetCertificateBase64(); + BYTE* pData = NULL; + int nLen = 0; + if (NSFile::CBase64Converter::Decode(sBase64.c_str(), (int)sBase64.length(), pData, nLen)) + { + std::string sHash = GetHash(pData, (unsigned int)nLen, OOXML_HASH_ALG_SHA1); + RELEASEARRAYOBJECTS(pData); + return sHash; + } + return ""; } virtual std::string GetDate() { - return ""; + if (NULL == m_cert) + return ""; + + ASN1_TIME* _time1 = X509_get_notBefore(m_cert); + struct tm t1 = this->ASN1_GetTimeT(_time1); + ASN1_TIME_free(_time1); + + ASN1_TIME* _time2 = X509_get_notAfter(m_cert); + struct tm t2 = this->ASN1_GetTimeT(_time2); + ASN1_TIME_free(_time2); + + std::string sRet = std::to_string(t1.tm_mday) + + "/" + + std::to_string(t1.tm_mon + 1) + + "/" + + std::to_string(t1.tm_year + 1900) + + " - " + + std::to_string(t1.tm_mday) + + "/" + + std::to_string(t2.tm_mon + 1) + + "/" + + std::to_string(t2.tm_year + 1900); + return sRet; } virtual std::string GetId() { - return ""; + // TODO: + public key? + return GetNumber(); } public: virtual std::string Sign(const std::string& sXml) { - return ""; + EVP_MD_CTX* pCtx = EVP_MD_CTX_create(); + const EVP_MD* pDigest = EVP_sha1(); + + int n1 = EVP_SignInit(pCtx, pDigest); + n1 = n1; + + int n2 = EVP_SignUpdate(pCtx, sXml.c_str(), sXml.length()); + n2 = n2; + + BYTE pSignature[4096]; + unsigned int nSignatureLen = 0; + + int n3 = EVP_SignFinal(pCtx, pSignature, &nSignatureLen, m_key); + n3 = n3; + + EVP_MD_CTX_destroy(pCtx); + + return std::string((char*)pSignature, (size_t)nSignatureLen); } virtual std::string GetHash(unsigned char* pData, unsigned int nSize, int nAlg) { + if (nAlg == OOXML_HASH_ALG_SHA1) + { + unsigned char obuf[20]; + SHA1(pData, (size_t)nSize, obuf); + + char* pBase64_hash = NULL; + int nBase64Len_hash = 0; + NSFile::CBase64Converter::Encode(obuf, 20, pBase64_hash, nBase64Len_hash, NSBase64::B64_BASE64_FLAG_NOCRLF); + + std::string sReturn(pBase64_hash, nBase64Len_hash); + delete [] pBase64_hash; + + return sReturn; + } return ""; } @@ -88,24 +227,324 @@ public: virtual bool Verify(const std::string& sXml, std::string& sXmlSignature, int nAlg) { - return false; + EVP_MD_CTX* pCtx = EVP_MD_CTX_create(); + const EVP_MD* pDigest = EVP_sha1(); + + int n1 = EVP_VerifyInit(pCtx, pDigest); + n1 = n1; + + BYTE* pDigestValue = NULL; + int nDigestLen = 0; + NSFile::CBase64Converter::Decode(sXmlSignature.c_str(), (int)sXmlSignature.length(), pDigestValue, nDigestLen); + + int n2 = EVP_VerifyUpdate(pCtx, pDigestValue, (size_t)nDigestLen); + n2 = n2; + + EVP_PKEY* pubkey = X509_get_pubkey(m_cert); + + int n3 = EVP_VerifyFinal(pCtx, (BYTE*)sXml.c_str(), (unsigned int)sXml.length(), pubkey); + n3 = n3; + + EVP_MD_CTX_destroy(pCtx); + EVP_PKEY_free(pubkey); + + RELEASEARRAYOBJECTS(pDigestValue); + + return (1 == n3) ? true : false; } virtual bool LoadFromBase64Data(const std::string& data) { - return false; - } + BYTE* pData = NULL; + int nLen = 0; + if (NSFile::CBase64Converter::Decode(data.c_str(), (int)data.length(), pData, nLen)) + { + X509* pCert = NULL; + int nErr = LoadCert(pData, (DWORD)nLen, "", &pCert); - virtual int ShowCertificate() - { - return 1; + if (nErr == OPEN_SSL_WARNING_OK || nErr == OPEN_SSL_WARNING_ALL_OK) + { + m_cert = pCert; + } + else + { + X509_free(pCert); + m_cert = NULL; + } + + RELEASEARRAYOBJECTS(pData); + return (NULL == m_cert) ? false : true; + } + return false; } public: virtual bool ShowSelectDialog() { + if (m_pDialog) + return m_pDialog->ShowSelectDialog(); return false; } + virtual int ShowCertificate() + { + if (m_pDialog) + return m_pDialog->ShowCertificate(); + return 1; + } + + virtual void SetOpenSslDialog(ICertificateSelectDialogOpenSsl* pDialog) + { + m_pDialog = pDialog; + } + +protected: + tm ASN1_GetTimeT(ASN1_TIME* time) + { + struct tm t; + const char* str = (const char*) time->data; + size_t i = 0; + + memset(&t, 0, sizeof(t)); + + if (time->type == V_ASN1_UTCTIME) + { + /* two digit year */ + t.tm_year = (str[i++] - '0') * 10; + t.tm_year += (str[i++] - '0'); + if (t.tm_year < 70) + t.tm_year += 100; + } + else if (time->type == V_ASN1_GENERALIZEDTIME) + { + /* four digit year */ + t.tm_year = (str[i++] - '0') * 1000; + t.tm_year+= (str[i++] - '0') * 100; + t.tm_year+= (str[i++] - '0') * 10; + t.tm_year+= (str[i++] - '0'); + t.tm_year -= 1900; + } + t.tm_mon = (str[i++] - '0') * 10; + t.tm_mon += (str[i++] - '0') - 1; // -1 since January is 0 not 1. + t.tm_mday = (str[i++] - '0') * 10; + t.tm_mday+= (str[i++] - '0'); + t.tm_hour = (str[i++] - '0') * 10; + t.tm_hour+= (str[i++] - '0'); + t.tm_min = (str[i++] - '0') * 10; + t.tm_min += (str[i++] - '0'); + t.tm_sec = (str[i++] - '0') * 10; + t.tm_sec += (str[i++] - '0'); + + /* Note: we did not adjust the time based on time zone information */ + return t; + } + +public: + static std::string GetOpenSslErrors() + { + BIO* bio = BIO_new(BIO_s_mem()); + ERR_print_errors(bio); + char *buf = NULL; + size_t len = BIO_get_mem_data(bio, &buf); + std::string sRet((char*)buf, len); + NSStringExt::ToLower(sRet); + BIO_free (bio); + return sRet; + } + static bool IsOpenSslPasswordError(const std::string& str) + { + if (std::string::npos != str.find("mac verify error")) + return true; + if (std::string::npos != str.find("mac verify failure")) + return true; + if (std::string::npos != str.find("password")) + return true; + return false; + } + + static int LoadKey(BYTE* pData, DWORD dwDataLen, std::string password, EVP_PKEY** ppKey) + { + int nErr = OPEN_SSL_WARNING_ERR; + std::string sError = ""; + + PKCS12* p12 = NULL; + EVP_PKEY* pKey = NULL; + char* pPassword = (password.empty()) ? NULL : (char*)password.c_str(); + + BIO* bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + if (PEM_read_bio_PrivateKey(bio, &pKey, NULL, (void*)pPassword)) + { + nErr = OPEN_SSL_WARNING_OK; + goto end; + } + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + + BIO_free(bio); + bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + if (d2i_PrivateKey_bio(bio, &pKey)) + { + nErr = OPEN_SSL_WARNING_OK; + goto end; + } + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + + BIO_free(bio); + bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + if (d2i_PKCS8PrivateKey_bio(bio, &pKey, NULL, (void*)pPassword)) + { + nErr = OPEN_SSL_WARNING_OK; + goto end; + } + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + + BIO_free(bio); + bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + + p12 = d2i_PKCS12_bio(bio, NULL); + if (p12) + { + X509* pCert = NULL; + STACK_OF(X509)* pCa = NULL; + + if (PKCS12_parse(p12, pPassword, &pKey, &pCert, &pCa)) + { + sk_X509_pop_free(pCa, X509_free); + X509_free(pCert); + PKCS12_free(p12); + nErr = OPEN_SSL_WARNING_ALL_OK; + goto end; + } + PKCS12_free(p12); + + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + } + +end: + if (NULL == ppKey) + EVP_PKEY_free(pKey); + else + *ppKey = pKey; + + BIO_free(bio); + return nErr; + } + + static int LoadKey(std::wstring file, std::string password, EVP_PKEY** ppKey) + { + BYTE* pData = NULL; + DWORD dwDataLen; + if (!NSFile::CFileBinary::ReadAllBytes(file, &pData, dwDataLen)) + return OPEN_SSL_WARNING_ERR; + + int nErr = LoadKey(pData, dwDataLen, password, ppKey); + RELEASEARRAYOBJECTS(pData); + return nErr; + } + + static int LoadCert(BYTE* pData, DWORD dwDataLen, std::string password, X509** ppCert) + { + int nErr = OPEN_SSL_WARNING_ERR; + std::string sError = ""; + + PKCS12* p12 = NULL; + X509* pCert = NULL; + char* pPassword = (password.empty()) ? NULL : (char*)password.c_str(); + + BIO* bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + if (PEM_read_bio_X509(bio, &pCert, NULL, (void*)pPassword)) + { + nErr = OPEN_SSL_WARNING_OK; + goto end; + } + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + + BIO_free(bio); + bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + if (d2i_X509_bio(bio, &pCert)) + { + nErr = OPEN_SSL_WARNING_OK; + goto end; + } + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + + BIO_free(bio); + bio = BIO_new_mem_buf((void*)pData, (int)dwDataLen); + + p12 = d2i_PKCS12_bio(bio, NULL); + if (p12) + { + EVP_PKEY* pKey = NULL; + STACK_OF(X509)* pCa = NULL; + + if (PKCS12_parse(p12, pPassword, &pKey, &pCert, &pCa)) + { + sk_X509_pop_free(pCa, X509_free); + EVP_PKEY_free(pKey); + PKCS12_free(p12); + BIO_free(bio); + nErr = OPEN_SSL_WARNING_ALL_OK; + goto end; + } + + PKCS12_free(p12); + sError = GetOpenSslErrors(); + if (IsOpenSslPasswordError(sError)) + { + nErr = OPEN_SSL_WARNING_PASS; + goto end; + } + } + +end: + if (NULL == ppCert) + X509_free(pCert); + else + *ppCert = pCert; + + BIO_free(bio); + return nErr; + } + + static int LoadCert(std::wstring file, std::string password, X509** ppCert) + { + BYTE* pData = NULL; + DWORD dwDataLen; + if (!NSFile::CFileBinary::ReadAllBytes(file, &pData, dwDataLen)) + return OPEN_SSL_WARNING_ERR; + + int nErr = LoadCert(pData, dwDataLen, password, ppCert); + RELEASEARRAYOBJECTS(pData); + return nErr; + } }; #endif // _XMLSIGNER_OPENSSL_H_ diff --git a/DesktopEditor/xmlsec/test/OpenSSL_gui_test/OpenSSL_gui_test.pro b/DesktopEditor/xmlsec/test/OpenSSL_gui_test/OpenSSL_gui_test.pro index 4d23f153e1..caad5a1907 100644 --- a/DesktopEditor/xmlsec/test/OpenSSL_gui_test/OpenSSL_gui_test.pro +++ b/DesktopEditor/xmlsec/test/OpenSSL_gui_test/OpenSSL_gui_test.pro @@ -27,10 +27,10 @@ core_linux { DEFINES += XMLSEC_OPENSSL_110 #DEFINES += "OPENSSL_API_COMPAT=\"0x10100000\"" -INCLUDEPATH += $$PWD/../../openssl/include +INCLUDEPATH += $$CORE_ROOT_DIR/Common/3dParty/openssl/openssl/include -LIBS += -L$$PWD/../../openssl -lssl -LIBS += -L$$PWD/../../openssl -lcrypto +LIBS += -L$$CORE_ROOT_DIR/Common/3dParty/openssl/openssl -lssl +LIBS += -L$$CORE_ROOT_DIR/Common/3dParty/openssl/openssl -lcrypto LIBS += -ldl diff --git a/DesktopEditor/xmlsec/test/openssl_linux/main.cpp b/DesktopEditor/xmlsec/test/openssl_linux/main.cpp index df35becfd2..705661bd30 100644 --- a/DesktopEditor/xmlsec/test/openssl_linux/main.cpp +++ b/DesktopEditor/xmlsec/test/openssl_linux/main.cpp @@ -44,7 +44,7 @@ static time_t ASN1_GetTimeT(ASN1_TIME* time) return mktime(&t); } -#if 0 +#if 1 int main() { std::wstring sFolderW = NSFile::GetProcessDirectory(); @@ -141,7 +141,7 @@ int main() } #endif -#if 1 +#if 0 int main(int argc, char **argv) { std::wstring sFolderW = NSFile::GetProcessDirectory();