Bump version to 5.0-14
[LibreOffice.git] / xmlsecurity / source / xmlsec / mscrypt / securityenvironment_mscryptimpl.cxx
blobe7af2df809dae8416290bb11de33234504a25e12
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
22 #ifdef _MSC_VER
23 #pragma warning(push,1)
24 #endif
25 #include "Windows.h"
26 #include "WinCrypt.h"
27 #ifdef _MSC_VER
28 #pragma warning(pop)
29 #endif
30 #include <sal/config.h>
31 #include <sal/macros.h>
32 #include <osl/thread.h>
33 #include "securityenvironment_mscryptimpl.hxx"
35 #include "x509certificate_mscryptimpl.hxx"
36 #include <comphelper/servicehelper.hxx>
38 #include "xmlsecurity/xmlsec-wrapper.h"
39 #include "xmlsec/mscrypto/akmngr.h"
41 #include <xmlsecurity/biginteger.hxx>
43 #include <sal/log.hxx>
44 #include <rtl/locale.h>
45 #include <osl/nlsupport.h>
46 #include <osl/process.h>
48 using namespace ::com::sun::star::uno ;
49 using namespace ::com::sun::star::lang ;
50 using ::com::sun::star::lang::XMultiServiceFactory ;
51 using ::com::sun::star::lang::XSingleServiceFactory ;
53 using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
54 using ::com::sun::star::security::XCertificate ;
56 extern X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert ) ;
58 struct CertErrorToString{
59 DWORD error;
60 char * name;
63 CertErrorToString arErrStrings[] =
65 { 0x00000000, "CERT_TRUST_NO_ERROR"},
66 { 0x00000001, "CERT_TRUST_IS_NOT_TIME_VALID"},
67 { 0x00000002, "CERT_TRUST_IS_NOT_TIME_NESTED"},
68 { 0x00000004, "CERT_TRUST_IS_REVOKED" },
69 { 0x00000008, "CERT_TRUST_IS_NOT_SIGNATURE_VALID" },
70 { 0x00000010, "CERT_TRUST_IS_NOT_SIGNATURE_VALID"},
71 { 0x00000020, "CERT_TRUST_IS_UNTRUSTED_ROOT"},
72 { 0x00000040, "CERT_TRUST_REVOCATION_STATUS_UNKNOWN"},
73 { 0x00000080, "CERT_TRUST_IS_CYCLIC"},
74 { 0x00000100, "CERT_TRUST_INVALID_EXTENSION"},
75 { 0x00000200, "CERT_TRUST_INVALID_POLICY_CONSTRAINTS"},
76 { 0x00000400, "CERT_TRUST_INVALID_BASIC_CONSTRAINTS"},
77 { 0x00000800, "CERT_TRUST_INVALID_NAME_CONSTRAINTS"},
78 { 0x00001000, "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT"},
79 { 0x00002000, "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT"},
80 { 0x00004000, "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT"},
81 { 0x00008000, "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT"},
82 { 0x01000000, "CERT_TRUST_IS_OFFLINE_REVOCATION"},
83 { 0x02000000, "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY"},
84 { 0x04000000, "CERT_TRUST_IS_EXPLICIT_DISTRUST"},
85 { 0x08000000, "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT"},
86 //Chain errors
87 { 0x00010000, "CERT_TRUST_IS_PARTIAL_CHAIN"},
88 { 0x00020000, "CERT_TRUST_CTL_IS_NOT_TIME_VALID"},
89 { 0x00040000, "CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID"},
90 { 0x00080000, "CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE"}
93 void traceTrustStatus(DWORD err)
95 if (err == 0)
96 SAL_INFO("xmlsecurity.xmlsec", " " << arErrStrings[0].name);
97 for (int i = 1; i < SAL_N_ELEMENTS(arErrStrings); i++)
99 if (arErrStrings[i].error & err)
100 SAL_INFO("xmlsecurity.xmlsec", " " << arErrStrings[i].name);
104 SecurityEnvironment_MSCryptImpl :: SecurityEnvironment_MSCryptImpl( const Reference< XMultiServiceFactory >& aFactory ) : m_hProv( NULL ) , m_pszContainer( NULL ) , m_hKeyStore( NULL ), m_hCertStore( NULL ), m_tSymKeyList() , m_tPubKeyList() , m_tPriKeyList(), m_xServiceManager( aFactory ), m_bEnableDefault( sal_False ), m_hMySystemStore(NULL), m_hRootSystemStore(NULL), m_hTrustSystemStore(NULL), m_hCaSystemStore(NULL){
108 SecurityEnvironment_MSCryptImpl :: ~SecurityEnvironment_MSCryptImpl() {
110 if( m_hProv != NULL ) {
111 CryptReleaseContext( m_hProv, 0 ) ;
112 m_hProv = NULL ;
115 if( m_pszContainer != NULL ) {
116 //TODO: Don't know whether or not it should be released now.
117 m_pszContainer = NULL ;
120 if( m_hCertStore != NULL ) {
121 CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
122 m_hCertStore = NULL ;
125 if( m_hKeyStore != NULL ) {
126 CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
127 m_hKeyStore = NULL ;
130 //i120675, close the store handles
131 if( m_hMySystemStore != NULL ) {
132 CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
133 m_hMySystemStore = NULL ;
136 if( m_hRootSystemStore != NULL ) {
137 CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
138 m_hRootSystemStore = NULL ;
141 if( m_hTrustSystemStore != NULL ) {
142 CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
143 m_hTrustSystemStore = NULL ;
146 if( m_hCaSystemStore != NULL ) {
147 CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
148 m_hCaSystemStore = NULL ;
151 if( !m_tSymKeyList.empty() ) {
152 std::list< HCRYPTKEY >::iterator symKeyIt ;
154 for( symKeyIt = m_tSymKeyList.begin() ; symKeyIt != m_tSymKeyList.end() ; ++symKeyIt )
155 CryptDestroyKey( *symKeyIt ) ;
158 if( !m_tPubKeyList.empty() ) {
159 std::list< HCRYPTKEY >::iterator pubKeyIt ;
161 for( pubKeyIt = m_tPubKeyList.begin() ; pubKeyIt != m_tPubKeyList.end() ; ++pubKeyIt )
162 CryptDestroyKey( *pubKeyIt ) ;
165 if( !m_tPriKeyList.empty() ) {
166 std::list< HCRYPTKEY >::iterator priKeyIt ;
168 for( priKeyIt = m_tPriKeyList.begin() ; priKeyIt != m_tPriKeyList.end() ; ++priKeyIt )
169 CryptDestroyKey( *priKeyIt ) ;
174 /* XServiceInfo */
175 OUString SAL_CALL SecurityEnvironment_MSCryptImpl :: getImplementationName() throw( RuntimeException ) {
176 return impl_getImplementationName() ;
179 /* XServiceInfo */
180 sal_Bool SAL_CALL SecurityEnvironment_MSCryptImpl :: supportsService( const OUString& serviceName) throw( RuntimeException ) {
181 Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
182 const OUString* pArray = seqServiceNames.getConstArray() ;
183 for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
184 if( *( pArray + i ) == serviceName )
185 return sal_True ;
187 return sal_False ;
190 /* XServiceInfo */
191 Sequence< OUString > SAL_CALL SecurityEnvironment_MSCryptImpl :: getSupportedServiceNames() throw( RuntimeException ) {
192 return impl_getSupportedServiceNames() ;
195 //Helper for XServiceInfo
196 Sequence< OUString > SecurityEnvironment_MSCryptImpl :: impl_getSupportedServiceNames() {
197 ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
198 Sequence< OUString > seqServiceNames( 1 ) ;
199 seqServiceNames[0] = "com.sun.star.xml.crypto.SecurityEnvironment";
200 return seqServiceNames ;
203 OUString SecurityEnvironment_MSCryptImpl :: impl_getImplementationName() throw( RuntimeException ) {
204 return OUString("com.sun.star.xml.security.bridge.xmlsec.SecurityEnvironment_MSCryptImpl") ;
207 //Helper for registry
208 Reference< XInterface > SAL_CALL SecurityEnvironment_MSCryptImpl :: impl_createInstance( const Reference< XMultiServiceFactory >& aServiceManager ) throw( RuntimeException ) {
209 return Reference< XInterface >( *new SecurityEnvironment_MSCryptImpl( aServiceManager ) ) ;
212 Reference< XSingleServiceFactory > SecurityEnvironment_MSCryptImpl :: impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) {
213 return ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName() , impl_createInstance , impl_getSupportedServiceNames() ) ;
216 /* XUnoTunnel */
217 sal_Int64 SAL_CALL SecurityEnvironment_MSCryptImpl :: getSomething( const Sequence< sal_Int8 >& aIdentifier )
218 throw( RuntimeException )
220 if( aIdentifier.getLength() == 16 && 0 == memcmp( getUnoTunnelId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) {
221 return ( sal_Int64 )this ;
223 return 0 ;
226 /* XUnoTunnel extension */
229 namespace
231 class theSecurityEnvironment_MSCryptImplUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSecurityEnvironment_MSCryptImplUnoTunnelId > {};
234 const Sequence< sal_Int8>& SecurityEnvironment_MSCryptImpl :: getUnoTunnelId() {
235 return theSecurityEnvironment_MSCryptImplUnoTunnelId::get().getSeq();
238 /* XUnoTunnel extension */
239 SecurityEnvironment_MSCryptImpl* SecurityEnvironment_MSCryptImpl :: getImplementation( const Reference< XInterface >& rObj ) {
240 Reference< XUnoTunnel > xUT( rObj , UNO_QUERY ) ;
241 if( xUT.is() ) {
242 return ( SecurityEnvironment_MSCryptImpl* )xUT->getSomething( getUnoTunnelId() ) ;
243 } else
244 return NULL ;
247 /* Native methods */
248 HCRYPTPROV SecurityEnvironment_MSCryptImpl :: getCryptoProvider() throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
249 return m_hProv ;
252 void SecurityEnvironment_MSCryptImpl :: setCryptoProvider( HCRYPTPROV aProv ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
253 if( m_hProv != NULL ) {
254 CryptReleaseContext( m_hProv, 0 ) ;
255 m_hProv = NULL ;
258 if( aProv != NULL ) {
259 m_hProv = aProv ;
263 LPCTSTR SecurityEnvironment_MSCryptImpl :: getKeyContainer() throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
264 return m_pszContainer ;
267 void SecurityEnvironment_MSCryptImpl :: setKeyContainer( LPCTSTR aKeyContainer ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
268 //TODO: Don't know whether or not it should be copied.
269 m_pszContainer = aKeyContainer ;
273 HCERTSTORE SecurityEnvironment_MSCryptImpl :: getCryptoSlot() throw( Exception , RuntimeException ) {
274 return m_hKeyStore ;
277 void SecurityEnvironment_MSCryptImpl :: setCryptoSlot( HCERTSTORE aSlot) throw( Exception , RuntimeException ) {
278 if( m_hKeyStore != NULL ) {
279 CertCloseStore( m_hKeyStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
280 m_hKeyStore = NULL ;
283 if( aSlot != NULL ) {
284 m_hKeyStore = CertDuplicateStore( aSlot ) ;
288 HCERTSTORE SecurityEnvironment_MSCryptImpl :: getCertDb() throw( Exception , RuntimeException ) {
289 return m_hCertStore ;
292 void SecurityEnvironment_MSCryptImpl :: setCertDb( HCERTSTORE aCertDb ) throw( Exception , RuntimeException ) {
293 if( m_hCertStore != NULL ) {
294 CertCloseStore( m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG ) ;
295 m_hCertStore = NULL ;
298 if( aCertDb != NULL ) {
299 m_hCertStore = CertDuplicateStore( aCertDb ) ;
303 void SecurityEnvironment_MSCryptImpl :: adoptSymKey( HCRYPTKEY aSymKey ) throw( Exception , RuntimeException ) {
304 HCRYPTKEY symkey ;
305 std::list< HCRYPTKEY >::iterator keyIt ;
307 if( aSymKey != NULL ) {
308 //First try to find the key in the list
309 for( keyIt = m_tSymKeyList.begin() ; keyIt != m_tSymKeyList.end() ; ++keyIt ) {
310 if( *keyIt == aSymKey )
311 return ;
314 //If we do not find the key in the list, add a new node
315 symkey = aSymKey ;
317 try {
318 m_tSymKeyList.push_back( symkey ) ;
319 } catch ( Exception& ) {
320 CryptDestroyKey( symkey ) ;
325 HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getSymKey( unsigned int position ) throw( Exception , RuntimeException ) {
326 HCRYPTKEY symkey ;
327 std::list< HCRYPTKEY >::iterator keyIt ;
328 unsigned int pos ;
330 symkey = NULL ;
331 for( pos = 0, keyIt = m_tSymKeyList.begin() ; pos < position && keyIt != m_tSymKeyList.end() ; ++pos , ++keyIt ) ;
333 if( pos == position && keyIt != m_tSymKeyList.end() )
334 symkey = *keyIt ;
336 return symkey ;
339 HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getPubKey( unsigned int position ) throw( Exception , RuntimeException ) {
340 HCRYPTKEY pubkey ;
341 std::list< HCRYPTKEY >::iterator keyIt ;
342 unsigned int pos ;
344 pubkey = NULL ;
345 for( pos = 0, keyIt = m_tPubKeyList.begin() ; pos < position && keyIt != m_tPubKeyList.end() ; ++pos , ++keyIt ) ;
347 if( pos == position && keyIt != m_tPubKeyList.end() )
348 pubkey = *keyIt ;
350 return pubkey ;
353 HCRYPTKEY SecurityEnvironment_MSCryptImpl :: getPriKey( unsigned int position ) throw( Exception , RuntimeException ) {
354 HCRYPTKEY prikey ;
355 std::list< HCRYPTKEY >::iterator keyIt ;
356 unsigned int pos ;
358 prikey = NULL ;
359 for( pos = 0, keyIt = m_tPriKeyList.begin() ; pos < position && keyIt != m_tPriKeyList.end() ; ++pos , ++keyIt ) ;
361 if( pos == position && keyIt != m_tPriKeyList.end() )
362 prikey = *keyIt ;
364 return prikey ;
367 //Methods from XSecurityEnvironment
368 Sequence< Reference < XCertificate > > SecurityEnvironment_MSCryptImpl :: getPersonalCertificates() throw( SecurityException , RuntimeException )
370 sal_Int32 length ;
371 X509Certificate_MSCryptImpl* xcert ;
372 std::list< X509Certificate_MSCryptImpl* > certsList ;
373 PCCERT_CONTEXT pCertContext = NULL;
375 //firstly, we try to find private keys in given key store.
376 if( m_hKeyStore != NULL ) {
377 pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
378 while (pCertContext)
380 xcert = MswcryCertContextToXCert( pCertContext ) ;
381 if( xcert != NULL )
382 certsList.push_back( xcert ) ;
383 pCertContext = CertEnumCertificatesInStore( m_hKeyStore, pCertContext );
387 //secondly, we try to find certificate from registered private keys.
388 if( !m_tPriKeyList.empty() ) {
389 //TODO: Don't know whether or not it is necessary ans possible.
392 //Thirdly, we try to find certificate from system default key store.
393 if( m_bEnableDefault ) {
394 HCERTSTORE hSystemKeyStore ;
395 DWORD dwKeySpec;
396 HCRYPTPROV hCryptProv;
398 hSystemKeyStore = CertOpenSystemStore( 0, "MY" ) ;
399 if( hSystemKeyStore != NULL ) {
400 pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
401 while (pCertContext)
403 // for checking whether the certificate is a personal certificate or not.
404 if(!(CryptAcquireCertificatePrivateKey(pCertContext,
405 CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
406 NULL,
407 &hCryptProv,
408 &dwKeySpec,
409 NULL)))
411 // Not Privatekey found. SKIP this one.
412 pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
413 continue;
415 // then TODO : Check the personal cert is valid or not.
417 xcert = MswcryCertContextToXCert( pCertContext ) ;
418 if( xcert != NULL )
419 certsList.push_back( xcert ) ;
420 pCertContext = CertEnumCertificatesInStore( hSystemKeyStore, pCertContext );
424 CertCloseStore( hSystemKeyStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
427 length = certsList.size() ;
428 if( length != 0 ) {
429 int i ;
430 std::list< X509Certificate_MSCryptImpl* >::iterator xcertIt ;
431 Sequence< Reference< XCertificate > > certSeq( length ) ;
433 for( i = 0, xcertIt = certsList.begin(); xcertIt != certsList.end(); ++xcertIt, ++i ) {
434 certSeq[i] = *xcertIt ;
437 return certSeq ;
440 return Sequence< Reference< XCertificate > >() ;
444 Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: getCertificate( const OUString& issuerName, const Sequence< sal_Int8 >& serialNumber ) throw( SecurityException , RuntimeException ) {
445 unsigned int i ;
446 LPSTR pszName ;
447 X509Certificate_MSCryptImpl *xcert = NULL ;
448 PCCERT_CONTEXT pCertContext = NULL ;
449 HCERTSTORE hCertStore = NULL ;
450 CRYPT_INTEGER_BLOB cryptSerialNumber ;
451 CERT_INFO certInfo ;
453 // for correct encoding
454 sal_uInt16 encoding ;
455 rtl_Locale *pLocale = NULL ;
456 osl_getProcessLocale( &pLocale ) ;
457 encoding = osl_getTextEncodingFromLocale( pLocale ) ;
459 //Create cert info from issue and serial
460 OString oissuer = OUStringToOString( issuerName , encoding ) ;
461 pszName = ( char* )oissuer.getStr() ;
463 if( ! ( CertStrToName(
464 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
465 pszName ,
466 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
467 NULL ,
468 NULL ,
469 &certInfo.Issuer.cbData, NULL ) )
471 return NULL ;
474 certInfo.Issuer.pbData = ( BYTE* )malloc( certInfo.Issuer.cbData );
475 if(!certInfo.Issuer.pbData)
476 throw RuntimeException() ;
478 if( ! ( CertStrToName(
479 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
480 pszName ,
481 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG,
482 NULL ,
483 ( BYTE* )certInfo.Issuer.pbData ,
484 &certInfo.Issuer.cbData, NULL ) )
486 free( certInfo.Issuer.pbData ) ;
487 return NULL ;
490 //Get the SerialNumber
491 cryptSerialNumber.cbData = serialNumber.getLength() ;
492 cryptSerialNumber.pbData = ( BYTE* )malloc( cryptSerialNumber.cbData);
493 if (!cryptSerialNumber.pbData)
495 free( certInfo.Issuer.pbData ) ;
496 throw RuntimeException() ;
498 for( i = 0; i < cryptSerialNumber.cbData; i ++ )
499 cryptSerialNumber.pbData[i] = serialNumber[ cryptSerialNumber.cbData - i - 1 ] ;
501 certInfo.SerialNumber.cbData = cryptSerialNumber.cbData ;
502 certInfo.SerialNumber.pbData = cryptSerialNumber.pbData ;
504 // Get the Cert from all store.
505 for( i = 0 ; i < 6 ; i ++ )
507 switch(i)
509 case 0:
510 if(m_hKeyStore == NULL) continue ;
511 hCertStore = m_hKeyStore ;
512 break;
513 case 1:
514 if(m_hCertStore == NULL) continue ;
515 hCertStore = m_hCertStore ;
516 break;
517 case 2:
518 hCertStore = CertOpenSystemStore( 0, "MY" ) ;
519 if(hCertStore == NULL || !m_bEnableDefault) continue ;
520 break;
521 case 3:
522 hCertStore = CertOpenSystemStore( 0, "Root" ) ;
523 if(hCertStore == NULL || !m_bEnableDefault) continue ;
524 break;
525 case 4:
526 hCertStore = CertOpenSystemStore( 0, "Trust" ) ;
527 if(hCertStore == NULL || !m_bEnableDefault) continue ;
528 break;
529 case 5:
530 hCertStore = CertOpenSystemStore( 0, "CA" ) ;
531 if(hCertStore == NULL || !m_bEnableDefault) continue ;
532 break;
533 default:
534 i=6;
535 continue;
538 /*******************************************************************************
539 * This code reserved for remind us there are another way to find one cert by
540 * IssuerName&serialnumber. You can use the code to replaced the function
541 * CertFindCertificateInStore IF and ONLY IF you must find one special cert in
542 * certStore but can not be found by CertFindCertificateInStore , then , you
543 * should also change the same part in libxmlsec/.../src/mscrypto/x509vfy.c#875.
544 * By Chandler Peng(chandler.peng@sun.com)
545 *****/
546 /*******************************************************************************
547 pCertContext = NULL ;
548 found = 0;
550 // 1. enum the certs has same string in the issuer string.
551 pCertContext = CertEnumCertificatesInStore( hCertStore , pCertContext ) ;
552 if( pCertContext != NULL )
554 // 2. check the cert's issuer name .
555 char* issuer = NULL ;
556 DWORD cbIssuer = 0 ;
558 cbIssuer = CertNameToStr(
559 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
560 &( pCertContext->pCertInfo->Issuer ),
561 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
562 NULL, 0
565 if( cbIssuer == 0 ) continue ; // discard this cert;
567 issuer = (char *)malloc( cbIssuer ) ;
568 if( issuer == NULL ) // discard this cert;
570 free( cryptSerialNumber.pbData) ;
571 free( certInfo.Issuer.pbData ) ;
572 CertFreeCertificateContext( pCertContext ) ;
573 if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
574 throw RuntimeException() ;
577 cbIssuer = CertNameToStr(
578 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
579 &( pCertContext->pCertInfo->Issuer ),
580 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
581 issuer, cbIssuer
584 if( cbIssuer <= 0 )
586 free( issuer ) ;
587 continue ;// discard this cert;
590 if(strncmp(pszName , issuer , cbIssuer) != 0)
592 free( issuer ) ;
593 continue ;// discard this cert;
595 free( issuer ) ;
597 // 3. check the serial number.
598 if( memcmp( cryptSerialNumber.pbData , pCertContext->pCertInfo->SerialNumber.pbData , cryptSerialNumber.cbData ) != 0 )
600 continue ;// discard this cert;
603 // 4. confirm and break;
604 found = 1;
605 break ;
608 }while(pCertContext);
610 if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
611 if( found != 0 ) break; // Found the certificate.
612 ********************************************************************************/
614 pCertContext = CertFindCertificateInStore(
615 hCertStore,
616 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
618 CERT_FIND_SUBJECT_CERT,
619 &certInfo,
620 NULL
623 if(i != 0 && i != 1) CertCloseStore( hCertStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
624 if( pCertContext != NULL ) break ; // Found the certificate.
628 if( cryptSerialNumber.pbData ) free( cryptSerialNumber.pbData ) ;
629 if( certInfo.Issuer.pbData ) free( certInfo.Issuer.pbData ) ;
631 if( pCertContext != NULL ) {
632 xcert = MswcryCertContextToXCert( pCertContext ) ;
633 if( pCertContext ) CertFreeCertificateContext( pCertContext ) ;
634 } else {
635 xcert = NULL ;
638 return xcert ;
641 Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: getCertificate( const OUString& issuerName, const OUString& serialNumber ) throw( SecurityException , RuntimeException ) {
642 Sequence< sal_Int8 > serial = numericStringToBigInteger( serialNumber ) ;
643 return getCertificate( issuerName, serial ) ;
646 Sequence< Reference < XCertificate > > SecurityEnvironment_MSCryptImpl :: buildCertificatePath( const Reference< XCertificate >& begin ) throw( SecurityException , RuntimeException ) {
647 PCCERT_CHAIN_CONTEXT pChainContext ;
648 PCCERT_CONTEXT pCertContext ;
649 const X509Certificate_MSCryptImpl* xcert ;
651 CERT_ENHKEY_USAGE enhKeyUsage ;
652 CERT_USAGE_MATCH certUsage ;
653 CERT_CHAIN_PARA chainPara ;
655 enhKeyUsage.cUsageIdentifier = 0 ;
656 enhKeyUsage.rgpszUsageIdentifier = NULL ;
657 certUsage.dwType = USAGE_MATCH_TYPE_AND ;
658 certUsage.Usage = enhKeyUsage ;
659 chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
660 chainPara.RequestedUsage = certUsage ;
662 Reference< XUnoTunnel > xCertTunnel( begin, UNO_QUERY ) ;
663 if( !xCertTunnel.is() ) {
664 throw RuntimeException() ;
667 xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
668 if( xcert == NULL ) {
669 throw RuntimeException() ;
672 pCertContext = xcert->getMswcryCert() ;
674 pChainContext = NULL ;
676 BOOL bChain = FALSE;
677 if( pCertContext != NULL )
679 HCERTSTORE hAdditionalStore = NULL;
680 HCERTSTORE hCollectionStore = NULL;
681 if (m_hCertStore && m_hKeyStore)
683 //Merge m_hCertStore and m_hKeyStore into one store.
684 hCollectionStore = CertOpenStore(
685 CERT_STORE_PROV_COLLECTION ,
687 NULL ,
689 NULL
691 if (hCollectionStore != NULL)
693 CertAddStoreToCollection (
694 hCollectionStore ,
695 m_hCertStore ,
696 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
697 0) ;
698 CertAddStoreToCollection (
699 hCollectionStore ,
700 m_hCertStore ,
701 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
702 0) ;
703 hAdditionalStore = hCollectionStore;
708 //if the merge of both stores failed then we add only m_hCertStore
709 if (hAdditionalStore == NULL && m_hCertStore)
710 hAdditionalStore = m_hCertStore;
711 else if (hAdditionalStore == NULL && m_hKeyStore)
712 hAdditionalStore = m_hKeyStore;
713 else
714 hAdditionalStore = NULL;
716 //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
717 bChain = CertGetCertificateChain(
718 NULL ,
719 pCertContext ,
720 NULL , //use current system time
721 hAdditionalStore,
722 &chainPara ,
723 CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_TIMESTAMP_TIME ,
724 NULL ,
725 &pChainContext);
726 if (!bChain)
727 pChainContext = NULL;
729 //Close the additional store
730 CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
733 if(bChain && pChainContext != NULL && pChainContext->cChain > 0 )
735 PCCERT_CONTEXT pCertInChain ;
736 PCERT_SIMPLE_CHAIN pCertChain ;
737 X509Certificate_MSCryptImpl* pCert ;
739 pCertChain = pChainContext->rgpChain[0] ;
740 if( pCertChain->cElement ) {
741 Sequence< Reference< XCertificate > > xCertChain( pCertChain->cElement ) ;
743 for( unsigned int i = 0 ; i < pCertChain->cElement ; i ++ ) {
744 if( pCertChain->rgpElement[i] )
745 pCertInChain = pCertChain->rgpElement[i]->pCertContext ;
746 else
747 pCertInChain = NULL ;
749 if( pCertInChain != NULL ) {
750 pCert = MswcryCertContextToXCert( pCertInChain ) ;
751 if( pCert != NULL )
752 xCertChain[i] = pCert ;
756 CertFreeCertificateChain( pChainContext ) ;
757 pChainContext = NULL ;
759 return xCertChain ;
762 if (pChainContext)
763 CertFreeCertificateChain(pChainContext);
765 return Sequence< Reference < XCertificate > >();
768 Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: createCertificateFromRaw( const Sequence< sal_Int8 >& rawCertificate ) throw( SecurityException , RuntimeException ) {
769 X509Certificate_MSCryptImpl* xcert ;
771 if( rawCertificate.getLength() > 0 ) {
772 xcert = new X509Certificate_MSCryptImpl() ;
773 xcert->setRawCert( rawCertificate ) ;
774 } else {
775 xcert = NULL ;
778 return xcert ;
781 Reference< XCertificate > SecurityEnvironment_MSCryptImpl :: createCertificateFromAscii( const OUString& asciiCertificate ) throw( SecurityException , RuntimeException ) {
782 xmlChar* chCert ;
783 xmlSecSize certSize ;
785 OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;
787 chCert = xmlStrndup( ( const xmlChar* )oscert.getStr(), ( int )oscert.getLength() ) ;
789 certSize = xmlSecBase64Decode( chCert, ( xmlSecByte* )chCert, xmlStrlen( chCert ) ) ;
791 Sequence< sal_Int8 > rawCert( certSize ) ;
792 for( unsigned int i = 0 ; i < certSize ; i ++ )
793 rawCert[i] = *( chCert + i ) ;
795 xmlFree( chCert ) ;
797 return createCertificateFromRaw( rawCert ) ;
801 HCERTSTORE getCertStoreForIntermediatCerts(
802 const Sequence< Reference< ::com::sun::star::security::XCertificate > >& seqCerts)
804 HCERTSTORE store = NULL;
805 store = CertOpenStore(
806 CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
807 if (store == NULL)
808 return NULL;
810 for (int i = 0; i < seqCerts.getLength(); i++)
812 SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " << seqCerts[i]->getSubjectName());
814 Sequence<sal_Int8> data = seqCerts[i]->getEncoded();
815 PCCERT_CONTEXT cert = CertCreateCertificateContext(
816 X509_ASN_ENCODING, ( const BYTE* )&data[0], data.getLength());
817 //Adding the certificate creates a copy and not just increases the ref count
818 //Therefore we free later the certificate that we now add
819 CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_ALWAYS, NULL);
820 CertFreeCertificateContext(cert);
822 return store;
825 //We return only valid or invalid, as long as the API documentation expresses
826 //explicitly that all validation steps are carried out even if one or several
827 //errors occur. See also
828 //http://wiki.openoffice.org/wiki/Certificate_Path_Validation#Validation_status
829 sal_Int32 SecurityEnvironment_MSCryptImpl :: verifyCertificate(
830 const Reference< ::com::sun::star::security::XCertificate >& aCert,
831 const Sequence< Reference< ::com::sun::star::security::XCertificate > >& seqCerts)
832 throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException )
834 sal_Int32 validity = 0;
835 PCCERT_CHAIN_CONTEXT pChainContext = NULL;
836 PCCERT_CONTEXT pCertContext = NULL;
837 const X509Certificate_MSCryptImpl* xcert = NULL;
839 Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
840 if( !xCertTunnel.is() ) {
841 throw RuntimeException() ;
844 SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName());
846 xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
847 if( xcert == NULL ) {
848 throw RuntimeException() ;
851 pCertContext = xcert->getMswcryCert() ;
853 CERT_ENHKEY_USAGE enhKeyUsage ;
854 CERT_USAGE_MATCH certUsage ;
855 CERT_CHAIN_PARA chainPara ;
856 memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA));
858 //Prepare parameter for CertGetCertificateChain
859 enhKeyUsage.cUsageIdentifier = 0 ;
860 enhKeyUsage.rgpszUsageIdentifier = NULL ;
861 certUsage.dwType = USAGE_MATCH_TYPE_AND ;
862 certUsage.Usage = enhKeyUsage ;
863 chainPara.cbSize = sizeof( CERT_CHAIN_PARA ) ;
864 chainPara.RequestedUsage = certUsage ;
867 HCERTSTORE hCollectionStore = NULL;
868 HCERTSTORE hIntermediateCertsStore = NULL;
869 BOOL bChain = FALSE;
870 if( pCertContext != NULL )
872 hIntermediateCertsStore =
873 getCertStoreForIntermediatCerts(seqCerts);
875 //Merge m_hCertStore and m_hKeyStore and the store of the intermediate
876 //certificates into one store.
877 hCollectionStore = CertOpenStore(
878 CERT_STORE_PROV_COLLECTION ,
880 NULL ,
882 NULL
884 if (hCollectionStore != NULL)
886 CertAddStoreToCollection (
887 hCollectionStore ,
888 m_hCertStore ,
889 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
890 0) ;
891 CertAddStoreToCollection (
892 hCollectionStore ,
893 m_hCertStore ,
894 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG ,
895 0) ;
896 CertAddStoreToCollection (
897 hCollectionStore,
898 hIntermediateCertsStore,
899 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
904 //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
905 //We do not check revocation of the root. In most cases there are none.
906 //Then we would get CERT_TRUST_REVOCATION_STATUS_UNKNOWN
907 SAL_INFO("xmlsecurity.xmlsec", "Verifying cert using revocation information.");
908 bChain = CertGetCertificateChain(
909 NULL ,
910 pCertContext ,
911 NULL , //use current system time
912 hCollectionStore,
913 &chainPara ,
914 CERT_CHAIN_REVOCATION_CHECK_CHAIN | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
915 NULL ,
916 &pChainContext);
918 if (bChain && pChainContext->cChain > 0)
920 SAL_INFO("xmlsecurity.xmlsec", "Overall error status (all chains):");
921 traceTrustStatus(pChainContext->TrustStatus.dwErrorStatus);
922 //highest quality chains come first
923 PCERT_SIMPLE_CHAIN pSimpleChain = pChainContext->rgpChain[0];
924 SAL_INFO("xmlsecurity.xmlsec", "Error status of first chain:");
925 traceTrustStatus(pSimpleChain->TrustStatus.dwErrorStatus);
927 //CERT_TRUST_REVOCATION_STATUS_UNKNOWN is also set if a certificate
928 //has no AIA(OCSP) or CRLDP extension and there is no CRL locally installed.
929 DWORD revocationFlags = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
930 CERT_TRUST_IS_OFFLINE_REVOCATION;
931 DWORD otherErrorsMask = ~revocationFlags;
932 if( !(pSimpleChain->TrustStatus.dwErrorStatus & otherErrorsMask))
935 //No errors except maybe those caused by missing revocation information
936 //Check if there are errors
937 if ( pSimpleChain->TrustStatus.dwErrorStatus & revocationFlags)
939 //No revocation information. Because MSDN documentation is not
940 //clear about if all other tests are performed if an error occurrs,
941 //we test again, without requiring revocation checking.
942 CertFreeCertificateChain(pChainContext);
943 pChainContext = NULL;
944 SAL_INFO("xmlsecurity.xmlsec", "Checking again but without requiring revocation information.");
945 bChain = CertGetCertificateChain(
946 NULL ,
947 pCertContext ,
948 NULL , //use current system time
949 hCollectionStore,
950 &chainPara ,
952 NULL ,
953 &pChainContext);
954 if (bChain
955 && pChainContext->cChain > 0
956 && pChainContext->rgpChain[0]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
958 SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
959 validity = ::com::sun::star::security::CertificateValidity::VALID;
961 else
963 SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
966 else
968 //valid and revocation information available
969 SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
970 validity = ::com::sun::star::security::CertificateValidity::VALID;
973 else
975 //invalid
976 SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
977 validity = ::com::sun::star::security::CertificateValidity::INVALID ;
980 else
982 SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChaine failed.");
986 if (pChainContext)
988 CertFreeCertificateChain(pChainContext);
989 pChainContext = NULL;
992 //Close the additional store, do not destroy the contained certs
993 CertCloseStore(hCollectionStore, CERT_CLOSE_STORE_CHECK_FLAG);
994 //Close the temporary store containing the intermediate certificates and make
995 //sure all certificates are deleted.
996 CertCloseStore(hIntermediateCertsStore, CERT_CLOSE_STORE_CHECK_FLAG);
998 return validity ;
1001 sal_Int32 SecurityEnvironment_MSCryptImpl :: getCertificateCharacters( const ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >& aCert ) throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException ) {
1002 sal_Int32 characters ;
1003 PCCERT_CONTEXT pCertContext ;
1004 const X509Certificate_MSCryptImpl* xcert ;
1006 Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
1007 if( !xCertTunnel.is() ) {
1008 throw RuntimeException() ;
1011 xcert = ( X509Certificate_MSCryptImpl* )xCertTunnel->getSomething( X509Certificate_MSCryptImpl::getUnoTunnelId() ) ;
1012 if( xcert == NULL ) {
1013 throw RuntimeException() ;
1016 pCertContext = xcert->getMswcryCert() ;
1018 characters = 0x00000000 ;
1020 //Firstly, make sentence whether or not the cert is self-signed.
1021 if( CertCompareCertificateName( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(pCertContext->pCertInfo->Subject), &(pCertContext->pCertInfo->Issuer) ) ) {
1022 characters |= ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
1023 } else {
1024 characters &= ~ ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
1027 //Secondly, make sentence whether or not the cert has a private key.
1029 BOOL fCallerFreeProv ;
1030 DWORD dwKeySpec ;
1031 HCRYPTPROV hProv ;
1032 if( CryptAcquireCertificatePrivateKey( pCertContext ,
1034 NULL ,
1035 &( hProv ) ,
1036 &( dwKeySpec ) ,
1037 &( fCallerFreeProv ) )
1039 characters |= ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;
1041 if( hProv != NULL && fCallerFreeProv )
1042 CryptReleaseContext( hProv, 0 ) ;
1043 } else {
1044 characters &= ~ ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;
1047 return characters ;
1050 void SecurityEnvironment_MSCryptImpl :: enableDefaultCrypt( sal_Bool enable ) throw( Exception, RuntimeException ) {
1051 m_bEnableDefault = enable ;
1054 sal_Bool SecurityEnvironment_MSCryptImpl :: defaultEnabled() throw( Exception, RuntimeException ) {
1055 return m_bEnableDefault ;
1058 X509Certificate_MSCryptImpl* MswcryCertContextToXCert( PCCERT_CONTEXT cert )
1060 X509Certificate_MSCryptImpl* xcert ;
1062 if( cert != NULL ) {
1063 xcert = new X509Certificate_MSCryptImpl() ;
1064 xcert->setMswcryCert( cert ) ;
1065 } else {
1066 xcert = NULL ;
1069 return xcert ;
1072 OUString SecurityEnvironment_MSCryptImpl::getSecurityEnvironmentInformation() throw( ::com::sun::star::uno::RuntimeException )
1074 return OUString("Microsoft Crypto API");
1077 /* Native methods */
1078 xmlSecKeysMngrPtr SecurityEnvironment_MSCryptImpl :: createKeysManager() throw( Exception, RuntimeException ) {
1080 unsigned int i ;
1081 HCRYPTKEY symKey ;
1082 HCRYPTKEY pubKey ;
1083 HCRYPTKEY priKey ;
1084 xmlSecKeysMngrPtr pKeysMngr = NULL ;
1087 * The following lines is based on the of xmlsec-mscrypto crypto engine
1089 pKeysMngr = xmlSecMSCryptoAppliedKeysMngrCreate( m_hKeyStore , m_hCertStore ) ;
1090 if( pKeysMngr == NULL )
1091 throw RuntimeException() ;
1094 * Adopt symmetric key into keys manager
1096 for( i = 0 ; ( symKey = getSymKey( i ) ) != NULL ; i ++ ) {
1097 if( xmlSecMSCryptoAppliedKeysMngrSymKeyLoad( pKeysMngr, symKey ) < 0 ) {
1098 throw RuntimeException() ;
1103 * Adopt asymmetric public key into keys manager
1105 for( i = 0 ; ( pubKey = getPubKey( i ) ) != NULL ; i ++ ) {
1106 if( xmlSecMSCryptoAppliedKeysMngrPubKeyLoad( pKeysMngr, pubKey ) < 0 ) {
1107 throw RuntimeException() ;
1112 * Adopt asymmetric private key into keys manager
1114 for( i = 0 ; ( priKey = getPriKey( i ) ) != NULL ; i ++ ) {
1115 if( xmlSecMSCryptoAppliedKeysMngrPriKeyLoad( pKeysMngr, priKey ) < 0 ) {
1116 throw RuntimeException() ;
1121 * Adopt system default certificate store.
1123 if( defaultEnabled() ) {
1124 //Add system key store into the keys manager.
1125 m_hMySystemStore = CertOpenSystemStore( 0, "MY" ) ;
1126 if( m_hMySystemStore != NULL ) {
1127 if( xmlSecMSCryptoAppliedKeysMngrAdoptKeyStore( pKeysMngr, m_hMySystemStore ) < 0 ) {
1128 CertCloseStore( m_hMySystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1129 m_hMySystemStore = NULL;
1130 throw RuntimeException() ;
1134 //Add system root store into the keys manager.
1135 m_hRootSystemStore = CertOpenSystemStore( 0, "Root" ) ;
1136 if( m_hRootSystemStore != NULL ) {
1137 if( xmlSecMSCryptoAppliedKeysMngrAdoptTrustedStore( pKeysMngr, m_hRootSystemStore ) < 0 ) {
1138 CertCloseStore( m_hRootSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1139 m_hRootSystemStore = NULL;
1140 throw RuntimeException() ;
1144 //Add system trusted store into the keys manager.
1145 m_hTrustSystemStore = CertOpenSystemStore( 0, "Trust" ) ;
1146 if( m_hTrustSystemStore != NULL ) {
1147 if( xmlSecMSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hTrustSystemStore ) < 0 ) {
1148 CertCloseStore( m_hTrustSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1149 m_hTrustSystemStore = NULL;
1150 throw RuntimeException() ;
1154 //Add system CA store into the keys manager.
1155 m_hCaSystemStore = CertOpenSystemStore( 0, "CA" ) ;
1156 if( m_hCaSystemStore != NULL ) {
1157 if( xmlSecMSCryptoAppliedKeysMngrAdoptUntrustedStore( pKeysMngr, m_hCaSystemStore ) < 0 ) {
1158 CertCloseStore( m_hCaSystemStore, CERT_CLOSE_STORE_CHECK_FLAG ) ;
1159 m_hCaSystemStore = NULL;
1160 throw RuntimeException() ;
1165 return pKeysMngr ;
1167 void SecurityEnvironment_MSCryptImpl :: destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) throw( Exception, RuntimeException ) {
1168 if( pKeysMngr != NULL ) {
1169 xmlSecKeysMngrDestroy( pKeysMngr ) ;
1173 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */