diff options
Diffstat (limited to 'xmlsecurity/source/xmlsec/mscrypt')
13 files changed, 3519 insertions, 0 deletions
diff --git a/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx b/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx new file mode 100644 index 000000000..ec3cecd4a --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/akmngr.cxx @@ -0,0 +1,229 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <xmlsec-wrapper.h> + +#include "akmngr.hxx" + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscng/crypto.h> +#include <xmlsec/mscng/keysstore.h> +#include <xmlsec/mscng/x509.h> +#include <svl/cryptosign.hxx> + +namespace xmlsecurity +{ + +/** + * MSCryptoAppliedKeysMngrCreate: + * + * Create and load key store and certificate database into keys manager + * + * Returns keys manager pointer on success or NULL otherwise. + */ +xmlSecKeysMngrPtr MSCryptoAppliedKeysMngrCreate() +{ + xmlSecKeysMngrPtr keyMngr = nullptr ; + xmlSecKeyStorePtr keyStore = nullptr ; + + keyStore = xmlSecKeyStoreCreate(xmlSecMSCngKeysStoreId); + if (keyStore == nullptr) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + return nullptr ; + } + + keyMngr = xmlSecKeysMngrCreate() ; + if (keyMngr == nullptr) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecKeysMngrCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + + xmlSecKeyStoreDestroy(keyStore) ; + return nullptr ; + } + + /*- + * Add key store to manager, from now on keys manager destroys the store if + * needed + */ + if (xmlSecKeysMngrAdoptKeysStore(keyMngr, keyStore) < 0) + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(keyStore)), + "xmlSecKeysMngrAdoptKeyStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + + xmlSecKeyStoreDestroy(keyStore) ; + xmlSecKeysMngrDestroy(keyMngr) ; + return nullptr ; + } + + /*- + * Initialize crypto library specific data in keys manager + */ + if (xmlSecMSCngKeysMngrInit(keyMngr) < 0) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecMSCngKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + xmlSecKeysMngrDestroy(keyMngr); + return nullptr; + } + + /*- + * Set certificate database to X509 key data store + */ + /*- + * At present, MS Crypto engine do not provide a way to setup a cert store. + */ + + /*- + * Set the getKey callback + */ + keyMngr->getKey = xmlSecKeysMngrGetKey ; + + return keyMngr ; +} + +int +MSCryptoAppliedKeysMngrAdoptKeyStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE keyStore +) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2(mngr != nullptr, -1) ; + xmlSecAssert2(keyStore != nullptr, -1) ; + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); + if (x509Store == nullptr) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + return -1 ; + } + + if (xmlSecMSCngX509StoreAdoptKeyStore(x509Store, keyStore) < 0) + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)), + "xmlSecMSCngX509StoreAdoptKeyStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return -1; + } + + return 0 ; +} + +int +MSCryptoAppliedKeysMngrAdoptTrustedStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE trustedStore +) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2(mngr != nullptr, -1) ; + xmlSecAssert2(trustedStore != nullptr, -1) ; + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); + if (x509Store == nullptr) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + return -1 ; + } + + if (xmlSecMSCngX509StoreAdoptTrustedStore(x509Store, trustedStore) < 0) + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)), + "xmlSecMSCngX509StoreAdoptKeyStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return -1; + } + + return 0 ; +} + +int +MSCryptoAppliedKeysMngrAdoptUntrustedStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE untrustedStore +) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2(mngr != nullptr, -1) ; + xmlSecAssert2(untrustedStore != nullptr, -1) ; + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCngX509StoreId); + if (x509Store == nullptr) + { + xmlSecError(XMLSEC_ERRORS_HERE, + nullptr, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE) ; + return -1 ; + } + + if (xmlSecMSCngX509StoreAdoptUntrustedStore(x509Store, untrustedStore) < 0) + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(x509Store)), + "xmlSecMSCngX509StoreAdoptKeyStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return -1; + } + + return 0 ; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx b/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx new file mode 100644 index 000000000..e5942ba2a --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/akmngr.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> + +namespace xmlsecurity +{ + +xmlSecKeysMngrPtr MSCryptoAppliedKeysMngrCreate(); + +int +MSCryptoAppliedKeysMngrAdoptKeyStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE keyStore +) ; + +int +MSCryptoAppliedKeysMngrAdoptTrustedStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE trustedStore +) ; + +int +MSCryptoAppliedKeysMngrAdoptUntrustedStore( + xmlSecKeysMngrPtr mngr, + HCERTSTORE untrustedStore +) ; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/oid.hxx b/xmlsecurity/source/xmlsec/mscrypt/oid.hxx new file mode 100644 index 000000000..ce573d882 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/oid.hxx @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/macros.h> + +typedef struct { + char const *oid; + char const *desc; +} OIDItem; + +OIDItem OIDs[] = { + {"1.2.840.113549", "RSA Data Security Inc."}, + {"1.2.840.113549.1", "PKCS"}, + {"1.2.840.113549.2", "RSA digest algorithm"}, + {"1.2.840.113549.3", "RSA cipher algorithm"}, + {"1.2.840.113549.1.1", "PKCS #1"}, + {"1.2.840.113549.1.2", "Unknown"}, + {"1.2.840.113549.1.3", "Unknown"}, + {"1.2.840.113549.1.4", "Unknown"}, + {"1.2.840.113549.1.5", "PKCS #5"}, + {"1.2.840.113549.1.6", "Unknown"}, + {"1.2.840.113549.1.7", "PKCS #7"}, + {"1.2.840.113549.1.8", "Unknown"}, + {"1.2.840.113549.1.9", "PKCS #9"}, + {"1.2.840.113549.1.10", "Unknown"}, + {"1.2.840.113549.1.12", "PKCS #12"}, + {"1.2.840.113549.1.1.2", "PKCS #1 MD2 With RSA Encryption"}, + {"1.2.840.113549.1.1.3", "PKCS #1 MD4 With RSA Encryption"}, + {"1.2.840.113549.1.1.4", "PKCS #1 MD5 With RSA Encryption"}, + {"1.2.840.113549.1.1.1", "PKCS #1 RSA Encryption"}, + {"1.2.840.113549.1.1.2", "PKCS #1 MD2 With RSA Encryption"}, + {"1.2.840.113549.1.1.3", "PKCS #1 MD4 With RSA Encryption"}, + {"1.2.840.113549.1.1.4", "PKCS #1 MD5 With RSA Encryption"}, + {"1.2.840.113549.1.1.5", "PKCS #1 SHA-1 With RSA Encryption"}, + {"1.2.840.113549.1.1.5", "PKCS #1 SHA-1 With RSA Encryption"}, + {"1.2.840.113549.1.3.1", "Unknown"}, + {"1.2.840.113549.1.7.1", "PKCS #7 Data"}, + {"1.2.840.113549.1.7.2", "PKCS #7 Signed Data"}, + {"1.2.840.113549.1.7.3", "PKCS #7 Enveloped Data"}, + {"1.2.840.113549.1.7.4", "PKCS #7 Signed and Enveloped Data"}, + {"1.2.840.113549.1.7.5", "PKCS #7 Digested Data"}, + {"1.2.840.113549.1.7.6", "PKCS #7 Encrypted Data"}, + {"1.2.840.113549.1.9.1", "PKCS #9 Email Address"}, + {"1.2.840.113549.1.9.2", "PKCS #9 Unstructured Name"}, + {"1.2.840.113549.1.9.3", "PKCS #9 Content Type"}, + {"1.2.840.113549.1.9.4", "PKCS #9 Message Digest"}, + {"1.2.840.113549.1.9.5", "PKCS #9 Signing Time"}, + {"1.2.840.113549.1.9.6", "PKCS #9 Counter Signature"}, + {"1.2.840.113549.1.9.7", "PKCS #9 Challenge Password"}, + {"1.2.840.113549.1.9.8", "PKCS #9 Unstructured Address"}, + {"1.2.840.113549.1.9.9", "PKCS #9 Extended Certificate Attributes"}, + {"1.2.840.113549.1.9.15", "PKCS #9 S/MIME Capabilities"}, + {"1.2.840.113549.1.9.15.1", "Unknown"}, + {"1.2.840.113549.3.2", "RC2-CBC"}, + {"1.2.840.113549.3.4", "RC4"}, + {"1.2.840.113549.3.7", "DES-EDE3-CBC"}, + {"1.2.840.113549.3.9", "RC5-CBCPad"}, + {"1.2.840.10046", "ANSI X9.42"}, + {"1.2.840.10046.2.1", "Diffie-Hellman Public Key Algorithm"}, + {"1.2.840.10040", "ANSI X9.57"}, + {"1.2.840.10040.4.1", "ANSI X9.57 DSA Signature"}, + {"1.2.840.10040.4.3", "ANSI X9.57 Algorithm DSA Signature with SHA-1 Digest"}, + {"2.5", "Directory"}, + {"2.5.8", "X.500-defined algorithms"}, + {"2.5.8.1", "X.500-defined encryption algorithms"}, + {"2.5.8.2", "Unknown"}, + {"2.5.8.3", "Unknown"}, + {"2.5.8.1.1", "RSA Encryption Algorithm"}, + {"1.3.14", "Open Systems Implementors Workshop"}, + {"1.3.14.3.2", "OIW SECSIG Algorithm"}, + {"1.3.14.3.2.2", "Unknown"}, + {"1.3.14.3.2.3", "Unknown"}, + {"1.3.14.3.2.4", "Unknown"}, + {"1.3.14.3.2.6", "DES-ECB"}, + {"1.3.14.3.2.7", "DES-CBC"}, + {"1.3.14.3.2.8", "DES-OFB"}, + {"1.3.14.3.2.9", "DES-CFB"}, + {"1.3.14.3.2.10", "DES-MAC"}, + {"1.3.14.3.2.11", "Unknown"}, + {"1.3.14.3.2.12", "Unknown"}, + {"1.3.14.3.2.13", "Unknown"}, + {"1.3.14.3.2.14", "Unknown"}, + {"1.3.14.3.2.15", "ISO SHA with RSA Signature"}, + {"1.3.14.3.2.16", "Unknown"}, + {"1.3.14.3.2.17", "DES-EDE"}, + {"1.3.14.3.2.18", "Unknown"}, + {"1.3.14.3.2.19", "Unknown"}, + {"1.3.14.3.2.20", "Unknown"}, + {"1.3.14.3.2.21", "Unknown"}, + {"1.3.14.3.2.22", "Unknown"}, + {"1.3.14.3.2.23", "Unknown"}, + {"1.3.14.3.2.24", "Unknown"}, + {"1.3.14.3.2.25", "Unknown"}, + {"1.3.14.3.2.26", "SHA-1"}, + {"1.3.14.3.2.27", "Forgezza DSA Signature with SHA-1 Digest"}, + {"1.3.14.3.2.28", "Unknown"}, + {"1.3.14.3.2.29", "Unknown"}, + {"1.3.14.7.2", "Unknown"}, + {"1.3.14.7.2.1", "Unknown"}, + {"1.3.14.7.2.2", "Unknown"}, + {"1.3.14.7.2.3", "Unknown"}, + {"1.3.14.7.2.2.1", "Unknown"}, + {"1.3.14.7.2.3.1", "Unknown"}, + {"2.16.840.1.101.2.1", "US DOD Infosec"}, + {"2.16.840.1.101.2.1.1.1", "Unknown"}, + {"2.16.840.1.101.2.1.1.2", "MISSI DSS Algorithm (Old)"}, + {"2.16.840.1.101.2.1.1.3", "Unknown"}, + {"2.16.840.1.101.2.1.1.4", "Skipjack CBC64"}, + {"2.16.840.1.101.2.1.1.5", "Unknown"}, + {"2.16.840.1.101.2.1.1.6", "Unknown"}, + {"2.16.840.1.101.2.1.1.7", "Unknown"}, + {"2.16.840.1.101.2.1.1.8", "Unknown"}, + {"2.16.840.1.101.2.1.1.9", "Unknown"}, + {"2.16.840.1.101.2.1.1.10", "MISSI KEA Algorithm"}, + {"2.16.840.1.101.2.1.1.11", "Unknown"}, + {"2.16.840.1.101.2.1.1.12", "MISSI KEA and DSS Algorithm (Old)"}, + {"2.16.840.1.101.2.1.1.13", "Unknown"}, + {"2.16.840.1.101.2.1.1.14", "Unknown"}, + {"2.16.840.1.101.2.1.1.15", "Unknown"}, + {"2.16.840.1.101.2.1.1.16", "Unknown"}, + {"2.16.840.1.101.2.1.1.17", "Unknown"}, + {"2.16.840.1.101.2.1.1.18", "Unknown"}, + {"2.16.840.1.101.2.1.1.19", "MISSI DSS Algorithm"}, + {"2.16.840.1.101.2.1.1.20", "MISSI KEA and DSS Algorithm"}, + {"2.16.840.1.101.2.1.1.21", "Unknown"}, + {"1.2.643.2.2.35.0", "GOST_R_34.10-2001_Test"}, + {"1.2.643.2.2.35.1", "GOST_R_34.10-2001_Sign_DH_PRO"}, + {"1.2.643.2.2.35.2", "GOST_R_34.10-2001_Sign_DH_CARD"}, + {"1.2.643.2.2.35.3", "GOST_R_34.10-2001_Sign_DH"}, + {"1.2.643.2.2.36.0", "GOST_R_34.10-2001_Sign_DH_PRO"} +}; + +const int nOID = SAL_N_ELEMENTS(OIDs); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx new file mode 100644 index 000000000..6ded5fa0c --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.cxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <memory> + +#include <rtl/uuid.h> +#include <rtl/ustring.hxx> +#include <com/sun/star/security/ExtAltNameType.hpp> +#include <com/sun/star/security/CertAltNameEntry.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <comphelper/sequence.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#include "sanextension_mscryptimpl.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::security ; + +using ::com::sun::star::security::XCertificateExtension ; + + +SanExtensionImpl::SanExtensionImpl() : + m_critical( false ) +{ +} + +SanExtensionImpl::~SanExtensionImpl() { +} + + +//Methods from XCertificateExtension +sal_Bool SAL_CALL SanExtensionImpl::isCritical() { + return m_critical ; +} + +css::uno::Sequence< sal_Int8 > SAL_CALL SanExtensionImpl::getExtensionId() { + return m_xExtnId ; +} + +css::uno::Sequence< sal_Int8 > SAL_CALL SanExtensionImpl::getExtensionValue() { + return m_xExtnValue ; +} + +//Methods from XSanExtension +css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL SanExtensionImpl::getAlternativeNames(){ + + if (!m_Entries.hasElements()) + { + CERT_ALT_NAME_INFO *subjectName; + DWORD size; + CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, reinterpret_cast<unsigned char*>(m_xExtnValue.getArray()), m_xExtnValue.getLength(), CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, nullptr,&subjectName, &size); + + auto arrCertAltNameEntry = std::make_unique<CertAltNameEntry[]>(subjectName->cAltEntry); + + for (unsigned int i = 0; i < static_cast<unsigned int>(subjectName->cAltEntry); i++){ + PCERT_ALT_NAME_ENTRY pEntry = &subjectName->rgAltEntry[i]; + + switch(pEntry->dwAltNameChoice) { + case CERT_ALT_NAME_OTHER_NAME : + { + arrCertAltNameEntry[i].Type = ExtAltNameType_OTHER_NAME; + PCERT_OTHER_NAME pOtherName = pEntry->pOtherName; + + css::beans::NamedValue otherNameProp; + otherNameProp.Name = OUString::createFromAscii(pOtherName->pszObjId); + + Sequence< sal_Int8 > otherName( comphelper::arrayToSequence<sal_Int8>( + pOtherName->Value.pbData, pOtherName->Value.cbData) ); + otherNameProp.Value <<= otherName; + + arrCertAltNameEntry[i].Value <<= otherNameProp; + break; + } + case CERT_ALT_NAME_RFC822_NAME : + arrCertAltNameEntry[i].Type = ExtAltNameType_RFC822_NAME; + arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszRfc822Name)); + break; + case CERT_ALT_NAME_DNS_NAME : + arrCertAltNameEntry[i].Type = ExtAltNameType_DNS_NAME; + arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszDNSName)); + break; + case CERT_ALT_NAME_DIRECTORY_NAME : + { + arrCertAltNameEntry[i].Type = ExtAltNameType_DIRECTORY_NAME; + break; + } + case CERT_ALT_NAME_URL : + arrCertAltNameEntry[i].Type = ExtAltNameType_URL; + arrCertAltNameEntry[i].Value <<= OUString(o3tl::toU(pEntry->pwszURL)); + break; + case CERT_ALT_NAME_IP_ADDRESS : + { + arrCertAltNameEntry[i].Type = ExtAltNameType_IP_ADDRESS; + + Sequence< sal_Int8 > ipAddress( comphelper::arrayToSequence<sal_Int8>( + pEntry->IPAddress.pbData, pEntry->IPAddress.cbData) ); + arrCertAltNameEntry[i].Value <<= ipAddress; + break; + } + case CERT_ALT_NAME_REGISTERED_ID : + arrCertAltNameEntry[i].Type = ExtAltNameType_REGISTERED_ID; + arrCertAltNameEntry[i].Value <<= OUString::createFromAscii(pEntry->pszRegisteredID); + break; + } + } + m_Entries = ::comphelper::arrayToSequence< css::security::CertAltNameEntry >(arrCertAltNameEntry.get(), subjectName->cAltEntry); + } + + return m_Entries; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx new file mode 100644 index 000000000..6c65c84f8 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/sanextension_mscryptimpl.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <Windows.h> +#include <WinCrypt.h> +#include <sal/config.h> +#include <rtl/ustring.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/SecurityException.hpp> +#include <com/sun/star/security/XCertificateExtension.hpp> +#include <com/sun/star/security/XSanExtension.hpp> +#include <com/sun/star/security/CertAltNameEntry.hpp> + +class SanExtensionImpl : public ::cppu::WeakImplHelper< + css::security::XSanExtension > +{ + private: + bool m_critical ; + css::uno::Sequence< sal_Int8 > m_xExtnId ; + css::uno::Sequence< sal_Int8 > m_xExtnValue ; + + css::uno::Sequence< css::security::CertAltNameEntry > m_Entries; + + public: + SanExtensionImpl() ; + virtual ~SanExtensionImpl() override; + + //Methods from XCertificateExtension + virtual sal_Bool SAL_CALL isCritical() override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionId() override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getExtensionValue() override; + + //Methods from XSanExtension + + virtual css::uno::Sequence< css::security::CertAltNameEntry > SAL_CALL getAlternativeNames() override; + + //Helper method + void setCertExtn( unsigned char* value, unsigned int vlen, unsigned char* id, unsigned int idlen, bool critical ) ; +} ; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx new file mode 100644 index 000000000..f198f839f --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx @@ -0,0 +1,1118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cstddef> +#include <string.h> + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <Windows.h> +#include <WinCrypt.h> +#include <sal/macros.h> +#include <osl/thread.h> +#include "securityenvironment_mscryptimpl.hxx" + +#include "x509certificate_mscryptimpl.hxx" +#include <comphelper/servicehelper.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <xmlsec-wrapper.h> +#include "akmngr.hxx" + +#include <biginteger.hxx> + +#include <comphelper/windowserrorstring.hxx> +#include <sal/log.hxx> +#include <rtl/locale.h> +#include <rtl/ref.hxx> +#include <osl/nlsupport.h> +#include <osl/process.h> +#include <o3tl/char16_t2wchar_t.hxx> +#include <svl/cryptosign.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang ; +using ::com::sun::star::lang::XMultiServiceFactory ; +using ::com::sun::star::lang::XSingleServiceFactory ; + +using ::com::sun::star::xml::crypto::XSecurityEnvironment ; +using ::com::sun::star::security::XCertificate ; + +static rtl::Reference<X509Certificate_MSCryptImpl> MswcryCertContextToXCert( PCCERT_CONTEXT cert ) ; + +namespace { + +struct CertErrorToString{ + DWORD error; + char const * name; +}; + +} + +CertErrorToString const arErrStrings[] = +{ + { 0x00000000, "CERT_TRUST_NO_ERROR"}, + { 0x00000001, "CERT_TRUST_IS_NOT_TIME_VALID"}, + { 0x00000002, "CERT_TRUST_IS_NOT_TIME_NESTED"}, + { 0x00000004, "CERT_TRUST_IS_REVOKED" }, + { 0x00000008, "CERT_TRUST_IS_NOT_SIGNATURE_VALID" }, + { 0x00000010, "CERT_TRUST_IS_NOT_SIGNATURE_VALID"}, + { 0x00000020, "CERT_TRUST_IS_UNTRUSTED_ROOT"}, + { 0x00000040, "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"}, + { 0x00000080, "CERT_TRUST_IS_CYCLIC"}, + { 0x00000100, "CERT_TRUST_INVALID_EXTENSION"}, + { 0x00000200, "CERT_TRUST_INVALID_POLICY_CONSTRAINTS"}, + { 0x00000400, "CERT_TRUST_INVALID_BASIC_CONSTRAINTS"}, + { 0x00000800, "CERT_TRUST_INVALID_NAME_CONSTRAINTS"}, + { 0x00001000, "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT"}, + { 0x00002000, "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT"}, + { 0x00004000, "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT"}, + { 0x00008000, "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT"}, + { 0x01000000, "CERT_TRUST_IS_OFFLINE_REVOCATION"}, + { 0x02000000, "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY"}, + { 0x04000000, "CERT_TRUST_IS_EXPLICIT_DISTRUST"}, + { 0x08000000, "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT"}, + //Chain errors + { 0x00010000, "CERT_TRUST_IS_PARTIAL_CHAIN"}, + { 0x00020000, "CERT_TRUST_CTL_IS_NOT_TIME_VALID"}, + { 0x00040000, "CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID"}, + { 0x00080000, "CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE"} +}; + +static void traceTrustStatus(DWORD err) +{ + if (err == 0) + SAL_INFO("xmlsecurity.xmlsec", " " << arErrStrings[0].name); + for (std::size_t i = 1; i < SAL_N_ELEMENTS(arErrStrings); i++) + { + if (arErrStrings[i].error & err) + SAL_INFO("xmlsecurity.xmlsec", " " << arErrStrings[i].name); + } +} + +SecurityEnvironment_MSCryptImpl::SecurityEnvironment_MSCryptImpl( const uno::Reference< uno::XComponentContext >& xContext ) : m_hProv( 0 ) , m_pszContainer( nullptr ) , m_hKeyStore( nullptr ), m_hCertStore( nullptr ), m_hMySystemStore(nullptr), m_hRootSystemStore(nullptr), m_hTrustSystemStore(nullptr), m_hCaSystemStore(nullptr), m_bEnableDefault( false ){ + + m_xServiceManager.set(xContext, uno::UNO_QUERY); +} + +SecurityEnvironment_MSCryptImpl::~SecurityEnvironment_MSCryptImpl() { + + if( m_hProv != 0 ) { + CryptReleaseContext( m_hProv, 0 ) ; + m_hProv = 0 ; + } + + if( m_pszContainer != nullptr ) { + //TODO: Don't know whether or not it should be released now. + m_pszContainer = nullptr ; + } + + if( m_hCertStore != nullptr ) { + CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ; + m_hCertStore = nullptr ; + } + + if( m_hKeyStore != nullptr ) { + CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ; + m_hKeyStore = nullptr ; + } + + //i120675, close the store handles + if( m_hMySystemStore != nullptr ) { + CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hMySystemStore = nullptr ; + } + + if( m_hRootSystemStore != nullptr ) { + CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hRootSystemStore = nullptr ; + } + + if( m_hTrustSystemStore != nullptr ) { + CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hTrustSystemStore = nullptr ; + } + + if( m_hCaSystemStore != nullptr ) { + CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hCaSystemStore = nullptr ; + } +} + +/* XServiceInfo */ +OUString SAL_CALL SecurityEnvironment_MSCryptImpl::getImplementationName() { + return "com.sun.star.xml.crypto.SecurityEnvironment"; +} + +/* XServiceInfo */ +sal_Bool SAL_CALL SecurityEnvironment_MSCryptImpl::supportsService( const OUString& serviceName) { + return cppu::supportsService(this, serviceName); +} +/* XServiceInfo */ +uno::Sequence< OUString > SAL_CALL SecurityEnvironment_MSCryptImpl::getSupportedServiceNames() { + return { "com.sun.star.xml.crypto.SecurityEnvironment" }; +} + +/* XUnoTunnel */ +UNO3_GETIMPLEMENTATION_IMPL(SecurityEnvironment_MSCryptImpl); + +HCRYPTPROV SecurityEnvironment_MSCryptImpl::getCryptoProvider() { + return m_hProv ; +} + +void SecurityEnvironment_MSCryptImpl::setCryptoProvider( HCRYPTPROV aProv ) { + if( m_hProv != 0 ) { + CryptReleaseContext( m_hProv, 0 ) ; + m_hProv = 0 ; + } + + if( aProv != 0 ) { + m_hProv = aProv ; + } +} + +LPCTSTR SecurityEnvironment_MSCryptImpl::getKeyContainer() { + return m_pszContainer ; +} + +void SecurityEnvironment_MSCryptImpl::setKeyContainer( LPCTSTR aKeyContainer ) { + //TODO: Don't know whether or not it should be copied. + m_pszContainer = aKeyContainer ; +} + + +HCERTSTORE SecurityEnvironment_MSCryptImpl::getCryptoSlot() { + return m_hKeyStore ; +} + +void SecurityEnvironment_MSCryptImpl::setCryptoSlot( HCERTSTORE aSlot) { + if( m_hKeyStore != nullptr ) { + CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ; + m_hKeyStore = nullptr ; + } + + if( aSlot != nullptr ) { + m_hKeyStore = CertDuplicateStore( aSlot ) ; + } +} + +HCERTSTORE SecurityEnvironment_MSCryptImpl::getCertDb() { + return m_hCertStore ; +} + +void SecurityEnvironment_MSCryptImpl::setCertDb( HCERTSTORE aCertDb ) { + if( m_hCertStore != nullptr ) { + CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ; + m_hCertStore = nullptr ; + } + + if( aCertDb != nullptr ) { + m_hCertStore = CertDuplicateStore( aCertDb ) ; + } +} + +#ifdef SAL_LOG_INFO + +// Based on sample code from MSDN + +static OUString get_system_name(const void *pvSystemStore, + DWORD dwFlags) +{ + LPCWSTR ppwszSystemName; + if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) + { + _CERT_SYSTEM_STORE_RELOCATE_PARA const * pRelocatePara; + pRelocatePara = static_cast<_CERT_SYSTEM_STORE_RELOCATE_PARA const *>(pvSystemStore); + ppwszSystemName = pRelocatePara->pwszSystemStore; + } + else + { + ppwszSystemName = static_cast<LPCWSTR>(pvSystemStore); + } + return OUString(o3tl::toU(ppwszSystemName)); +} + +extern "C" { + +static BOOL WINAPI cert_enum_physical_store_callback(const void *, + DWORD dwFlags, + LPCWSTR pwszStoreName, + PCERT_PHYSICAL_STORE_INFO, + void *, + void *) +{ + OUString name(o3tl::toU(pwszStoreName)); + if (dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG) + name += " (implicitly created)"; + SAL_INFO("xmlsecurity.xmlsec", " Physical store: " << name); + + return TRUE; +} + +static BOOL WINAPI cert_enum_system_store_callback(const void *pvSystemStore, + DWORD dwFlags, + PCERT_SYSTEM_STORE_INFO, + void *, + void *) +{ + SAL_INFO("xmlsecurity.xmlsec", "System store: " << get_system_name(pvSystemStore, dwFlags)); + + if (!CertEnumPhysicalStore(pvSystemStore, + dwFlags, + nullptr, + cert_enum_physical_store_callback)) + { + DWORD dwErr = GetLastError(); + if (!(ERROR_FILE_NOT_FOUND == dwErr || + ERROR_NOT_SUPPORTED == dwErr)) + { + SAL_WARN("xmlsecurity.xmlsec", "CertEnumPhysicalStore failed:" << WindowsErrorString(GetLastError())); + } + } + return TRUE; +} + +} + +#endif + +//Methods from XSecurityEnvironment +uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::getPersonalCertificates() +{ + sal_Int32 length ; + rtl::Reference<X509Certificate_MSCryptImpl> xcert ; + std::vector< rtl::Reference<X509Certificate_MSCryptImpl> > certsList ; + PCCERT_CONTEXT pCertContext = nullptr; + + //firstly, we try to find private keys in given key store. + if( m_hKeyStore != nullptr ) { + pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext ); + while (pCertContext) + { + xcert = MswcryCertContextToXCert( pCertContext ) ; + if( xcert.is() ) + certsList.push_back( xcert ) ; + pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext ); + } + } + + //Thirdly, we try to find certificate from system default key store. + if( m_bEnableDefault ) { + HCERTSTORE hSystemKeyStore ; + DWORD dwKeySpec; + NCRYPT_KEY_HANDLE hCryptKey; + +#ifdef SAL_LOG_INFO + CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, nullptr, nullptr, cert_enum_system_store_callback); +#endif + + hSystemKeyStore = CertOpenSystemStoreW( 0, L"MY" ) ; + if( hSystemKeyStore != nullptr ) { + pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext ); + while (pCertContext) + { + // for checking whether the certificate is a personal certificate or not. + DWORD dwFlags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey; + if(!(CryptAcquireCertificatePrivateKey(pCertContext, + dwFlags, + nullptr, + phCryptProvOrNCryptKey, + &dwKeySpec, + nullptr))) + { + // Not Privatekey found. SKIP this one. + pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext ); + continue; + } + // then TODO : Check the personal cert is valid or not. + + xcert = MswcryCertContextToXCert( pCertContext ) ; + if( xcert.is() ) + certsList.push_back( xcert ) ; + pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext ); + } + } + + CertCloseStore( hSystemKeyStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + } + + length = certsList.size() ; + if( length != 0 ) { + int i = 0; + uno::Sequence< uno::Reference< XCertificate > > certSeq( length ) ; + auto pcertSeq = certSeq.getArray(); + + for( const auto& rXCert : certsList ) { + pcertSeq[i] = rXCert ; + ++i; + } + + return certSeq ; + } + + return uno::Sequence< uno::Reference< XCertificate > >() ; +} + + +uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const uno::Sequence< sal_Int8 >& serialNumber ) { + unsigned int i ; + rtl::Reference<X509Certificate_MSCryptImpl> xcert ; + PCCERT_CONTEXT pCertContext = nullptr ; + HCERTSTORE hCertStore = nullptr ; + CRYPT_INTEGER_BLOB cryptSerialNumber ; + CERT_INFO certInfo ; + + // for correct encoding + rtl_Locale *pLocale = nullptr ; + osl_getProcessLocale( &pLocale ) ; + + //Create cert info from issue and serial + LPCWSTR pszName = o3tl::toW( issuerName.getStr() ); + + if( ! ( CertStrToNameW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + pszName , + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG, + nullptr , + nullptr , + &certInfo.Issuer.cbData, nullptr ) ) + ) { + return nullptr ; + } + + certInfo.Issuer.pbData = static_cast<BYTE*>(malloc( certInfo.Issuer.cbData )); + if(!certInfo.Issuer.pbData) + throw uno::RuntimeException() ; + + if( ! ( CertStrToNameW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + pszName , + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG, + nullptr , + certInfo.Issuer.pbData , + &certInfo.Issuer.cbData, nullptr ) ) + ) { + free( certInfo.Issuer.pbData ) ; + return nullptr ; + } + + //Get the SerialNumber + cryptSerialNumber.cbData = serialNumber.getLength() ; + cryptSerialNumber.pbData = static_cast<BYTE*>(malloc( cryptSerialNumber.cbData)); + if (!cryptSerialNumber.pbData) + { + free( certInfo.Issuer.pbData ) ; + throw uno::RuntimeException() ; + } + for( i = 0; i < cryptSerialNumber.cbData; i ++ ) + cryptSerialNumber.pbData[i] = serialNumber[ cryptSerialNumber.cbData - i - 1 ] ; + + certInfo.SerialNumber.cbData = cryptSerialNumber.cbData ; + certInfo.SerialNumber.pbData = cryptSerialNumber.pbData ; + + // Get the Cert from all store. + for( i = 0 ; i < 6 ; i ++ ) + { + switch(i) + { + case 0: + if(m_hKeyStore == nullptr) continue ; + hCertStore = m_hKeyStore ; + break; + case 1: + if(m_hCertStore == nullptr) continue ; + hCertStore = m_hCertStore ; + break; + case 2: + hCertStore = CertOpenSystemStoreW( 0, L"MY" ) ; + if(hCertStore == nullptr || !m_bEnableDefault) continue ; + break; + case 3: + hCertStore = CertOpenSystemStoreW( 0, L"Root" ) ; + if(hCertStore == nullptr || !m_bEnableDefault) continue ; + break; + case 4: + hCertStore = CertOpenSystemStoreW( 0, L"Trust" ) ; + if(hCertStore == nullptr || !m_bEnableDefault) continue ; + break; + case 5: + hCertStore = CertOpenSystemStoreW( 0, L"CA" ) ; + if(hCertStore == nullptr || !m_bEnableDefault) continue ; + break; + default: + i=6; + continue; + } + +/******************************************************************************* + * This code reserved for remind us there are another way to find one cert by + * IssuerName&serialnumber. You can use the code to replaced the function + * CertFindCertificateInStore IF and ONLY IF you must find one special cert in + * certStore but can not be found by CertFindCertificateInStore , then , you + * should also change the same part in libxmlsec/.../src/mscrypto/x509vfy.c#875. + * By Chandler Peng(chandler.peng@sun.com) + *****/ +/******************************************************************************* + pCertContext = NULL ; + found = 0; + do{ + // 1. enum the certs has same string in the issuer string. + pCertContext = CertEnumCertificatesInStore( hCertStore , pCertContext ) ; + if( pCertContext != NULL ) + { + // 2. check the cert's issuer name . + char* issuer = NULL ; + DWORD cbIssuer = 0 ; + + cbIssuer = CertNameToStr( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( pCertContext->pCertInfo->Issuer ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + NULL, 0 + ) ; + + if( cbIssuer == 0 ) continue ; // discard this cert; + + issuer = (char *)malloc( cbIssuer ) ; + if( issuer == NULL ) // discard this cert; + { + free( cryptSerialNumber.pbData) ; + free( certInfo.Issuer.pbData ) ; + CertFreeCertificateContext( pCertContext ) ; + if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + throw RuntimeException() ; + } + + cbIssuer = CertNameToStr( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( pCertContext->pCertInfo->Issuer ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + issuer, cbIssuer + ) ; + + if( cbIssuer <= 0 ) + { + free( issuer ) ; + continue ;// discard this cert; + } + + if(strncmp(pszName , issuer , cbIssuer) != 0) + { + free( issuer ) ; + continue ;// discard this cert; + } + free( issuer ) ; + + // 3. check the serial number. + if( memcmp( cryptSerialNumber.pbData , pCertContext->pCertInfo->SerialNumber.pbData , cryptSerialNumber.cbData ) != 0 ) + { + continue ;// discard this cert; + } + + // 4. confirm and break; + found = 1; + break ; + } + + }while(pCertContext); + + if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + if( found != 0 ) break; // Found the certificate. +********************************************************************************/ + + pCertContext = CertFindCertificateInStore( + hCertStore, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + nullptr + ) ; + + if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + if( pCertContext != nullptr ) break ; // Found the certificate. + + } + + free(cryptSerialNumber.pbData); + free(certInfo.Issuer.pbData); + + if( pCertContext != nullptr ) { + xcert = MswcryCertContextToXCert(pCertContext); + CertFreeCertificateContext(pCertContext); + } + + return xcert ; +} + +uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const OUString& serialNumber ) { + uno::Sequence< sal_Int8 > serial = xmlsecurity::numericStringToBigInteger( serialNumber ) ; + return getCertificate( issuerName, serial ) ; +} + +uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::buildCertificatePath( const uno::Reference< XCertificate >& begin ) { + PCCERT_CHAIN_CONTEXT pChainContext ; + PCCERT_CONTEXT pCertContext ; + + CERT_ENHKEY_USAGE enhKeyUsage ; + CERT_USAGE_MATCH certUsage ; + CERT_CHAIN_PARA chainPara ; + + enhKeyUsage.cUsageIdentifier = 0 ; + enhKeyUsage.rgpszUsageIdentifier = nullptr ; + certUsage.dwType = USAGE_MATCH_TYPE_AND ; + certUsage.Usage = enhKeyUsage ; + chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ; + chainPara.RequestedUsage = certUsage ; + + uno::Reference< XUnoTunnel > xCertTunnel( begin, uno::UNO_QUERY_THROW ) ; + const auto* xcert = comphelper::getFromUnoTunnel<X509Certificate_MSCryptImpl>(xCertTunnel); + if( xcert == nullptr ) { + throw uno::RuntimeException() ; + } + + pCertContext = xcert->getMswcryCert() ; + + pChainContext = nullptr ; + + bool bChain = false; + if( pCertContext != nullptr ) + { + HCERTSTORE hAdditionalStore = nullptr; + HCERTSTORE hCollectionStore = nullptr; + if (m_hCertStore && m_hKeyStore) + { + //Merge m_hCertStore and m_hKeyStore into one store. + hCollectionStore = CertOpenStore( + CERT_STORE_PROV_COLLECTION , + 0 , + 0 , + 0 , + nullptr + ) ; + if (hCollectionStore != nullptr) + { + CertAddStoreToCollection ( + hCollectionStore , + m_hCertStore , + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , + 0) ; + CertAddStoreToCollection ( + hCollectionStore , + m_hKeyStore, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , + 0) ; + hAdditionalStore = hCollectionStore; + } + + } + + //if the merge of both stores failed then we add only m_hCertStore + if (hAdditionalStore == nullptr && m_hCertStore) + hAdditionalStore = m_hCertStore; + else if (hAdditionalStore == nullptr && m_hKeyStore) + hAdditionalStore = m_hKeyStore; + else + hAdditionalStore = nullptr; + + //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST + bChain = CertGetCertificateChain( + nullptr , + pCertContext , + nullptr , //use current system time + hAdditionalStore, + &chainPara , + CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_TIMESTAMP_TIME , + nullptr , + &pChainContext); + if (!bChain) + pChainContext = nullptr; + + //Close the additional store + CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG); + } + + if(bChain && pChainContext != nullptr && pChainContext->cChain > 0 ) + { + PCCERT_CONTEXT pCertInChain ; + PCERT_SIMPLE_CHAIN pCertChain ; + rtl::Reference<X509Certificate_MSCryptImpl> pCert ; + + pCertChain = pChainContext->rgpChain[0] ; + if( pCertChain->cElement ) { + uno::Sequence< uno::Reference< XCertificate > > xCertChain( pCertChain->cElement ) ; + auto pxCertChain = xCertChain.getArray(); + + for( unsigned int i = 0 ; i < pCertChain->cElement ; i ++ ) { + if( pCertChain->rgpElement[i] ) + pCertInChain = pCertChain->rgpElement[i]->pCertContext ; + else + pCertInChain = nullptr ; + + if( pCertInChain != nullptr ) { + pCert = MswcryCertContextToXCert( pCertInChain ) ; + if( pCert.is() ) + pxCertChain[i] = pCert ; + } + } + + CertFreeCertificateChain( pChainContext ) ; + pChainContext = nullptr ; + + return xCertChain ; + } + } + if (pChainContext) + CertFreeCertificateChain(pChainContext); + + return uno::Sequence< uno::Reference < XCertificate > >(); +} + +uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromRaw( const uno::Sequence< sal_Int8 >& rawCertificate ) { + rtl::Reference<X509Certificate_MSCryptImpl> xcert ; + + if( rawCertificate.getLength() > 0 ) { + xcert = new X509Certificate_MSCryptImpl() ; + xcert->setRawCert( rawCertificate ) ; + } + + return xcert ; +} + +uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromAscii( const OUString& asciiCertificate ) { + + OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ; + + xmlChar* chCert = xmlStrndup( reinterpret_cast<const xmlChar*>(oscert.getStr()), static_cast<int>(oscert.getLength()) ) ; + + xmlSecSize certSize = xmlSecBase64Decode( chCert, chCert, xmlStrlen( chCert ) ) ; + + uno::Sequence< sal_Int8 > rawCert( certSize ) ; + auto rawCertRange = asNonConstRange(rawCert); + for( xmlSecSize i = 0 ; i < certSize ; i ++ ) + rawCertRange[i] = *( chCert + i ) ; + + xmlFree( chCert ) ; + + return createCertificateFromRaw( rawCert ) ; +} + + +static HCERTSTORE getCertStoreForIntermediatCerts( + const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts) +{ + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, nullptr); + if (store == nullptr) + return nullptr; + + for (int i = 0; i < seqCerts.getLength(); i++) + { + SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " << seqCerts[i]->getSubjectName()); + + uno::Sequence<sal_Int8> data = seqCerts[i]->getEncoded(); + PCCERT_CONTEXT cert = CertCreateCertificateContext( + X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(&data[0]), data.getLength()); + //Adding the certificate creates a copy and not just increases the ref count + //Therefore we free later the certificate that we now add + CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_ALWAYS, nullptr); + CertFreeCertificateContext(cert); + } + return store; +} + +static bool CheckUnitTestStore(PCCERT_CHAIN_CONTEXT const pChainContext, DWORD ignoreFlags) +{ + bool ret = false; + static char const*const pVar = getenv("LIBO_TEST_CRYPTOAPI_PKCS7"); + if (!pVar) + { + return ret; + } + if (pChainContext->cChain == 0) + { + return ret; + } + PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0]; + // check if untrusted root is the only problem + if (pSimpleChain->TrustStatus.dwErrorStatus & ~(CERT_TRUST_IS_UNTRUSTED_ROOT | ignoreFlags)) + { + return ret; + } + + // leak this store, re-opening is a waste of time in tests + static HCERTSTORE const hExtra = CertOpenStore( + CERT_STORE_PROV_FILENAME_A, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, + CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, + OString(OString::Concat(pVar) + "/test.p7b").getStr()); + assert(hExtra != nullptr); + if (pSimpleChain->cElement < 1) + { + SAL_WARN("xmlsecurity.xmlsec", "unexpected empty chain"); + return ret; + } + PCCERT_CONTEXT const pRoot(pSimpleChain->rgpElement[pSimpleChain->cElement-1]->pCertContext); + PCCERT_CONTEXT const pIssuerCert = CertFindCertificateInStore( + hExtra, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &pRoot->pCertInfo->Subject, + nullptr); + if (pIssuerCert) + { + // check that it signed itself + DWORD flags = CERT_STORE_SIGNATURE_FLAG; + bool result = CertVerifySubjectCertificateContext(pRoot, pIssuerCert, &flags); + if (result && flags == 0) + { + ret = true; + } + } + CertFreeCertificateContext(pIssuerCert); + return ret; +} + +//We return only valid or invalid, as long as the API documentation expresses +//explicitly that all validation steps are carried out even if one or several +//errors occur. See also +//http://wiki.openoffice.org/wiki/Certificate_Path_Validation#Validation_status +sal_Int32 SecurityEnvironment_MSCryptImpl::verifyCertificate( + const uno::Reference< css::security::XCertificate >& aCert, + const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts) +{ + sal_Int32 validity = css::security::CertificateValidity::INVALID; + PCCERT_CHAIN_CONTEXT pChainContext = nullptr; + PCCERT_CONTEXT pCertContext = nullptr; + + uno::Reference< XUnoTunnel > xCertTunnel( aCert, uno::UNO_QUERY_THROW ) ; + + SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName()); + + const auto* xcert = comphelper::getFromUnoTunnel<X509Certificate_MSCryptImpl>(xCertTunnel); + if( xcert == nullptr ) { + throw uno::RuntimeException() ; + } + + pCertContext = xcert->getMswcryCert() ; + + CERT_ENHKEY_USAGE enhKeyUsage ; + CERT_USAGE_MATCH certUsage ; + CERT_CHAIN_PARA chainPara = {}; + + //Prepare parameter for CertGetCertificateChain + enhKeyUsage.cUsageIdentifier = 0 ; + enhKeyUsage.rgpszUsageIdentifier = nullptr ; + certUsage.dwType = USAGE_MATCH_TYPE_AND ; + certUsage.Usage = enhKeyUsage ; + chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ; + chainPara.RequestedUsage = certUsage ; + + + HCERTSTORE hCollectionStore = nullptr; + HCERTSTORE hIntermediateCertsStore = nullptr; + bool bChain = false; + if( pCertContext != nullptr ) + { + hIntermediateCertsStore = + getCertStoreForIntermediatCerts(seqCerts); + + //Merge m_hCertStore and m_hKeyStore and the store of the intermediate + //certificates into one store. + hCollectionStore = CertOpenStore( + CERT_STORE_PROV_COLLECTION , + 0 , + 0 , + 0 , + nullptr + ) ; + if (hCollectionStore != nullptr) + { + CertAddStoreToCollection ( + hCollectionStore , + m_hCertStore , + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , + 0) ; + CertAddStoreToCollection ( + hCollectionStore , + m_hKeyStore, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , + 0) ; + CertAddStoreToCollection ( + hCollectionStore, + hIntermediateCertsStore, + CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, + 0); + + } + + //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST + //We do not check revocation of the root. In most cases there are none. + //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN + SAL_INFO("xmlsecurity.xmlsec", "Verifying cert using revocation information."); + bChain = CertGetCertificateChain( + nullptr , + pCertContext , + nullptr , //use current system time + hCollectionStore, + &chainPara , + CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, + nullptr , + &pChainContext); + + if (bChain && pChainContext->cChain > 0) + { + SAL_INFO("xmlsecurity.xmlsec", "Overall error status (all chains):"); + traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus); + //highest quality chains come first + PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0]; + SAL_INFO("xmlsecurity.xmlsec", "Error status of first chain:"); + traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus); + + //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate + //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed. + DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN | + CERT_TRUST_IS_OFFLINE_REVOCATION; + DWORD otherErrorsMask = ~revocationFlags; + if (!(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask) + || CheckUnitTestStore(pChainContext, revocationFlags)) + + { + //No errors except maybe those caused by missing revocation information + //Check if there are errors + if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags) + { + //No revocation information. Because MSDN documentation is not + //clear about if all other tests are performed if an error occurs, + //we test again, without requiring revocation checking. + CertFreeCertificateChain(pChainContext); + pChainContext = nullptr; + SAL_INFO("xmlsecurity.xmlsec", "Checking again but without requiring revocation information."); + bChain = CertGetCertificateChain( + nullptr , + pCertContext , + nullptr , //use current system time + hCollectionStore, + &chainPara , + 0, + nullptr , + &pChainContext); + if (bChain + && pChainContext->cChain > 0 + && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR) + { + SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid."); + validity = css::security::CertificateValidity::VALID; + } + else if (CheckUnitTestStore(pChainContext, 0)) + { + SAL_INFO("xmlsecurity.xmlsec", "root certificate found in extra test store"); + validity = css::security::CertificateValidity::VALID; + } + else + { + SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid."); + } + } + else + { + //valid and revocation information available + SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid."); + validity = css::security::CertificateValidity::VALID; + } + } + else + { + //invalid + SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid."); + validity = css::security::CertificateValidity::INVALID ; + } + } + else + { + SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChain failed."); + } + } + + if (pChainContext) + { + CertFreeCertificateChain(pChainContext); + pChainContext = nullptr; + } + + //Close the additional store, do not destroy the contained certs + CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG); + //Close the temporary store containing the intermediate certificates and make + //sure all certificates are deleted. + CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG); + + return validity ; +} + +sal_Int32 SecurityEnvironment_MSCryptImpl::getCertificateCharacters( const css::uno::Reference< css::security::XCertificate >& aCert ) { + sal_Int32 characters ; + PCCERT_CONTEXT pCertContext ; + + uno::Reference< XUnoTunnel > xCertTunnel( aCert, uno::UNO_QUERY_THROW ) ; + const auto* xcert = comphelper::getFromUnoTunnel<X509Certificate_MSCryptImpl>(xCertTunnel); + if( xcert == nullptr ) { + throw uno::RuntimeException() ; + } + + pCertContext = xcert->getMswcryCert() ; + + characters = 0x00000000 ; + + //Firstly, make sentence whether or not the cert is self-signed. + if( CertCompareCertificateName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pCertContext->pCertInfo->Subject), &(pCertContext->pCertInfo->Issuer) ) ) { + characters |= css::security::CertificateCharacters::SELF_SIGNED ; + } else { + characters &= ~ css::security::CertificateCharacters::SELF_SIGNED ; + } + + //Secondly, make sentence whether or not the cert has a private key. + { + BOOL fCallerFreeProv ; + DWORD dwKeySpec ; + NCRYPT_KEY_HANDLE hKey = 0; + DWORD dwFlags = CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hKey; + if( CryptAcquireCertificatePrivateKey( pCertContext , + dwFlags, + nullptr , + phCryptProvOrNCryptKey, + &dwKeySpec, + &fCallerFreeProv ) + ) { + characters |= css::security::CertificateCharacters::HAS_PRIVATE_KEY ; + + if (hKey && fCallerFreeProv) + NCryptFreeObject(hKey); + } else { + characters &= ~ css::security::CertificateCharacters::HAS_PRIVATE_KEY ; + } + } + return characters ; +} + +void SecurityEnvironment_MSCryptImpl::enableDefaultCrypt( bool enable ) { + m_bEnableDefault = enable ; +} + +bool SecurityEnvironment_MSCryptImpl::defaultEnabled() { + return m_bEnableDefault ; +} + +static rtl::Reference<X509Certificate_MSCryptImpl> MswcryCertContextToXCert( PCCERT_CONTEXT cert ) +{ + rtl::Reference<X509Certificate_MSCryptImpl> xcert ; + + if( cert != nullptr ) { + xcert = new X509Certificate_MSCryptImpl() ; + xcert->setMswcryCert( cert ) ; + } + + return xcert ; +} + +OUString SecurityEnvironment_MSCryptImpl::getSecurityEnvironmentInformation() +{ + return "Microsoft Crypto API"; +} + +xmlSecKeysMngrPtr SecurityEnvironment_MSCryptImpl::createKeysManager() { + + /*- + * The following lines is based on the of xmlsec-mscrypto crypto engine + */ + xmlSecKeysMngrPtr pKeysMngr = xmlsecurity::MSCryptoAppliedKeysMngrCreate() ; + if( pKeysMngr == nullptr ) + throw uno::RuntimeException() ; + + /*- + * Adopt system default certificate store. + */ + if( defaultEnabled() ) { + //Add system key store into the keys manager. + m_hMySystemStore = CertOpenSystemStoreW( 0, L"MY" ) ; + if( m_hMySystemStore != nullptr ) { + if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptKeyStore( pKeysMngr, m_hMySystemStore ) < 0 ) { + CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hMySystemStore = nullptr; + throw uno::RuntimeException() ; + } + m_hMySystemStore = nullptr; + } + + //Add system root store into the keys manager. + m_hRootSystemStore = CertOpenSystemStoreW( 0, L"Root" ) ; + if( m_hRootSystemStore != nullptr ) { + if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptTrustedStore( pKeysMngr, m_hRootSystemStore ) < 0 ) { + CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hRootSystemStore = nullptr; + throw uno::RuntimeException() ; + } + m_hRootSystemStore = nullptr; + } + + //Add system trusted store into the keys manager. + m_hTrustSystemStore = CertOpenSystemStoreW( 0, L"Trust" ) ; + if( m_hTrustSystemStore != nullptr ) { + if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hTrustSystemStore ) < 0 ) { + CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hTrustSystemStore = nullptr; + throw uno::RuntimeException() ; + } + m_hTrustSystemStore = nullptr; + } + + //Add system CA store into the keys manager. + m_hCaSystemStore = CertOpenSystemStoreW( 0, L"CA" ) ; + if( m_hCaSystemStore != nullptr ) { + if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hCaSystemStore ) < 0 ) { + CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ; + m_hCaSystemStore = nullptr; + throw uno::RuntimeException() ; + } + m_hCaSystemStore = nullptr; + } + } + + return pKeysMngr ; +} +void SecurityEnvironment_MSCryptImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) { + if( pKeysMngr != nullptr ) { + xmlSecKeysMngrDestroy( pKeysMngr ) ; + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_xml_crypto_SecurityEnvironment_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SecurityEnvironment_MSCryptImpl(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx new file mode 100644 index 000000000..a4ae45742 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.hxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <wincrypt.h> +#include <sal/config.h> +#include <rtl/ustring.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/uno/Exception.hpp> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/xml/crypto/XSecurityEnvironment.hpp> +#include <com/sun/star/security/XCertificate.hpp> +#include <com/sun/star/security/CertificateCharacters.hpp> +#include <com/sun/star/security/CertificateValidity.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +#include <vector> +#include <xmlsec-wrapper.h> + +#include <sal/types.h> + + +class SecurityEnvironment_MSCryptImpl : public ::cppu::WeakImplHelper< + css::xml::crypto::XSecurityEnvironment , + css::lang::XServiceInfo, + css::lang::XUnoTunnel > +{ + private: + //crypto provider and key container + HCRYPTPROV m_hProv ; + LPCTSTR m_pszContainer ; + + //Key store + HCERTSTORE m_hKeyStore ; + + //Certificate store + HCERTSTORE m_hCertStore ; + + // i120675, save the store handles + HCERTSTORE m_hMySystemStore; + HCERTSTORE m_hRootSystemStore; + HCERTSTORE m_hTrustSystemStore; + HCERTSTORE m_hCaSystemStore; + + //Enable default system cryptography setting + bool m_bEnableDefault ; + + //Service manager + css::uno::Reference< css::lang::XMultiServiceFactory > m_xServiceManager ; + + public: + explicit SecurityEnvironment_MSCryptImpl( const css::uno::Reference< css::uno::XComponentContext >& xContext ) ; + virtual ~SecurityEnvironment_MSCryptImpl() override; + + //Methods from XSecurityEnvironment + virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getPersonalCertificates() override; + virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL getAllCertificates() override + { return css::uno::Sequence< css::uno::Reference< css::security::XCertificate > >(); } + + virtual css::uno::Reference< css::security::XCertificate > SAL_CALL getCertificate( + const OUString& issuerName, + const css::uno::Sequence< sal_Int8 >& serialNumber ) override; + + /// @throws css::uno::SecurityException + /// @throws css::uno::RuntimeException + virtual css::uno::Reference< css::security::XCertificate > getCertificate( + const OUString& issuerName, + const OUString& serialNumber ) ; + + virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > SAL_CALL buildCertificatePath( + const css::uno::Reference< css::security::XCertificate >& beginCert ) override; + + virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromRaw( + const css::uno::Sequence< sal_Int8 >& rawCertificate ) override; + + virtual css::uno::Reference< css::security::XCertificate > SAL_CALL createCertificateFromAscii( + const OUString& asciiCertificate ) override; + + virtual ::sal_Int32 SAL_CALL verifyCertificate( + const css::uno::Reference< css::security::XCertificate >& xCert, + const css::uno::Sequence< css::uno::Reference< + css::security::XCertificate > >& intermediateCertificates) override; + + virtual ::sal_Int32 SAL_CALL getCertificateCharacters( + const css::uno::Reference< css::security::XCertificate >& xCert ) override; + + virtual OUString SAL_CALL getSecurityEnvironmentInformation( ) override; + + + //Methods from XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService( + const OUString& ServiceName + ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //Methods from XUnoTunnel + UNO3_GETIMPLEMENTATION_DECL(SecurityEnvironment_MSCryptImpl) + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + HCRYPTPROV getCryptoProvider() ; + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void setCryptoProvider( HCRYPTPROV aProv ) ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + LPCTSTR getKeyContainer() ; + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void setKeyContainer( LPCTSTR aKeyContainer ) ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + HCERTSTORE getCryptoSlot() ; + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void setCryptoSlot( HCERTSTORE aKeyStore ) ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + HCERTSTORE getCertDb() ; + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void setCertDb( HCERTSTORE aCertDb ) ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void enableDefaultCrypt( bool enable ) ; + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + bool defaultEnabled() ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + xmlSecKeysMngrPtr createKeysManager() ; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + static void destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) ; +} ; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx new file mode 100644 index 000000000..08143f992 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <xmlsec-wrapper.h> + +#include "seinitializer_mscryptimpl.hxx" + +#include "securityenvironment_mscryptimpl.hxx" + +#include <xmlsec/mscng/app.h> +#include <com/sun/star/xml/crypto/SecurityEnvironment.hpp> +#include <com/sun/star/xml/crypto/XMLSecurityContext.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <svl/cryptosign.hxx> + +using namespace com::sun::star; +namespace cssl = com::sun::star::lang; +namespace cssxc = com::sun::star::xml::crypto; + +SEInitializer_MSCryptImpl::SEInitializer_MSCryptImpl( + const uno::Reference< uno::XComponentContext > &rxContext) + :mxContext( rxContext ) +{ +} + +SEInitializer_MSCryptImpl::~SEInitializer_MSCryptImpl() +{ +} + +/* XSEInitializer */ +uno::Reference< cssxc::XXMLSecurityContext > SAL_CALL + SEInitializer_MSCryptImpl::createSecurityContext( + const OUString& sCertDB ) +{ + const char* n_pCertStore ; + HCERTSTORE n_hStoreHandle ; + OString sCertDir; + + //Initialize the crypto engine + if( sCertDB.getLength() > 0 ) + { + sCertDir = OString(sCertDB.getStr(), sCertDB.getLength(), RTL_TEXTENCODING_ASCII_US); + n_pCertStore = sCertDir.getStr(); + n_hStoreHandle = CertOpenSystemStoreW( 0, o3tl::toW(sCertDB.getStr())) ; + if( n_hStoreHandle == nullptr ) + { + return nullptr; + } + } + else + { + n_pCertStore = nullptr ; + n_hStoreHandle = nullptr ; + } + + xmlSecMSCngAppInit(n_pCertStore); + + try { + /* Build Security Environment */ + uno::Reference< cssxc::XSecurityEnvironment > xSecEnv = cssxc::SecurityEnvironment::create( mxContext ); + + /* Setup key slot and certDb */ + uno::Reference< cssl::XUnoTunnel > xSecEnvTunnel( xSecEnv, uno::UNO_QUERY_THROW ); + SecurityEnvironment_MSCryptImpl* pSecEnv = comphelper::getFromUnoTunnel<SecurityEnvironment_MSCryptImpl>(xSecEnvTunnel); + if( pSecEnv == nullptr ) + { + if( n_hStoreHandle != nullptr ) + { + CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ; + } + + xmlSecMSCngAppShutdown(); + return nullptr; + } + + if( n_hStoreHandle != nullptr ) + { + pSecEnv->setCryptoSlot( n_hStoreHandle ) ; + pSecEnv->setCertDb( n_hStoreHandle ) ; + } + else + { + pSecEnv->enableDefaultCrypt( true ) ; + } + + /* Build XML Security Context */ + uno::Reference< cssxc::XXMLSecurityContext > xSecCtx = cssxc::XMLSecurityContext::create( mxContext ); + + xSecCtx->setDefaultSecurityEnvironmentIndex(xSecCtx->addSecurityEnvironment( xSecEnv )) ; + return xSecCtx; + } + catch( uno::Exception& ) + { + if( n_hStoreHandle != nullptr ) + { + CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ; + } + + xmlSecMSCngAppShutdown(); + return nullptr; + } +} + +void SAL_CALL SEInitializer_MSCryptImpl::freeSecurityContext( const uno::Reference< cssxc::XXMLSecurityContext >&) +{ + /* + uno::Reference< cssxc::XSecurityEnvironment > xSecEnv + = securityContext->getSecurityEnvironment(); + + if( xSecEnv.is() ) + { + uno::Reference< cssl::XUnoTunnel > xEnvTunnel( xSecEnv , uno::UNO_QUERY ) ; + if (auto pSecEnv = comphelper::getFromUnoTunnel<SecurityEnvironment_MSCryptImpl>(xEnvTunnel)) + { + HCERTSTORE n_hStoreHandle = pSecEnv->getCryptoSlot(); + + if( n_hStoreHandle != NULL ) + { + CertCloseStore( n_hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG ) ; + pSecEnv->setCryptoSlot( NULL ) ; + pSecEnv->setCertDb( NULL ) ; + } + + xmlSecMSCryptoAppShutdown() ; + } + } + */ + + xmlSecMSCngAppShutdown(); +} + +/* XServiceInfo */ +OUString SAL_CALL SEInitializer_MSCryptImpl::getImplementationName() +{ + return "com.sun.star.xml.crypto.SEInitializer"; +} + +sal_Bool SAL_CALL SEInitializer_MSCryptImpl::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + +uno::Sequence< OUString > SAL_CALL SEInitializer_MSCryptImpl::getSupportedServiceNames() +{ + return { "com.sun.star.xml.crypto.SEInitializer" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_xml_crypto_SEInitializer_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new SEInitializer_MSCryptImpl(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx new file mode 100644 index 000000000..182ba5e5a --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/seinitializer_mscryptimpl.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> +#include <com/sun/star/xml/crypto/XSEInitializer.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase.hxx> + +#include <libxml/tree.h> + +class SEInitializer_MSCryptImpl : public cppu::WeakImplHelper +< + css::xml::crypto::XSEInitializer, + css::lang::XServiceInfo +> +/****** SEInitializer_MSCryptImpl.hxx/CLASS SEInitializer_MSCryptImpl *********** + * + * NAME + * SEInitializer_MSCryptImpl -- Class to initialize a Security Context + * instance + * + * FUNCTION + * Use this class to initialize a XmlSec based Security Context + * instance. After this instance is used up, use this class to free this + * instance. + ******************************************************************************/ +{ +private: + css::uno::Reference< css::uno::XComponentContext > mxContext; + +public: + explicit SEInitializer_MSCryptImpl(const css::uno::Reference< css::uno::XComponentContext > &rxContext); + virtual ~SEInitializer_MSCryptImpl() override; + + /* XSEInitializer */ + virtual css::uno::Reference< css::xml::crypto::XXMLSecurityContext > + SAL_CALL createSecurityContext( const OUString& certDB ) override; + + virtual void SAL_CALL freeSecurityContext( const css::uno::Reference< + css::xml::crypto::XXMLSecurityContext >& securityContext ) override; + + /* XServiceInfo */ + virtual OUString SAL_CALL getImplementationName( ) override; + + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx new file mode 100644 index 000000000..5e0ca9094 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx @@ -0,0 +1,786 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <string.h> + +#include <sal/config.h> +#include <sal/log.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/windowserrorstring.hxx> +#include <cppuhelper/supportsservice.hxx> +#include "x509certificate_mscryptimpl.hxx" +#include <certificateextension_xmlsecimpl.hxx> +#include <biginteger.hxx> +#include "sanextension_mscryptimpl.hxx" + +#include "oid.hxx" + +#include <rtl/locale.h> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/nlsupport.h> +#include <osl/process.h> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <memory> +#include <string_view> +#include <utility> +#include <vector> +#include <tools/time.hxx> +#include <svl/sigstruct.hxx> + +using namespace com::sun::star; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::security ; + +using ::com::sun::star::security::XCertificate ; +using ::com::sun::star::util::DateTime ; + +/*Returns the index within rRawString where sTypeName starts and where it ends. + The starting index is pair.first. The ending index in pair.second points + one char after the last character of the type. + sTypeName can be + "S" or "CN" (without ""). Do not use spaces at the beginning of the type name. + If the type name is not found then pair.first and pair.second are -1. +*/ +static std::pair< sal_Int32, sal_Int32 > +findTypeInDN(const OUString& rRawString, std::u16string_view sTypeName) +{ + std::pair< sal_Int32, sal_Int32 > retVal; + bool bInEscape = false; + bool bInValue = false; + bool bFound = false; + sal_Int32 nTypeNameStart = 0; + sal_Int32 length = rRawString.getLength(); + + for (sal_Int32 i = 0; i < length; i++) + { + sal_Unicode c = rRawString[i]; + + if (c == '=') + { + if (! bInValue) + { + OUString sType = rRawString.copy(nTypeNameStart, i - nTypeNameStart); + sType = sType.trim(); + if (sType.equalsIgnoreAsciiCase(sTypeName)) + { + bFound = true; + break; + } + } + } + else if (c == '"') + { + if (!bInEscape) + { + //If this is the quote is the first of the couple which enclose the + //whole value, because the value contains special characters + //then we just drop it. That is, this character must be followed by + //a character which is not '"'. + if ( i + 1 < length && rRawString[i+1] == '"') + bInEscape = true; + else + bInValue = !bInValue; //value is enclosed in " " + } + else + { + //This quote is escaped by a preceding quote and therefore is + //part of the value + bInEscape = false; + } + } + else if (c == ',' || c == '+') + { + //The comma separate the attribute value pairs. + //If the comma is not part of a value (the value would then be enclosed in '"'), + //then we have reached the end of the value + if (!bInValue) + { + //The next char is the start of the new type + nTypeNameStart = i + 1; + } + } + } + + //Found the Type Name, but there can still be spaces after the last comma + //and the beginning of the type. + if (bFound) + { + while (true) + { + sal_Unicode c = rRawString[nTypeNameStart]; + if (c != ' ' && c != '\t') + //found + break; + nTypeNameStart ++; + } + // search end (one after last letter) + sal_Int32 nTypeNameEnd = nTypeNameStart; + nTypeNameEnd++; + while (true) + { + sal_Unicode c = rRawString[nTypeNameEnd]; + if (c == ' ' || c == '\t' || c == '=') + break; + nTypeNameEnd++; + } + retVal = std::make_pair(nTypeNameStart, nTypeNameEnd); + } + else + { + retVal = std::make_pair(-1, -1); + } + return retVal; +} + + +/* + MS Crypto uses the 'S' tag (equal to the 'ST' tag in NSS), but the NSS can't recognise + it, so the 'S' tag should be changed to 'ST' tag. However I am not sure if this is necessary + anymore, because we provide always the signers certificate when signing. So libmlsec can find + the private key based on the provided certificate (X509Certificate element) and does not need + the issuer name (X509IssuerName element). The issuer name in the xml signature has also no + effect for the signature nor the certificate validation. + In many RFCs, for example 4519, on speaks of 'ST'. However, the certificate does not contain + strings for type names. Instead it uses OIDs. + */ + +static OUString replaceTagSWithTagST(OUString const & oldDN) +{ + std::pair<sal_Int32, sal_Int32 > pairIndex = findTypeInDN(oldDN, u"S"); + + if (pairIndex.first != -1) + { + return OUString::Concat(oldDN.subView(0, pairIndex.first))+"ST" + +oldDN.subView(pairIndex.second); + } + return oldDN; +} +/* end */ + +X509Certificate_MSCryptImpl::X509Certificate_MSCryptImpl() : + m_pCertContext( nullptr ) +{ +} + +X509Certificate_MSCryptImpl::~X509Certificate_MSCryptImpl() { + if( m_pCertContext != nullptr ) { + CertFreeCertificateContext( m_pCertContext ) ; + } +} + +//Methods from XCertificate +sal_Int16 SAL_CALL X509Certificate_MSCryptImpl::getVersion() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + return static_cast<char>(m_pCertContext->pCertInfo->dwVersion) ; + } else { + return -1 ; + } +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSerialNumber() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + Sequence< sal_Int8 > serial( m_pCertContext->pCertInfo->SerialNumber.cbData ) ; + auto serialRange = asNonConstRange(serial); + for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SerialNumber.cbData ; i ++ ) + serialRange[i] = *( m_pCertContext->pCertInfo->SerialNumber.pbData + m_pCertContext->pCertInfo->SerialNumber.cbData - i - 1 ) ; + + return serial ; + } else { + return Sequence< sal_Int8 >(); + } +} + +OUString SAL_CALL X509Certificate_MSCryptImpl::getIssuerName() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + DWORD cchIssuer = CertNameToStrW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( m_pCertContext->pCertInfo->Issuer ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + nullptr, 0 + ) ; + + // Here the cbIssuer count the last 0x00 , take care. + if( cchIssuer != 0 ) { + auto issuer = std::make_unique<wchar_t[]>(cchIssuer); + + cchIssuer = CertNameToStrW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( m_pCertContext->pCertInfo->Issuer ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + issuer.get(), cchIssuer + ) ; + + if( cchIssuer <= 0 ) { + throw RuntimeException() ; + } + + if(issuer.get()[cchIssuer -1] == 0) cchIssuer--; //delimit the last 0x00; + OUString xIssuer(o3tl::toU(issuer.get()), cchIssuer) ; + + return replaceTagSWithTagST(xIssuer); + } else { + return OUString() ; + } + } else { + return OUString() ; + } +} + +OUString SAL_CALL X509Certificate_MSCryptImpl::getSubjectName() +{ + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) + { + DWORD cchSubject = CertNameToStrW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( m_pCertContext->pCertInfo->Subject ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + nullptr, 0 + ) ; + + if( cchSubject != 0 ) + { + auto subject = std::make_unique<wchar_t[]>(cchSubject); + + cchSubject = CertNameToStrW( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING , + &( m_pCertContext->pCertInfo->Subject ), + CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG , + subject.get(), cchSubject + ) ; + + if( cchSubject <= 0 ) { + throw RuntimeException() ; + } + + OUString xSubject(o3tl::toU(subject.get())); + + return replaceTagSWithTagST(xSubject); + } else + { + return OUString() ; + } + } + else + { + return OUString() ; + } +} + +css::util::DateTime SAL_CALL X509Certificate_MSCryptImpl::getNotValidBefore() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + SYSTEMTIME explTime ; + DateTime dateTime ; + FILETIME localFileTime; + + if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotBefore ), &localFileTime)) + { + if( FileTimeToSystemTime( &localFileTime, &explTime ) ) { + //Convert the time to readable local time + dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ; + dateTime.Seconds = explTime.wSecond ; + dateTime.Minutes = explTime.wMinute ; + dateTime.Hours = explTime.wHour ; + dateTime.Day = explTime.wDay ; + dateTime.Month = explTime.wMonth ; + dateTime.Year = explTime.wYear ; + } + } + + return dateTime ; + } else { + return DateTime() ; + } +} + +css::util::DateTime SAL_CALL X509Certificate_MSCryptImpl::getNotValidAfter() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + SYSTEMTIME explTime ; + DateTime dateTime ; + FILETIME localFileTime; + + if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotAfter ), &localFileTime)) + { + if( FileTimeToSystemTime( &localFileTime, &explTime ) ) { + //Convert the time to readable local time + dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ; + dateTime.Seconds = explTime.wSecond ; + dateTime.Minutes = explTime.wMinute ; + dateTime.Hours = explTime.wHour ; + dateTime.Day = explTime.wDay ; + dateTime.Month = explTime.wMonth ; + dateTime.Year = explTime.wYear ; + } + } + + return dateTime ; + } else { + return DateTime() ; + } +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getIssuerUniqueID() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + Sequence< sal_Int8 > issuerUid( m_pCertContext->pCertInfo->IssuerUniqueId.cbData ) ; + auto issuerUidRange = asNonConstRange(issuerUid); + for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->IssuerUniqueId.cbData; i ++ ) + issuerUidRange[i] = *( m_pCertContext->pCertInfo->IssuerUniqueId.pbData + i ) ; + + return issuerUid ; + } else { + return Sequence< sal_Int8 >(); + } +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectUniqueID() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) { + Sequence< sal_Int8 > subjectUid( m_pCertContext->pCertInfo->SubjectUniqueId.cbData ) ; + auto subjectUidRange = asNonConstRange(subjectUid); + for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SubjectUniqueId.cbData; i ++ ) + subjectUidRange[i] = *( m_pCertContext->pCertInfo->SubjectUniqueId.pbData + i ) ; + + return subjectUid ; + } else { + return Sequence< sal_Int8 >(); + } +} + +css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL X509Certificate_MSCryptImpl::getExtensions() { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 ) { + rtl::Reference<CertificateExtension_XmlSecImpl> xExtn ; + Sequence< Reference< XCertificateExtension > > xExtns( m_pCertContext->pCertInfo->cExtension ) ; + auto pExtns = xExtns.getArray(); + + for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) { + CERT_EXTENSION* pExtn = &(m_pCertContext->pCertInfo->rgExtension[i]) ; + + + OUString objId = OUString::createFromAscii( pExtn->pszObjId ); + + if ( objId == "2.5.29.17" ) + xExtn = reinterpret_cast<CertificateExtension_XmlSecImpl*>(new SanExtensionImpl()); + else + xExtn = new CertificateExtension_XmlSecImpl; + + xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ; + + pExtns[i] = xExtn ; + } + + return xExtns ; + } else { + return Sequence< Reference< XCertificateExtension > >(); + } +} + +css::uno::Reference< css::security::XCertificateExtension > SAL_CALL X509Certificate_MSCryptImpl::findCertificateExtension( const css::uno::Sequence< sal_Int8 >& /*oid*/ ) { + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 ) { + rtl::Reference<CertificateExtension_XmlSecImpl> xExtn ; + + for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) { + CERT_EXTENSION* pExtn = &( m_pCertContext->pCertInfo->rgExtension[i] ) ; + + //TODO: Compare the oid + if( false ) { + xExtn = new CertificateExtension_XmlSecImpl; + xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ; + } + } + + return xExtn ; + } else { + return nullptr ; + } +} + + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getEncoded() { + if( m_pCertContext != nullptr && m_pCertContext->cbCertEncoded > 0 ) { + Sequence< sal_Int8 > rawCert( m_pCertContext->cbCertEncoded ) ; + auto prawCert = rawCert.getArray(); + + for( unsigned int i = 0 ; i < m_pCertContext->cbCertEncoded ; i ++ ) + prawCert[i] = *( m_pCertContext->pbCertEncoded + i ) ; + + return rawCert ; + } else { + return Sequence< sal_Int8 >(); + } +} + +//Helper methods +void X509Certificate_MSCryptImpl::setMswcryCert( const CERT_CONTEXT* cert ) { + if( m_pCertContext != nullptr ) { + CertFreeCertificateContext( m_pCertContext ) ; + m_pCertContext = nullptr ; + } + + if( cert != nullptr ) { + m_pCertContext = CertDuplicateCertificateContext( cert ) ; + } +} + +const CERT_CONTEXT* X509Certificate_MSCryptImpl::getMswcryCert() const { + if( m_pCertContext != nullptr ) { + return m_pCertContext ; + } else { + return nullptr ; + } +} + +void X509Certificate_MSCryptImpl::setRawCert( Sequence< sal_Int8 > const & rawCert ) { + if( m_pCertContext != nullptr ) { + CertFreeCertificateContext( m_pCertContext ) ; + m_pCertContext = nullptr ; + } + + if( rawCert.getLength() != 0 ) { + m_pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING, reinterpret_cast<const sal_uInt8*>(&rawCert[0]), rawCert.getLength() ) ; + } +} + +/* XUnoTunnel */ +UNO3_GETIMPLEMENTATION_IMPL(X509Certificate_MSCryptImpl); + +static OUString findOIDDescription(char const *oid) +{ + OUString ouOID = OUString::createFromAscii( oid ); + for (int i=0; i<nOID; i++) + { + OUString item = OUString::createFromAscii( OIDs[i].oid ); + if (ouOID == item) + { + return OUString::createFromAscii( OIDs[i].desc ); + } + } + + return OUString() ; +} + +static css::uno::Sequence< sal_Int8 > getThumbprint(const CERT_CONTEXT* pCertContext, DWORD dwPropId) +{ + if( pCertContext != nullptr ) + { + DWORD cbData = dwPropId == CERT_SHA256_HASH_PROP_ID ? 32 : 20; + unsigned char fingerprint[32]; + if (CertGetCertificateContextProperty(pCertContext, dwPropId, fingerprint, &cbData)) + { + Sequence< sal_Int8 > thumbprint( cbData ) ; + auto pthumbprint = thumbprint.getArray(); + for( unsigned int i = 0 ; i < cbData ; i ++ ) + { + pthumbprint[i] = fingerprint[i]; + } + + return thumbprint; + } + else + { + DWORD e = GetLastError(); + cbData = e; + } + } + + return Sequence< sal_Int8 >(); +} + +OUString SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyAlgorithm() +{ + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) + { + CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm; + return findOIDDescription( algorithm.pszObjId ) ; + } + else + { + return OUString() ; + } +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyValue() +{ + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) + { + CRYPT_BIT_BLOB publicKey = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey; + + Sequence< sal_Int8 > key( publicKey.cbData ) ; + auto keyRange = asNonConstRange(key); + for( unsigned int i = 0 ; i < publicKey.cbData ; i++ ) + { + keyRange[i] = *(publicKey.pbData + i) ; + } + + return key; + } + else + { + return Sequence< sal_Int8 >(); + } +} + +OUString SAL_CALL X509Certificate_MSCryptImpl::getSignatureAlgorithm() +{ + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) + { + CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SignatureAlgorithm; + return findOIDDescription( algorithm.pszObjId ) ; + } + else + { + return OUString() ; + } +} + +uno::Sequence<sal_Int8> X509Certificate_MSCryptImpl::getSHA256Thumbprint() +{ + return getThumbprint(m_pCertContext, CERT_SHA256_HASH_PROP_ID); +} + +svl::crypto::SignatureMethodAlgorithm X509Certificate_MSCryptImpl::getSignatureMethodAlgorithm() +{ + svl::crypto::SignatureMethodAlgorithm nRet = svl::crypto::SignatureMethodAlgorithm::RSA; + + if (!m_pCertContext || !m_pCertContext->pCertInfo) + return nRet; + + CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm; + OString aObjId(algorithm.pszObjId); + if (aObjId == szOID_ECC_PUBLIC_KEY) + nRet = svl::crypto::SignatureMethodAlgorithm::ECDSA; + + return nRet; +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSHA1Thumbprint() +{ + return getThumbprint(m_pCertContext, CERT_SHA1_HASH_PROP_ID); +} + +css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getMD5Thumbprint() +{ + return getThumbprint(m_pCertContext, CERT_MD5_HASH_PROP_ID); +} + +CertificateKind SAL_CALL X509Certificate_MSCryptImpl::getCertificateKind() +{ + return CertificateKind_X509; +} + +sal_Int32 SAL_CALL X509Certificate_MSCryptImpl::getCertificateUsage( ) +{ + sal_Int32 usage = + CERT_DATA_ENCIPHERMENT_KEY_USAGE | + CERT_DIGITAL_SIGNATURE_KEY_USAGE | + CERT_KEY_AGREEMENT_KEY_USAGE | + CERT_KEY_CERT_SIGN_KEY_USAGE | + CERT_KEY_ENCIPHERMENT_KEY_USAGE | + CERT_NON_REPUDIATION_KEY_USAGE | + CERT_OFFLINE_CRL_SIGN_KEY_USAGE; + + if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 ) + { + CERT_EXTENSION* pExtn = CertFindExtension( + szOID_KEY_USAGE, + m_pCertContext->pCertInfo->cExtension, + m_pCertContext->pCertInfo->rgExtension); + + if (pExtn != nullptr) + { + DWORD length = 0; + bool rc = CryptDecodeObject( + X509_ASN_ENCODING, + X509_KEY_USAGE, + pExtn->Value.pbData, + pExtn->Value.cbData, + 0, + nullptr, + &length); + + if (!rc) + SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError())); + else + { + std::vector<char>buffer(length); + + rc = CryptDecodeObject( + X509_ASN_ENCODING, + X509_KEY_USAGE, + pExtn->Value.pbData, + pExtn->Value.cbData, + 0, + buffer.data(), + &length); + + CRYPT_BIT_BLOB *blob = reinterpret_cast<CRYPT_BIT_BLOB*>(buffer.data()); + if (!rc) + SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError())); + else if (blob->cbData == 1) + usage = blob->pbData[0]; + else + SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject(X509_KEY_USAGE) returned unexpected amount of data: " << blob->cbData); + } + } + } + + return usage; +} + +/* XServiceInfo */ +OUString SAL_CALL X509Certificate_MSCryptImpl::getImplementationName() +{ + return "com.sun.star.xml.security.gpg.XCertificate_MsCryptImpl"; +} + +/* XServiceInfo */ +sal_Bool SAL_CALL X509Certificate_MSCryptImpl::supportsService(const OUString& serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +/* XServiceInfo */ +Sequence<OUString> SAL_CALL X509Certificate_MSCryptImpl::getSupportedServiceNames() +{ + return { OUString() }; +} + +namespace xmlsecurity { + +// based on some guesswork and: +// https://datatracker.ietf.org/doc/html/rfc1485 +// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR +// the main problem appears to be that in values NSS uses \ escapes but CryptoAPI requires " quotes around value +static OUString CompatDNNSS(OUString const& rDN) +{ + OUStringBuffer buf(rDN.getLength()); + enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT); + for (sal_Int32 i = 0; i < rDN.getLength(); ++i) + { + if (state == DEFAULT) + { + buf.append(rDN[i]); + if (rDN[i] == '=') + { + if (rDN.getLength() == i+1) + { + break; // invalid? + } + else + { + buf.append('"'); + state = INVALUE; + } + } + } + else if (state == INVALUE) + { + if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';') + { + buf.append('"'); + buf.append(rDN[i]); + state = DEFAULT; + } + else if (rDN[i] == '\\') + { + if (rDN.getLength() == i+1) + { + break; // invalid? + } + if (rDN[i+1] == '"') + { + buf.append('"'); + } + buf.append(rDN[i+1]); + ++i; + } + else + { + buf.append(rDN[i]); + } + if (i+1 == rDN.getLength()) + { + buf.append('"'); + state = DEFAULT; + } + } + } + return buf.makeStringAndClear(); +} + +static bool EncodeDistinguishedName(std::u16string_view const rName, CERT_NAME_BLOB & rBlob) +{ + LPCWSTR pszError; + if (!CertStrToNameW(X509_ASN_ENCODING, + reinterpret_cast<LPCWSTR>(rName.data()), CERT_X500_NAME_STR, + nullptr, nullptr, &rBlob.cbData, &pszError)) + { + SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError))); + return false; + } + rBlob.pbData = new BYTE[rBlob.cbData]; + if (!CertStrToNameW(X509_ASN_ENCODING, + reinterpret_cast<LPCWSTR>(rName.data()), CERT_X500_NAME_STR, + nullptr, rBlob.pbData, &rBlob.cbData, &pszError)) + { + SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError))); + return false; + } + return true; +} + +bool EqualDistinguishedNames( + std::u16string_view const rName1, std::u16string_view const rName2, + EqualMode const eMode) +{ + if (eMode == COMPAT_BOTH && !rName1.empty() && rName1 == rName2) + { // handle case where both need to be converted + return true; + } + CERT_NAME_BLOB blob1; + if (!EncodeDistinguishedName(rName1, blob1)) + { + return false; + } + CERT_NAME_BLOB blob2; + bool ret(false); + if (EncodeDistinguishedName(rName2, blob2)) + { + ret = CertCompareCertificateName(X509_ASN_ENCODING, + &blob1, &blob2) == TRUE; + delete[] blob2.pbData; + } + if (!ret && eMode == COMPAT_2ND) + { + CERT_NAME_BLOB blob2compat; + if (!EncodeDistinguishedName(CompatDNNSS(OUString(rName2)), blob2compat)) + { + delete[] blob1.pbData; + return false; + } + ret = CertCompareCertificateName(X509_ASN_ENCODING, + &blob1, &blob2compat) == TRUE; + delete[] blob2compat.pbData; + } + delete[] blob1.pbData; + return ret; +} + +} // namespace xmlsecurity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx new file mode 100644 index 000000000..9bd6a34ce --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <Windows.h> +#include <WinCrypt.h> +#include <sal/config.h> +#include <rtl/ustring.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/servicehelper.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/SecurityException.hpp> +#include <com/sun/star/security/CertificateKind.hpp> +#include <com/sun/star/security/XCertificate.hpp> +#include <certificate.hxx> + +class X509Certificate_MSCryptImpl : public ::cppu::WeakImplHelper< + css::security::XCertificate , + css::lang::XUnoTunnel, + css::lang::XServiceInfo > , public xmlsecurity::Certificate +{ + private: + const CERT_CONTEXT* m_pCertContext ; + + public: + X509Certificate_MSCryptImpl() ; + virtual ~X509Certificate_MSCryptImpl() override; + + //Methods from XCertificate + virtual sal_Int16 SAL_CALL getVersion() override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSerialNumber() override; + virtual OUString SAL_CALL getIssuerName() override; + virtual OUString SAL_CALL getSubjectName() override; + virtual css::util::DateTime SAL_CALL getNotValidBefore() override; + virtual css::util::DateTime SAL_CALL getNotValidAfter() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getIssuerUniqueID() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectUniqueID() override; + virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL getExtensions() override; + virtual css::uno::Reference< css::security::XCertificateExtension > SAL_CALL findCertificateExtension( const css::uno::Sequence< sal_Int8 >& oid ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getEncoded() override; + virtual OUString SAL_CALL getSubjectPublicKeyAlgorithm() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectPublicKeyValue() override; + virtual OUString SAL_CALL getSignatureAlgorithm() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSHA1Thumbprint() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getMD5Thumbprint() override; + virtual css::security::CertificateKind SAL_CALL getCertificateKind() override; + + + virtual sal_Int32 SAL_CALL getCertificateUsage( ) override; + + //Methods from XUnoTunnel + UNO3_GETIMPLEMENTATION_DECL(X509Certificate_MSCryptImpl) + + /// @see xmlsecurity::Certificate::getSHA256Thumbprint(). + virtual css::uno::Sequence<sal_Int8> getSHA256Thumbprint() override; + + /// @see xmlsecurity::Certificate::getSignatureMethodAlgorithm(). + virtual svl::crypto::SignatureMethodAlgorithm getSignatureMethodAlgorithm() override; + + //Helper methods + void setMswcryCert( const CERT_CONTEXT* cert ) ; + const CERT_CONTEXT* getMswcryCert() const ; + /// @throws css::uno::RuntimeException + void setRawCert( css::uno::Sequence< sal_Int8 > const & rawCert ) ; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +} ; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx new file mode 100644 index 000000000..7d71d4863 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsecuritycontext_mscryptimpl.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <xmlsec-wrapper.h> + +#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> +#include "securityenvironment_mscryptimpl.hxx" + +#include <xmlsec/xmlstreamio.hxx> +#include "akmngr.hxx" + +#include <cppuhelper/supportsservice.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang ; +using ::com::sun::star::lang::XMultiServiceFactory ; +using ::com::sun::star::lang::XSingleServiceFactory ; + +using ::com::sun::star::xml::crypto::XSecurityEnvironment ; +using ::com::sun::star::xml::crypto::XXMLSecurityContext ; + +namespace { + +class XMLSecurityContext_MSCryptImpl : public ::cppu::WeakImplHelper< + css::xml::crypto::XXMLSecurityContext , + css::lang::XServiceInfo > +{ + private: + //xmlSecKeysMngrPtr m_pKeysMngr ; + css::uno::Reference< css::xml::crypto::XSecurityEnvironment > m_xSecurityEnvironment ; + + public: + XMLSecurityContext_MSCryptImpl(); + + //Methods from XXMLSecurityContext + virtual sal_Int32 SAL_CALL addSecurityEnvironment( + const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aSecurityEnvironment + ) override; + + virtual ::sal_Int32 SAL_CALL getSecurityEnvironmentNumber( ) override; + + virtual css::uno::Reference< + css::xml::crypto::XSecurityEnvironment > SAL_CALL + getSecurityEnvironmentByIndex( ::sal_Int32 index ) override; + + virtual css::uno::Reference< + css::xml::crypto::XSecurityEnvironment > SAL_CALL + getSecurityEnvironment( ) override; + + virtual ::sal_Int32 SAL_CALL getDefaultSecurityEnvironmentIndex( ) override; + + virtual void SAL_CALL setDefaultSecurityEnvironmentIndex( sal_Int32 nDefaultEnvIndex ) override; + + + //Methods from XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService( + const OUString& ServiceName + ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +XMLSecurityContext_MSCryptImpl::XMLSecurityContext_MSCryptImpl() +{ +} + +sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::addSecurityEnvironment( + const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aSecurityEnvironment) +{ + if( !aSecurityEnvironment.is() ) + { + throw uno::RuntimeException() ; + } + + m_xSecurityEnvironment = aSecurityEnvironment; + + return 0; +} + + +sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::getSecurityEnvironmentNumber( ) +{ + return 1; +} + +css::uno::Reference< css::xml::crypto::XSecurityEnvironment > SAL_CALL + XMLSecurityContext_MSCryptImpl::getSecurityEnvironmentByIndex( sal_Int32 index ) +{ + if (index != 0) + { + throw uno::RuntimeException() ; + } + return m_xSecurityEnvironment; +} + +css::uno::Reference< css::xml::crypto::XSecurityEnvironment > SAL_CALL + XMLSecurityContext_MSCryptImpl::getSecurityEnvironment( ) +{ + return m_xSecurityEnvironment; +} + +sal_Int32 SAL_CALL XMLSecurityContext_MSCryptImpl::getDefaultSecurityEnvironmentIndex( ) +{ + return 0; +} + +void SAL_CALL XMLSecurityContext_MSCryptImpl::setDefaultSecurityEnvironmentIndex( sal_Int32 /*nDefaultEnvIndex*/ ) +{ + //dummy +} + +/* XServiceInfo */ +OUString SAL_CALL XMLSecurityContext_MSCryptImpl::getImplementationName() { + return "com.sun.star.xml.crypto.XMLSecurityContext" ; +} + +/* XServiceInfo */ +sal_Bool SAL_CALL XMLSecurityContext_MSCryptImpl::supportsService( const OUString& serviceName) { + return cppu::supportsService(this, serviceName); +} + +/* XServiceInfo */ +uno::Sequence< OUString > SAL_CALL XMLSecurityContext_MSCryptImpl::getSupportedServiceNames() { + return { "com.sun.star.xml.crypto.XMLSecurityContext" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_xml_crypto_XMLSecurityContext_get_implementation( + uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new XMLSecurityContext_MSCryptImpl); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx new file mode 100644 index 000000000..87af0f040 --- /dev/null +++ b/xmlsecurity/source/xmlsec/mscrypt/xmlsignature_mscryptimpl.cxx @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> +#include <rtl/uuid.h> +#include <xmlsec-wrapper.h> + +#include <xmlsec/mscng/x509.h> + +#include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp> +#include <com/sun/star/xml/crypto/XXMLSignature.hpp> + +#include "securityenvironment_mscryptimpl.hxx" + +#include <xmlsec/xmldocumentwrapper_xmlsecimpl.hxx> +#include <xmlelementwrapper_xmlsecimpl.hxx> +#include <xmlsec/xmlstreamio.hxx> +#include <xmlsec/errorcallback.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::lang ; +using ::com::sun::star::lang::XMultiServiceFactory ; +using ::com::sun::star::lang::XSingleServiceFactory ; + +using ::com::sun::star::xml::wrapper::XXMLElementWrapper ; +using ::com::sun::star::xml::wrapper::XXMLDocumentWrapper ; +using ::com::sun::star::xml::crypto::XSecurityEnvironment ; +using ::com::sun::star::xml::crypto::XXMLSignature ; +using ::com::sun::star::xml::crypto::XXMLSignatureTemplate ; +using ::com::sun::star::xml::crypto::XXMLSecurityContext ; +using ::com::sun::star::xml::crypto::XUriBinding ; + +namespace { + +class XMLSignature_MSCryptImpl : public ::cppu::WeakImplHelper< + css::xml::crypto::XXMLSignature , + css::lang::XServiceInfo > +{ + public: + explicit XMLSignature_MSCryptImpl(); + + //Methods from XXMLSignature + virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL generate( + const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate , + const css::uno::Reference< css::xml::crypto::XSecurityEnvironment >& aEnvironment + ) override; + + virtual css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate > SAL_CALL validate( + const css::uno::Reference< css::xml::crypto::XXMLSignatureTemplate >& aTemplate , + const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& aContext + ) override; + + //Methods from XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService( + const OUString& ServiceName + ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +} ; + +} + +XMLSignature_MSCryptImpl::XMLSignature_MSCryptImpl() { +} + +/* XXMLSignature */ +Reference< XXMLSignatureTemplate > +SAL_CALL XMLSignature_MSCryptImpl::generate( + const Reference< XXMLSignatureTemplate >& aTemplate , + const Reference< XSecurityEnvironment >& aEnvironment +) +{ + xmlSecKeysMngrPtr pMngr = nullptr ; + xmlSecDSigCtxPtr pDsigCtx = nullptr ; + xmlNodePtr pNode = nullptr ; + + if( !aTemplate.is() ) + throw RuntimeException() ; + + if( !aEnvironment.is() ) + throw RuntimeException() ; + + //Get Keys Manager + Reference< XUnoTunnel > xSecTunnel( aEnvironment , UNO_QUERY_THROW ) ; + SecurityEnvironment_MSCryptImpl* pSecEnv = comphelper::getFromUnoTunnel<SecurityEnvironment_MSCryptImpl>(xSecTunnel); + if( pSecEnv == nullptr ) + throw RuntimeException() ; + + //Get the xml node + Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ; + if( !xElement.is() ) { + throw RuntimeException() ; + } + + Reference< XUnoTunnel > xNodTunnel( xElement , UNO_QUERY_THROW ) ; + XMLElementWrapper_XmlSecImpl* pElement = comphelper::getFromUnoTunnel<XMLElementWrapper_XmlSecImpl>(xNodTunnel); + if( pElement == nullptr ) { + throw RuntimeException() ; + } + + pNode = pElement->getNativeElement() ; + + //Get the stream/URI binding + Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ; + if( xUriBinding.is() ) { + //Register the stream input callbacks into libxml2 + if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 ) + throw RuntimeException() ; + } + + setErrorRecorder( ); + + pMngr = pSecEnv->createKeysManager(); + if( !pMngr ) { + throw RuntimeException() ; + } + + //Create Signature context + pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ; + if( pDsigCtx == nullptr ) + { + //throw XMLSignatureException() ; + SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr ); + clearErrorRecorder(); + return aTemplate; + } + + //Sign the template + if( xmlSecDSigCtxSign( pDsigCtx , pNode ) == 0 ) + { + if (pDsigCtx->status == xmlSecDSigStatusSucceeded) + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED); + else + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN); + } + else + { + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN); + } + + + xmlSecDSigCtxDestroy( pDsigCtx ) ; + SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr ); + + //Unregistered the stream/URI binding + if( xUriBinding.is() ) + xmlUnregisterStreamInputCallbacks() ; + + clearErrorRecorder(); + return aTemplate ; +} + +/* XXMLSignature */ +Reference< XXMLSignatureTemplate > +SAL_CALL XMLSignature_MSCryptImpl::validate( + const Reference< XXMLSignatureTemplate >& aTemplate , + const Reference< XXMLSecurityContext >& aSecurityCtx +) { + xmlSecKeysMngrPtr pMngr = nullptr ; + xmlSecDSigCtxPtr pDsigCtx = nullptr ; + xmlNodePtr pNode = nullptr ; + + if( !aTemplate.is() ) + throw RuntimeException() ; + + if( !aSecurityCtx.is() ) + throw RuntimeException() ; + + //Get Keys Manager + Reference< XSecurityEnvironment > xSecEnv + = aSecurityCtx->getSecurityEnvironmentByIndex( + aSecurityCtx->getDefaultSecurityEnvironmentIndex()); + Reference< XUnoTunnel > xSecTunnel( xSecEnv , UNO_QUERY_THROW ) ; + SecurityEnvironment_MSCryptImpl* pSecEnv = comphelper::getFromUnoTunnel<SecurityEnvironment_MSCryptImpl>(xSecTunnel); + if( pSecEnv == nullptr ) + throw RuntimeException() ; + + //Get the xml node + Reference< XXMLElementWrapper > xElement = aTemplate->getTemplate() ; + if( !xElement.is() ) + throw RuntimeException() ; + + Reference< XUnoTunnel > xNodTunnel( xElement , UNO_QUERY_THROW ) ; + XMLElementWrapper_XmlSecImpl* pElement = comphelper::getFromUnoTunnel<XMLElementWrapper_XmlSecImpl>(xNodTunnel); + if( pElement == nullptr ) + throw RuntimeException() ; + + pNode = pElement->getNativeElement() ; + + //Get the stream/URI binding + Reference< XUriBinding > xUriBinding = aTemplate->getBinding() ; + if( xUriBinding.is() ) { + //Register the stream input callbacks into libxml2 + if( xmlRegisterStreamInputCallbacks( xUriBinding ) < 0 ) + throw RuntimeException() ; + } + + setErrorRecorder( ); + + pMngr = pSecEnv->createKeysManager(); + if( !pMngr ) { + throw RuntimeException() ; + } + + //Create Signature context + pDsigCtx = xmlSecDSigCtxCreate( pMngr ) ; + if( pDsigCtx == nullptr ) + { + SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr ); + clearErrorRecorder(); + return aTemplate; + } + + // We do certificate verification ourselves. + pDsigCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS; + + // limit possible key data to valid X509 certificates only, no KeyValues + if (xmlSecPtrListAdd(&(pDsigCtx->keyInfoReadCtx.enabledKeyData), BAD_CAST xmlSecMSCngKeyDataX509GetKlass()) < 0) + throw RuntimeException("failed to limit allowed key data"); + + //Verify signature + //The documentation says that the signature is only valid if the return value is 0 (that is, not < 0) + //AND pDsigCtx->status == xmlSecDSigStatusSucceeded. That is, we must not make any assumptions, if + //the return value is < 0. Then we must regard the signature as INVALID. We cannot use the + //error recorder feature to get the ONE error that made the verification fail, because there is no + //documentation/specification as to how to interpret the number of recorded errors and what is the initial + //error. + int rs = xmlSecDSigCtxVerify(pDsigCtx , pNode); + + // Also verify manifest: this is empty for ODF, but contains everything (except signature metadata) for OOXML. + xmlSecSize nReferenceCount = xmlSecPtrListGetSize(&pDsigCtx->manifestReferences); + // Require that all manifest references are also good. + xmlSecSize nReferenceGood = 0; + for (xmlSecSize nReference = 0; nReference < nReferenceCount; ++nReference) + { + xmlSecDSigReferenceCtxPtr pReference = static_cast<xmlSecDSigReferenceCtxPtr>(xmlSecPtrListGetItem(&pDsigCtx->manifestReferences, nReference)); + if (pReference) + { + if (pReference->status == xmlSecDSigStatusSucceeded) + ++nReferenceGood; + } + } + SAL_INFO("xmlsecurity.xmlsec", "xmlSecDSigCtxVerify status " << pDsigCtx->status << ", references good " << nReferenceGood << " of " << nReferenceCount); + + if (rs == 0 && nReferenceCount == nReferenceGood) + { + if (pDsigCtx->status == xmlSecDSigStatusSucceeded) + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED); + else + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN); + } + else + { + aTemplate->setStatus(css::xml::crypto::SecurityOperationStatus_UNKNOWN); + } + + xmlSecDSigCtxDestroy( pDsigCtx ) ; + SecurityEnvironment_MSCryptImpl::destroyKeysManager( pMngr ); + + //Unregistered the stream/URI binding + if( xUriBinding.is() ) + xmlUnregisterStreamInputCallbacks() ; + + + clearErrorRecorder(); + return aTemplate; +} + +/* XServiceInfo */ +OUString SAL_CALL XMLSignature_MSCryptImpl::getImplementationName() { + return "com.sun.star.xml.crypto.XMLSignature"; +} + +/* XServiceInfo */ +sal_Bool SAL_CALL XMLSignature_MSCryptImpl::supportsService( const OUString& serviceName) { +return cppu::supportsService(this, serviceName); +} + +/* XServiceInfo */ +Sequence< OUString > SAL_CALL XMLSignature_MSCryptImpl::getSupportedServiceNames() { + return { "com.sun.star.xml.crypto.XMLSignature" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_xml_crypto_XMLSignature_get_implementation(uno::XComponentContext* /*pCtx*/, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new XMLSignature_MSCryptImpl); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |