1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <cstddef>
23 #include <string.h>
24 
25 #if !defined WIN32_LEAN_AND_MEAN
26 # define WIN32_LEAN_AND_MEAN
27 #endif
28 #include <Windows.h>
29 #include <WinCrypt.h>
30 #include <sal/macros.h>
31 #include <osl/thread.h>
32 #include "securityenvironment_mscryptimpl.hxx"
33 
34 #include "x509certificate_mscryptimpl.hxx"
35 #include <comphelper/servicehelper.hxx>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 
38 #include <xmlsec-wrapper.h>
39 #include "akmngr.hxx"
40 
41 #include <biginteger.hxx>
42 
43 #include <comphelper/windowserrorstring.hxx>
44 #include <sal/log.hxx>
45 #include <rtl/locale.h>
46 #include <osl/nlsupport.h>
47 #include <osl/process.h>
48 #include <o3tl/char16_t2wchar_t.hxx>
49 #include <svl/cryptosign.hxx>
50 
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::lang ;
53 using ::com::sun::star::lang::XMultiServiceFactory ;
54 using ::com::sun::star::lang::XSingleServiceFactory ;
55 
56 using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
57 using ::com::sun::star::security::XCertificate ;
58 
59 static X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert ) ;
60 
61 struct CertErrorToString{
62     DWORD error;
63     char const * name;
64 };
65 
66 CertErrorToString const arErrStrings[] =
67 {
68     { 0x00000000, "CERT_TRUST_NO_ERROR"},
69     { 0x00000001, "CERT_TRUST_IS_NOT_TIME_VALID"},
70     { 0x00000002, "CERT_TRUST_IS_NOT_TIME_NESTED"},
71     { 0x00000004, "CERT_TRUST_IS_REVOKED" },
72     { 0x00000008, "CERT_TRUST_IS_NOT_SIGNATURE_VALID" },
73     { 0x00000010, "CERT_TRUST_IS_NOT_SIGNATURE_VALID"},
74     { 0x00000020, "CERT_TRUST_IS_UNTRUSTED_ROOT"},
75     { 0x00000040, "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"},
76     { 0x00000080, "CERT_TRUST_IS_CYCLIC"},
77     { 0x00000100, "CERT_TRUST_INVALID_EXTENSION"},
78     { 0x00000200, "CERT_TRUST_INVALID_POLICY_CONSTRAINTS"},
79     { 0x00000400, "CERT_TRUST_INVALID_BASIC_CONSTRAINTS"},
80     { 0x00000800, "CERT_TRUST_INVALID_NAME_CONSTRAINTS"},
81     { 0x00001000, "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT"},
82     { 0x00002000, "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT"},
83     { 0x00004000, "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT"},
84     { 0x00008000, "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT"},
85     { 0x01000000, "CERT_TRUST_IS_OFFLINE_REVOCATION"},
86     { 0x02000000, "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY"},
87     { 0x04000000, "CERT_TRUST_IS_EXPLICIT_DISTRUST"},
88     { 0x08000000, "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT"},
89     //Chain errors
90     { 0x00010000, "CERT_TRUST_IS_PARTIAL_CHAIN"},
91     { 0x00020000, "CERT_TRUST_CTL_IS_NOT_TIME_VALID"},
92     { 0x00040000, "CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID"},
93     { 0x00080000, "CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE"}
94 };
95 
traceTrustStatus(DWORD err)96 static void traceTrustStatus(DWORD err)
97 {
98     if (err == 0)
99         SAL_INFO("xmlsecurity.xmlsec", "  " << arErrStrings[0].name);
100     for (std::size_t i = 1; i < SAL_N_ELEMENTS(arErrStrings); i++)
101     {
102         if (arErrStrings[i].error & err)
103             SAL_INFO("xmlsecurity.xmlsec", "  " << arErrStrings[i].name);
104     }
105 }
106 
SecurityEnvironment_MSCryptImpl(const uno::Reference<uno::XComponentContext> & xContext)107 SecurityEnvironment_MSCryptImpl::SecurityEnvironment_MSCryptImpl( const uno::Reference< uno::XComponentContext >& xContext ) : m_hProv( NULL ) , m_pszContainer( nullptr ) , m_hKeyStore( nullptr ), m_hCertStore( nullptr ), m_hMySystemStore(nullptr), m_hRootSystemStore(nullptr), m_hTrustSystemStore(nullptr), m_hCaSystemStore(nullptr), m_bEnableDefault( false ){
108 
109     m_xServiceManager.set(xContext, uno::UNO_QUERY);
110 }
111 
~SecurityEnvironment_MSCryptImpl()112 SecurityEnvironment_MSCryptImpl::~SecurityEnvironment_MSCryptImpl() {
113 
114     if( m_hProv != NULL ) {
115         CryptReleaseContext( m_hProv, 0 ) ;
116         m_hProv = NULL ;
117     }
118 
119     if( m_pszContainer != nullptr ) {
120         //TODO: Don't know whether or not it should be released now.
121         m_pszContainer = nullptr ;
122     }
123 
124     if( m_hCertStore != nullptr ) {
125         CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
126         m_hCertStore = nullptr ;
127     }
128 
129     if( m_hKeyStore != nullptr ) {
130         CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
131         m_hKeyStore = nullptr ;
132     }
133 
134     //i120675, close the store handles
135     if( m_hMySystemStore != nullptr ) {
136         CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
137         m_hMySystemStore = nullptr ;
138     }
139 
140     if( m_hRootSystemStore != nullptr ) {
141         CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
142         m_hRootSystemStore = nullptr ;
143     }
144 
145     if( m_hTrustSystemStore != nullptr ) {
146         CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
147         m_hTrustSystemStore = nullptr ;
148     }
149 
150     if( m_hCaSystemStore != nullptr ) {
151         CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
152         m_hCaSystemStore = nullptr ;
153     }
154 }
155 
156 /* XServiceInfo */
getImplementationName()157 OUString SAL_CALL SecurityEnvironment_MSCryptImpl::getImplementationName() {
158     return "com.sun.star.xml.crypto.SecurityEnvironment";
159 }
160 
161 /* XServiceInfo */
supportsService(const OUString & serviceName)162 sal_Bool SAL_CALL SecurityEnvironment_MSCryptImpl::supportsService( const OUString& serviceName) {
163     uno::Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
164     const OUString* pArray = seqServiceNames.getConstArray() ;
165     for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
166         if( *( pArray + i ) == serviceName )
167             return true ;
168     }
169     return false ;
170 }
171 
172 /* XServiceInfo */
getSupportedServiceNames()173 uno::Sequence< OUString > SAL_CALL SecurityEnvironment_MSCryptImpl::getSupportedServiceNames() {
174     uno::Sequence<OUString> seqServiceNames { "com.sun.star.xml.crypto.SecurityEnvironment" };
175     return seqServiceNames ;
176 }
177 
178 /* XUnoTunnel */
179 UNO3_GETIMPLEMENTATION_IMPL(SecurityEnvironment_MSCryptImpl);
180 
getCryptoProvider()181 HCRYPTPROV SecurityEnvironment_MSCryptImpl::getCryptoProvider() {
182     return m_hProv ;
183 }
184 
setCryptoProvider(HCRYPTPROV aProv)185 void SecurityEnvironment_MSCryptImpl::setCryptoProvider( HCRYPTPROV aProv ) {
186     if( m_hProv != NULL ) {
187         CryptReleaseContext( m_hProv, 0 ) ;
188         m_hProv = NULL ;
189     }
190 
191     if( aProv != NULL ) {
192         m_hProv = aProv ;
193     }
194 }
195 
getKeyContainer()196 LPCTSTR SecurityEnvironment_MSCryptImpl::getKeyContainer() {
197     return m_pszContainer ;
198 }
199 
setKeyContainer(LPCTSTR aKeyContainer)200 void SecurityEnvironment_MSCryptImpl::setKeyContainer( LPCTSTR aKeyContainer ) {
201     //TODO: Don't know whether or not it should be copied.
202     m_pszContainer = aKeyContainer ;
203 }
204 
205 
getCryptoSlot()206 HCERTSTORE SecurityEnvironment_MSCryptImpl::getCryptoSlot() {
207     return m_hKeyStore ;
208 }
209 
setCryptoSlot(HCERTSTORE aSlot)210 void SecurityEnvironment_MSCryptImpl::setCryptoSlot( HCERTSTORE aSlot) {
211     if( m_hKeyStore != nullptr ) {
212         CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
213         m_hKeyStore = nullptr ;
214     }
215 
216     if( aSlot != nullptr ) {
217         m_hKeyStore = CertDuplicateStore( aSlot ) ;
218     }
219 }
220 
getCertDb()221 HCERTSTORE SecurityEnvironment_MSCryptImpl::getCertDb() {
222     return m_hCertStore ;
223 }
224 
setCertDb(HCERTSTORE aCertDb)225 void SecurityEnvironment_MSCryptImpl::setCertDb( HCERTSTORE aCertDb ) {
226     if( m_hCertStore != nullptr ) {
227         CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
228         m_hCertStore = nullptr ;
229     }
230 
231     if( aCertDb != nullptr ) {
232         m_hCertStore = CertDuplicateStore( aCertDb ) ;
233     }
234 }
235 
236 #ifdef SAL_LOG_INFO
237 
238 // Based on sample code from MSDN
239 
get_system_name(const void * pvSystemStore,DWORD dwFlags)240 static OUString get_system_name(const void *pvSystemStore,
241                             DWORD dwFlags)
242 {
243     LPCWSTR ppwszSystemName;
244     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
245     {
246         _CERT_SYSTEM_STORE_RELOCATE_PARA const * pRelocatePara;
247         pRelocatePara = static_cast<_CERT_SYSTEM_STORE_RELOCATE_PARA const *>(pvSystemStore);
248         ppwszSystemName = pRelocatePara->pwszSystemStore;
249     }
250     else
251     {
252         ppwszSystemName = static_cast<LPCWSTR>(pvSystemStore);
253     }
254     return o3tl::toU(ppwszSystemName);
255 }
256 
257 extern "C" {
258 
cert_enum_physical_store_callback(const void *,DWORD dwFlags,LPCWSTR pwszStoreName,PCERT_PHYSICAL_STORE_INFO,void *,void *)259 static BOOL WINAPI cert_enum_physical_store_callback(const void *,
260                                                          DWORD dwFlags,
261                                                          LPCWSTR pwszStoreName,
262                                                          PCERT_PHYSICAL_STORE_INFO,
263                                                          void *,
264                                                          void *)
265 {
266     OUString name(o3tl::toU(pwszStoreName));
267     if (dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG)
268         name += " (implicitly created)";
269     SAL_INFO("xmlsecurity.xmlsec", "  Physical store: " << name);
270 
271     return TRUE;
272 }
273 
cert_enum_system_store_callback(const void * pvSystemStore,DWORD dwFlags,PCERT_SYSTEM_STORE_INFO,void *,void *)274 static BOOL WINAPI cert_enum_system_store_callback(const void *pvSystemStore,
275                                                        DWORD dwFlags,
276                                                        PCERT_SYSTEM_STORE_INFO,
277                                                        void *,
278                                                        void *)
279 {
280     SAL_INFO("xmlsecurity.xmlsec", "System store: " << get_system_name(pvSystemStore, dwFlags));
281 
282     if (!CertEnumPhysicalStore(pvSystemStore,
283                                dwFlags,
284                                nullptr,
285                                cert_enum_physical_store_callback))
286     {
287         DWORD dwErr = GetLastError();
288         if (!(ERROR_FILE_NOT_FOUND == dwErr ||
289               ERROR_NOT_SUPPORTED == dwErr))
290         {
291             SAL_WARN("xmlsecurity.xmlsec", "CertEnumPhysicalStore failed:" << WindowsErrorString(GetLastError()));
292         }
293     }
294     return TRUE;
295 }
296 
297 }
298 
299 #endif
300 
301 //Methods from XSecurityEnvironment
getPersonalCertificates()302 uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::getPersonalCertificates()
303 {
304     sal_Int32 length ;
305     X509Certificate_MSCryptImpl* xcert ;
306     std::vector< X509Certificate_MSCryptImpl* > certsList ;
307     PCCERT_CONTEXT pCertContext = nullptr;
308 
309     //firstly, we try to find private keys in given key store.
310     if( m_hKeyStore != nullptr ) {
311         pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
312         while (pCertContext)
313         {
314             xcert = MswcryCertContextToXCert( pCertContext ) ;
315             if( xcert != nullptr )
316                 certsList.push_back( xcert ) ;
317             pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
318         }
319     }
320 
321     //Thirdly, we try to find certificate from system default key store.
322     if( m_bEnableDefault ) {
323         HCERTSTORE hSystemKeyStore ;
324         DWORD      dwKeySpec;
325         NCRYPT_KEY_HANDLE hCryptKey;
326 
327 #ifdef SAL_LOG_INFO
328         CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, nullptr, nullptr, cert_enum_system_store_callback);
329 #endif
330 
331         hSystemKeyStore = CertOpenSystemStoreW( 0, L"MY" ) ;
332         if( hSystemKeyStore != nullptr ) {
333             pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
334             while (pCertContext)
335             {
336                 // for checking whether the certificate is a personal certificate or not.
337                 DWORD dwFlags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
338                 HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey;
339                 if(!(CryptAcquireCertificatePrivateKey(pCertContext,
340                         dwFlags,
341                         nullptr,
342                         phCryptProvOrNCryptKey,
343                         &dwKeySpec,
344                         nullptr)))
345                 {
346                     // Not Privatekey found. SKIP this one.
347                     pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
348                     continue;
349                 }
350                 // then TODO : Check the personal cert is valid or not.
351 
352                 xcert = MswcryCertContextToXCert( pCertContext ) ;
353                 if( xcert != nullptr )
354                     certsList.push_back( xcert ) ;
355                 pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
356             }
357         }
358 
359         CertCloseStore( hSystemKeyStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
360     }
361 
362     length = certsList.size() ;
363     if( length != 0 ) {
364         int i = 0;
365         uno::Sequence< uno::Reference< XCertificate > > certSeq( length ) ;
366 
367         for( const auto& rXCert : certsList ) {
368             certSeq[i] = rXCert ;
369             ++i;
370         }
371 
372         return certSeq ;
373     }
374 
375     return uno::Sequence< uno::Reference< XCertificate > >() ;
376 }
377 
378 
getCertificate(const OUString & issuerName,const uno::Sequence<sal_Int8> & serialNumber)379 uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const uno::Sequence< sal_Int8 >& serialNumber ) {
380     unsigned int i ;
381     X509Certificate_MSCryptImpl *xcert = nullptr ;
382     PCCERT_CONTEXT pCertContext = nullptr ;
383     HCERTSTORE hCertStore = nullptr ;
384     CRYPT_INTEGER_BLOB cryptSerialNumber ;
385     CERT_INFO certInfo ;
386 
387     // for correct encoding
388     sal_uInt16 encoding ;
389     rtl_Locale *pLocale = nullptr ;
390     osl_getProcessLocale( &pLocale ) ;
391     encoding = osl_getTextEncodingFromLocale( pLocale ) ;
392 
393     //Create cert info from issue and serial
394     LPCWSTR pszName = o3tl::toW( issuerName.getStr() );
395 
396     if( ! ( CertStrToNameW(
397         X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
398         pszName ,
399         CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
400         nullptr ,
401         nullptr ,
402         &certInfo.Issuer.cbData, nullptr ) )
403     ) {
404         return nullptr ;
405     }
406 
407     certInfo.Issuer.pbData = static_cast<BYTE*>(malloc( certInfo.Issuer.cbData ));
408     if(!certInfo.Issuer.pbData)
409         throw uno::RuntimeException() ;
410 
411     if( ! ( CertStrToNameW(
412         X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
413         pszName ,
414         CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
415         nullptr ,
416         certInfo.Issuer.pbData ,
417         &certInfo.Issuer.cbData, nullptr ) )
418     ) {
419         free( certInfo.Issuer.pbData ) ;
420         return nullptr ;
421     }
422 
423     //Get the SerialNumber
424     cryptSerialNumber.cbData = serialNumber.getLength() ;
425     cryptSerialNumber.pbData = static_cast<BYTE*>(malloc( cryptSerialNumber.cbData));
426     if (!cryptSerialNumber.pbData)
427     {
428         free( certInfo.Issuer.pbData ) ;
429         throw uno::RuntimeException() ;
430     }
431     for( i = 0; i < cryptSerialNumber.cbData; i ++ )
432         cryptSerialNumber.pbData[i] = serialNumber[ cryptSerialNumber.cbData - i - 1 ] ;
433 
434     certInfo.SerialNumber.cbData = cryptSerialNumber.cbData ;
435     certInfo.SerialNumber.pbData = cryptSerialNumber.pbData ;
436 
437     // Get the Cert from all store.
438     for( i = 0 ; i < 6 ; i ++ )
439     {
440         switch(i)
441         {
442         case 0:
443             if(m_hKeyStore == nullptr) continue ;
444             hCertStore = m_hKeyStore ;
445             break;
446         case 1:
447             if(m_hCertStore == nullptr) continue ;
448             hCertStore = m_hCertStore ;
449             break;
450         case 2:
451             hCertStore = CertOpenSystemStoreW( 0, L"MY" ) ;
452             if(hCertStore == nullptr || !m_bEnableDefault) continue ;
453             break;
454         case 3:
455             hCertStore = CertOpenSystemStoreW( 0, L"Root" ) ;
456             if(hCertStore == nullptr || !m_bEnableDefault) continue ;
457             break;
458         case 4:
459             hCertStore = CertOpenSystemStoreW( 0, L"Trust" ) ;
460             if(hCertStore == nullptr || !m_bEnableDefault) continue ;
461             break;
462         case 5:
463             hCertStore = CertOpenSystemStoreW( 0, L"CA" ) ;
464             if(hCertStore == nullptr || !m_bEnableDefault) continue ;
465             break;
466         default:
467             i=6;
468             continue;
469         }
470 
471 /*******************************************************************************
472  * This code reserved for remind us there are another way to find one cert by
473  * IssuerName&serialnumber. You can use the code to replaced the function
474  * CertFindCertificateInStore IF and ONLY IF you must find one special cert in
475  * certStore but can not be found by CertFindCertificateInStore , then , you
476  * should also change the same part in libxmlsec/.../src/mscrypto/x509vfy.c#875.
477  * By Chandler Peng(chandler.peng@sun.com)
478  *****/
479 /*******************************************************************************
480         pCertContext = NULL ;
481         found = 0;
482         do{
483             //  1. enum the certs has same string in the issuer string.
484             pCertContext = CertEnumCertificatesInStore( hCertStore , pCertContext ) ;
485             if( pCertContext != NULL )
486             {
487                 // 2. check the cert's issuer name .
488                 char* issuer = NULL ;
489                 DWORD cbIssuer = 0 ;
490 
491                 cbIssuer = CertNameToStr(
492                     X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
493                     &( pCertContext->pCertInfo->Issuer ),
494                     CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
495                     NULL, 0
496                 ) ;
497 
498                 if( cbIssuer == 0 ) continue ; // discard this cert;
499 
500                 issuer = (char *)malloc( cbIssuer ) ;
501                 if( issuer == NULL )  // discard this cert;
502                 {
503                     free( cryptSerialNumber.pbData) ;
504                     free( certInfo.Issuer.pbData ) ;
505                     CertFreeCertificateContext( pCertContext ) ;
506                     if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
507                     throw RuntimeException() ;
508                 }
509 
510                 cbIssuer = CertNameToStr(
511                     X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
512                     &( pCertContext->pCertInfo->Issuer ),
513                     CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
514                     issuer, cbIssuer
515                 ) ;
516 
517                 if( cbIssuer <= 0 )
518                 {
519                     free( issuer ) ;
520                     continue ;// discard this cert;
521                 }
522 
523                 if(strncmp(pszName , issuer , cbIssuer) != 0)
524                 {
525                     free( issuer ) ;
526                     continue ;// discard this cert;
527                 }
528                 free( issuer ) ;
529 
530                 // 3. check the serial number.
531                 if( memcmp( cryptSerialNumber.pbData , pCertContext->pCertInfo->SerialNumber.pbData  , cryptSerialNumber.cbData ) != 0 )
532                 {
533                     continue ;// discard this cert;
534                 }
535 
536                 // 4. confirm and break;
537                 found = 1;
538                 break ;
539             }
540 
541         }while(pCertContext);
542 
543         if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
544         if( found != 0 ) break; // Found the certificate.
545 ********************************************************************************/
546 
547         pCertContext = CertFindCertificateInStore(
548             hCertStore,
549             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
550             0,
551             CERT_FIND_SUBJECT_CERT,
552             &certInfo,
553             nullptr
554         ) ;
555 
556         if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
557         if( pCertContext != nullptr ) break ; // Found the certificate.
558 
559     }
560 
561     free(cryptSerialNumber.pbData);
562     free(certInfo.Issuer.pbData);
563 
564     if( pCertContext != nullptr ) {
565         xcert = MswcryCertContextToXCert(pCertContext);
566         CertFreeCertificateContext(pCertContext);
567     } else {
568         xcert = nullptr ;
569     }
570 
571     return xcert ;
572 }
573 
getCertificate(const OUString & issuerName,const OUString & serialNumber)574 uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::getCertificate( const OUString& issuerName, const OUString& serialNumber ) {
575     uno::Sequence< sal_Int8 > serial = xmlsecurity::numericStringToBigInteger( serialNumber ) ;
576     return getCertificate( issuerName, serial ) ;
577 }
578 
buildCertificatePath(const uno::Reference<XCertificate> & begin)579 uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl::buildCertificatePath( const uno::Reference< XCertificate >& begin ) {
580     PCCERT_CHAIN_CONTEXT pChainContext ;
581     PCCERT_CONTEXT pCertContext ;
582     const X509Certificate_MSCryptImpl* xcert ;
583 
584     CERT_ENHKEY_USAGE   enhKeyUsage ;
585     CERT_USAGE_MATCH    certUsage ;
586     CERT_CHAIN_PARA     chainPara ;
587 
588     enhKeyUsage.cUsageIdentifier = 0 ;
589     enhKeyUsage.rgpszUsageIdentifier = nullptr ;
590     certUsage.dwType = USAGE_MATCH_TYPE_AND ;
591     certUsage.Usage = enhKeyUsage ;
592     chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
593     chainPara.RequestedUsage = certUsage ;
594 
595     uno::Reference< XUnoTunnel > xCertTunnel( begin, uno::UNO_QUERY_THROW ) ;
596     xcert = reinterpret_cast<X509Certificate_MSCryptImpl*>(xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ));
597     if( xcert == nullptr ) {
598         throw uno::RuntimeException() ;
599     }
600 
601     pCertContext = xcert->getMswcryCert() ;
602 
603     pChainContext = nullptr ;
604 
605     BOOL bChain = FALSE;
606     if( pCertContext != nullptr )
607     {
608         HCERTSTORE hAdditionalStore = nullptr;
609         HCERTSTORE hCollectionStore = nullptr;
610         if (m_hCertStore && m_hKeyStore)
611         {
612             //Merge m_hCertStore and m_hKeyStore into one store.
613             hCollectionStore = CertOpenStore(
614                 CERT_STORE_PROV_COLLECTION ,
615                 0 ,
616                 NULL ,
617                 0 ,
618                 nullptr
619                 ) ;
620             if (hCollectionStore != nullptr)
621             {
622                 CertAddStoreToCollection (
623                      hCollectionStore ,
624                      m_hCertStore ,
625                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
626                      0) ;
627                 CertAddStoreToCollection (
628                      hCollectionStore ,
629                      m_hCertStore ,
630                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
631                      0) ;
632                 hAdditionalStore = hCollectionStore;
633             }
634 
635         }
636 
637         //if the merge of both stores failed then we add only m_hCertStore
638         if (hAdditionalStore == nullptr && m_hCertStore)
639             hAdditionalStore = m_hCertStore;
640         else if (hAdditionalStore == nullptr && m_hKeyStore)
641             hAdditionalStore = m_hKeyStore;
642         else
643             hAdditionalStore = nullptr;
644 
645         //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
646         bChain = CertGetCertificateChain(
647             nullptr ,
648             pCertContext ,
649             nullptr , //use current system time
650             hAdditionalStore,
651             &chainPara ,
652             CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_TIMESTAMP_TIME ,
653             nullptr ,
654             &pChainContext);
655         if (!bChain)
656             pChainContext = nullptr;
657 
658         //Close the additional store
659         CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
660     }
661 
662     if(bChain &&  pChainContext != nullptr && pChainContext->cChain > 0 )
663     {
664         PCCERT_CONTEXT pCertInChain ;
665         PCERT_SIMPLE_CHAIN pCertChain ;
666         X509Certificate_MSCryptImpl* pCert ;
667 
668         pCertChain = pChainContext->rgpChain[0] ;
669         if( pCertChain->cElement ) {
670             uno::Sequence< uno::Reference< XCertificate > > xCertChain( pCertChain->cElement ) ;
671 
672             for( unsigned int i = 0 ; i < pCertChain->cElement ; i ++ ) {
673                 if( pCertChain->rgpElement[i] )
674                     pCertInChain = pCertChain->rgpElement[i]->pCertContext ;
675                 else
676                     pCertInChain = nullptr ;
677 
678                 if( pCertInChain != nullptr ) {
679                     pCert = MswcryCertContextToXCert( pCertInChain ) ;
680                     if( pCert != nullptr )
681                         xCertChain[i] = pCert ;
682                 }
683             }
684 
685             CertFreeCertificateChain( pChainContext ) ;
686             pChainContext = nullptr ;
687 
688             return xCertChain ;
689         }
690     }
691     if (pChainContext)
692         CertFreeCertificateChain(pChainContext);
693 
694     return uno::Sequence< uno::Reference < XCertificate > >();
695 }
696 
createCertificateFromRaw(const uno::Sequence<sal_Int8> & rawCertificate)697 uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromRaw( const uno::Sequence< sal_Int8 >& rawCertificate ) {
698     X509Certificate_MSCryptImpl* xcert ;
699 
700     if( rawCertificate.getLength() > 0 ) {
701         xcert = new X509Certificate_MSCryptImpl() ;
702         xcert->setRawCert( rawCertificate ) ;
703     } else {
704         xcert = nullptr ;
705     }
706 
707     return xcert ;
708 }
709 
createCertificateFromAscii(const OUString & asciiCertificate)710 uno::Reference< XCertificate > SecurityEnvironment_MSCryptImpl::createCertificateFromAscii( const OUString& asciiCertificate ) {
711 
712     OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;
713 
714     xmlChar* chCert = xmlStrndup( reinterpret_cast<const xmlChar*>(oscert.getStr()), static_cast<int>(oscert.getLength()) ) ;
715 
716     xmlSecSize certSize = xmlSecBase64Decode( chCert, chCert, xmlStrlen( chCert ) ) ;
717 
718     uno::Sequence< sal_Int8 > rawCert( certSize ) ;
719     for( xmlSecSize i = 0 ; i < certSize ; i ++ )
720         rawCert[i] = *( chCert + i ) ;
721 
722     xmlFree( chCert ) ;
723 
724     return createCertificateFromRaw( rawCert ) ;
725 }
726 
727 
getCertStoreForIntermediatCerts(const uno::Sequence<uno::Reference<css::security::XCertificate>> & seqCerts)728 static HCERTSTORE getCertStoreForIntermediatCerts(
729     const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts)
730 {
731     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, nullptr);
732     if (store == nullptr)
733         return nullptr;
734 
735     for (int i = 0; i < seqCerts.getLength(); i++)
736     {
737         SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " << seqCerts[i]->getSubjectName());
738 
739         uno::Sequence<sal_Int8> data = seqCerts[i]->getEncoded();
740         PCCERT_CONTEXT cert = CertCreateCertificateContext(
741             X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(&data[0]), data.getLength());
742         //Adding the certificate creates a copy and not just increases the ref count
743         //Therefore we free later the certificate that we now add
744         CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_ALWAYS, nullptr);
745         CertFreeCertificateContext(cert);
746     }
747     return store;
748 }
749 
750 //We return only valid or invalid, as long as the API documentation expresses
751 //explicitly that all validation steps are carried out even if one or several
752 //errors occur. See also
753 //http://wiki.openoffice.org/wiki/Certificate_Path_Validation#Validation_status
verifyCertificate(const uno::Reference<css::security::XCertificate> & aCert,const uno::Sequence<uno::Reference<css::security::XCertificate>> & seqCerts)754 sal_Int32 SecurityEnvironment_MSCryptImpl::verifyCertificate(
755     const uno::Reference< css::security::XCertificate >& aCert,
756     const uno::Sequence< uno::Reference< css::security::XCertificate > >& seqCerts)
757 {
758     sal_Int32 validity = 0;
759     PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
760     PCCERT_CONTEXT pCertContext = nullptr;
761 
762     uno::Reference< XUnoTunnel > xCertTunnel( aCert, uno::UNO_QUERY_THROW ) ;
763 
764     SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName());
765 
766     auto xcert = reinterpret_cast<const X509Certificate_MSCryptImpl*>
767             (xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ));
768     if( xcert == nullptr ) {
769         throw uno::RuntimeException() ;
770     }
771 
772     pCertContext = xcert->getMswcryCert() ;
773 
774     CERT_ENHKEY_USAGE   enhKeyUsage ;
775     CERT_USAGE_MATCH    certUsage ;
776     CERT_CHAIN_PARA     chainPara = {};
777 
778     //Prepare parameter for CertGetCertificateChain
779     enhKeyUsage.cUsageIdentifier = 0 ;
780     enhKeyUsage.rgpszUsageIdentifier = nullptr ;
781     certUsage.dwType = USAGE_MATCH_TYPE_AND ;
782     certUsage.Usage = enhKeyUsage ;
783     chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
784     chainPara.RequestedUsage = certUsage ;
785 
786 
787     HCERTSTORE hCollectionStore = nullptr;
788     HCERTSTORE hIntermediateCertsStore = nullptr;
789     BOOL bChain = FALSE;
790     if( pCertContext != nullptr )
791     {
792         hIntermediateCertsStore =
793             getCertStoreForIntermediatCerts(seqCerts);
794 
795         //Merge m_hCertStore and m_hKeyStore and the store of the intermediate
796         //certificates into one store.
797         hCollectionStore = CertOpenStore(
798             CERT_STORE_PROV_COLLECTION ,
799             0 ,
800             NULL ,
801             0 ,
802             nullptr
803             ) ;
804         if (hCollectionStore != nullptr)
805         {
806             CertAddStoreToCollection (
807                 hCollectionStore ,
808                 m_hCertStore ,
809                 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
810                 0) ;
811             CertAddStoreToCollection (
812                 hCollectionStore ,
813                 m_hCertStore ,
814                 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
815                 0) ;
816             CertAddStoreToCollection (
817                 hCollectionStore,
818                 hIntermediateCertsStore,
819                 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
820                 0);
821 
822         }
823 
824         //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
825         //We do not check revocation of the root. In most cases there are none.
826         //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN
827         SAL_INFO("xmlsecurity.xmlsec", "Verifying cert using revocation information.");
828         bChain = CertGetCertificateChain(
829             nullptr ,
830             pCertContext ,
831             nullptr , //use current system time
832             hCollectionStore,
833             &chainPara ,
834             CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
835             nullptr ,
836             &pChainContext);
837 
838         if (bChain && pChainContext->cChain > 0)
839         {
840             SAL_INFO("xmlsecurity.xmlsec", "Overall error status (all chains):");
841             traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus);
842             //highest quality chains come first
843             PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
844             SAL_INFO("xmlsecurity.xmlsec", "Error status of first chain:");
845             traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus);
846 
847             //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate
848             //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed.
849             DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
850                 CERT_TRUST_IS_OFFLINE_REVOCATION;
851             DWORD otherErrorsMask = ~revocationFlags;
852             if( !(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask))
853 
854             {
855                 //No errors except maybe those caused by missing revocation information
856                 //Check if there are errors
857                 if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags)
858                 {
859                     //No revocation information. Because MSDN documentation is not
860                     //clear about if all other tests are performed if an error occurs,
861                     //we test again, without requiring revocation checking.
862                     CertFreeCertificateChain(pChainContext);
863                     pChainContext = nullptr;
864                     SAL_INFO("xmlsecurity.xmlsec", "Checking again but without requiring revocation information.");
865                     bChain = CertGetCertificateChain(
866                         nullptr ,
867                         pCertContext ,
868                         nullptr , //use current system time
869                         hCollectionStore,
870                         &chainPara ,
871                         0,
872                         nullptr ,
873                         &pChainContext);
874                     if (bChain
875                         && pChainContext->cChain > 0
876                         && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
877                     {
878                         SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
879                         validity = css::security::CertificateValidity::VALID;
880                     }
881                     else
882                     {
883                         SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
884                     }
885                 }
886                 else
887                 {
888                     //valid and revocation information available
889                     SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
890                     validity = css::security::CertificateValidity::VALID;
891                 }
892             }
893             else
894             {
895                 //invalid
896                 SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
897                 validity = css::security::CertificateValidity::INVALID ;
898             }
899         }
900         else
901         {
902             SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChaine failed.");
903         }
904     }
905 
906     if (pChainContext)
907     {
908         CertFreeCertificateChain(pChainContext);
909         pChainContext = nullptr;
910     }
911 
912     //Close the additional store, do not destroy the contained certs
913     CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
914     //Close the temporary store containing the intermediate certificates and make
915     //sure all certificates are deleted.
916     CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG);
917 
918     return validity ;
919 }
920 
getCertificateCharacters(const css::uno::Reference<css::security::XCertificate> & aCert)921 sal_Int32 SecurityEnvironment_MSCryptImpl::getCertificateCharacters( const css::uno::Reference< css::security::XCertificate >& aCert ) {
922     sal_Int32 characters ;
923     PCCERT_CONTEXT pCertContext ;
924     const X509Certificate_MSCryptImpl* xcert ;
925 
926     uno::Reference< XUnoTunnel > xCertTunnel( aCert, uno::UNO_QUERY_THROW ) ;
927     xcert = reinterpret_cast<X509Certificate_MSCryptImpl*>(xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ));
928     if( xcert == nullptr ) {
929         throw uno::RuntimeException() ;
930     }
931 
932     pCertContext = xcert->getMswcryCert() ;
933 
934     characters = 0x00000000 ;
935 
936     //Firstly, make sentence whether or not the cert is self-signed.
937     if( CertCompareCertificateName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pCertContext->pCertInfo->Subject), &(pCertContext->pCertInfo->Issuer) ) ) {
938         characters |= css::security::CertificateCharacters::SELF_SIGNED ;
939     } else {
940         characters &= ~ css::security::CertificateCharacters::SELF_SIGNED ;
941     }
942 
943     //Secondly, make sentence whether or not the cert has a private key.
944     {
945         BOOL    fCallerFreeProv ;
946         DWORD   dwKeySpec ;
947         NCRYPT_KEY_HANDLE hKey = 0;
948         DWORD dwFlags = CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
949         HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hKey;
950         if( CryptAcquireCertificatePrivateKey( pCertContext ,
951                    dwFlags,
952                    nullptr ,
953                    phCryptProvOrNCryptKey,
954                    &dwKeySpec,
955                    &fCallerFreeProv )
956         ) {
957             characters |=  css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
958 
959             if (hKey && fCallerFreeProv)
960                 NCryptFreeObject(hKey);
961         } else {
962             characters &= ~ css::security::CertificateCharacters::HAS_PRIVATE_KEY ;
963         }
964     }
965     return characters ;
966 }
967 
enableDefaultCrypt(bool enable)968 void SecurityEnvironment_MSCryptImpl::enableDefaultCrypt( bool enable ) {
969     m_bEnableDefault = enable ;
970 }
971 
defaultEnabled()972 bool SecurityEnvironment_MSCryptImpl::defaultEnabled() {
973     return m_bEnableDefault ;
974 }
975 
MswcryCertContextToXCert(PCCERT_CONTEXT cert)976 static X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert )
977 {
978     X509Certificate_MSCryptImpl* xcert ;
979 
980     if( cert != nullptr ) {
981         xcert = new X509Certificate_MSCryptImpl() ;
982         xcert->setMswcryCert( cert ) ;
983     } else {
984         xcert = nullptr ;
985     }
986 
987     return xcert ;
988 }
989 
getSecurityEnvironmentInformation()990 OUString SecurityEnvironment_MSCryptImpl::getSecurityEnvironmentInformation()
991 {
992     return "Microsoft Crypto API";
993 }
994 
createKeysManager()995 xmlSecKeysMngrPtr SecurityEnvironment_MSCryptImpl::createKeysManager() {
996 
997     xmlSecKeysMngrPtr pKeysMngr = nullptr ;
998 
999     /*-
1000      * The following lines is based on the of xmlsec-mscrypto crypto engine
1001      */
1002     pKeysMngr = xmlsecurity::MSCryptoAppliedKeysMngrCreate() ;
1003     if( pKeysMngr == nullptr )
1004         throw uno::RuntimeException() ;
1005 
1006     /*-
1007      * Adopt system default certificate store.
1008      */
1009     if( defaultEnabled() ) {
1010         //Add system key store into the keys manager.
1011         m_hMySystemStore = CertOpenSystemStoreW( 0, L"MY" ) ;
1012         if( m_hMySystemStore != nullptr ) {
1013             if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptKeyStore( pKeysMngr, m_hMySystemStore ) < 0 ) {
1014                 CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1015                 m_hMySystemStore = nullptr;
1016                 throw uno::RuntimeException() ;
1017             }
1018             m_hMySystemStore = nullptr;
1019         }
1020 
1021         //Add system root store into the keys manager.
1022         m_hRootSystemStore = CertOpenSystemStoreW( 0, L"Root" ) ;
1023         if( m_hRootSystemStore != nullptr ) {
1024             if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptTrustedStore( pKeysMngr, m_hRootSystemStore ) < 0 ) {
1025                 CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1026                 m_hRootSystemStore = nullptr;
1027                 throw uno::RuntimeException() ;
1028             }
1029             m_hRootSystemStore = nullptr;
1030         }
1031 
1032         //Add system trusted store into the keys manager.
1033         m_hTrustSystemStore = CertOpenSystemStoreW( 0, L"Trust" ) ;
1034         if( m_hTrustSystemStore != nullptr ) {
1035             if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hTrustSystemStore ) < 0 ) {
1036                 CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1037                 m_hTrustSystemStore = nullptr;
1038                 throw uno::RuntimeException() ;
1039             }
1040             m_hTrustSystemStore = nullptr;
1041         }
1042 
1043         //Add system CA store into the keys manager.
1044         m_hCaSystemStore = CertOpenSystemStoreW( 0, L"CA" ) ;
1045         if( m_hCaSystemStore != nullptr ) {
1046             if( xmlsecurity::MSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hCaSystemStore ) < 0 ) {
1047                 CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1048                 m_hCaSystemStore = nullptr;
1049                 throw uno::RuntimeException() ;
1050             }
1051             m_hCaSystemStore = nullptr;
1052         }
1053     }
1054 
1055     return pKeysMngr ;
1056 }
destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr)1057 void SecurityEnvironment_MSCryptImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) {
1058     if( pKeysMngr != nullptr ) {
1059         xmlSecKeysMngrDestroy( pKeysMngr ) ;
1060     }
1061 }
1062 
1063 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
com_sun_star_xml_crypto_SecurityEnvironment_get_implementation(uno::XComponentContext * pCtx,uno::Sequence<uno::Any> const &)1064 com_sun_star_xml_crypto_SecurityEnvironment_get_implementation(
1065     uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
1066 {
1067     return cppu::acquire(new SecurityEnvironment_MSCryptImpl(pCtx));
1068 }
1069 
1070 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1071