1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #pragma warning(push,1)
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
{
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"},
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
)
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 ) ;
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
) ;
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
) ;
175 OUString SAL_CALL
SecurityEnvironment_MSCryptImpl :: getImplementationName() throw( RuntimeException
) {
176 return impl_getImplementationName() ;
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
)
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() ) ;
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 ;
226 /* XUnoTunnel extension */
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
) ;
242 return ( SecurityEnvironment_MSCryptImpl
* )xUT
->getSomething( getUnoTunnelId() ) ;
248 HCRYPTPROV
SecurityEnvironment_MSCryptImpl :: getCryptoProvider() throw( ::com::sun::star::uno::Exception
, ::com::sun::star::uno::RuntimeException
) {
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 ) ;
258 if( aProv
!= NULL
) {
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
) {
277 void SecurityEnvironment_MSCryptImpl :: setCryptoSlot( HCERTSTORE aSlot
) throw( Exception
, RuntimeException
) {
278 if( m_hKeyStore
!= NULL
) {
279 CertCloseStore( m_hKeyStore
, CERT_CLOSE_STORE_FORCE_FLAG
) ;
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
) {
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
)
314 //If we do not find the key in the list, add a new node
318 m_tSymKeyList
.push_back( symkey
) ;
319 } catch ( Exception
& ) {
320 CryptDestroyKey( symkey
) ;
325 HCRYPTKEY
SecurityEnvironment_MSCryptImpl :: getSymKey( unsigned int position
) throw( Exception
, RuntimeException
) {
327 std::list
< HCRYPTKEY
>::iterator keyIt
;
331 for( pos
= 0, keyIt
= m_tSymKeyList
.begin() ; pos
< position
&& keyIt
!= m_tSymKeyList
.end() ; ++pos
, ++keyIt
) ;
333 if( pos
== position
&& keyIt
!= m_tSymKeyList
.end() )
339 HCRYPTKEY
SecurityEnvironment_MSCryptImpl :: getPubKey( unsigned int position
) throw( Exception
, RuntimeException
) {
341 std::list
< HCRYPTKEY
>::iterator keyIt
;
345 for( pos
= 0, keyIt
= m_tPubKeyList
.begin() ; pos
< position
&& keyIt
!= m_tPubKeyList
.end() ; ++pos
, ++keyIt
) ;
347 if( pos
== position
&& keyIt
!= m_tPubKeyList
.end() )
353 HCRYPTKEY
SecurityEnvironment_MSCryptImpl :: getPriKey( unsigned int position
) throw( Exception
, RuntimeException
) {
355 std::list
< HCRYPTKEY
>::iterator keyIt
;
359 for( pos
= 0, keyIt
= m_tPriKeyList
.begin() ; pos
< position
&& keyIt
!= m_tPriKeyList
.end() ; ++pos
, ++keyIt
) ;
361 if( pos
== position
&& keyIt
!= m_tPriKeyList
.end() )
367 //Methods from XSecurityEnvironment
368 Sequence
< Reference
< XCertificate
> > SecurityEnvironment_MSCryptImpl :: getPersonalCertificates() throw( SecurityException
, RuntimeException
)
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
);
380 xcert
= MswcryCertContextToXCert( pCertContext
) ;
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
;
396 HCRYPTPROV hCryptProv
;
398 hSystemKeyStore
= CertOpenSystemStore( 0, "MY" ) ;
399 if( hSystemKeyStore
!= NULL
) {
400 pCertContext
= CertEnumCertificatesInStore( hSystemKeyStore
, pCertContext
);
403 // for checking whether the certificate is a personal certificate or not.
404 if(!(CryptAcquireCertificatePrivateKey(pCertContext
,
405 CRYPT_ACQUIRE_COMPARE_KEY_FLAG
,
411 // Not Privatekey found. SKIP this one.
412 pCertContext
= CertEnumCertificatesInStore( hSystemKeyStore
, pCertContext
);
415 // then TODO : Check the personal cert is valid or not.
417 xcert
= MswcryCertContextToXCert( pCertContext
) ;
419 certsList
.push_back( xcert
) ;
420 pCertContext
= CertEnumCertificatesInStore( hSystemKeyStore
, pCertContext
);
424 CertCloseStore( hSystemKeyStore
, CERT_CLOSE_STORE_CHECK_FLAG
) ;
427 length
= certsList
.size() ;
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
;
440 return Sequence
< Reference
< XCertificate
> >() ;
444 Reference
< XCertificate
> SecurityEnvironment_MSCryptImpl :: getCertificate( const OUString
& issuerName
, const Sequence
< sal_Int8
>& serialNumber
) throw( SecurityException
, RuntimeException
) {
447 X509Certificate_MSCryptImpl
*xcert
= NULL
;
448 PCCERT_CONTEXT pCertContext
= NULL
;
449 HCERTSTORE hCertStore
= NULL
;
450 CRYPT_INTEGER_BLOB cryptSerialNumber
;
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
,
466 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
| CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG
,
469 &certInfo
.Issuer
.cbData
, 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
,
481 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
| CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG
,
483 ( BYTE
* )certInfo
.Issuer
.pbData
,
484 &certInfo
.Issuer
.cbData
, NULL
) )
486 free( certInfo
.Issuer
.pbData
) ;
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
++ )
510 if(m_hKeyStore
== NULL
) continue ;
511 hCertStore
= m_hKeyStore
;
514 if(m_hCertStore
== NULL
) continue ;
515 hCertStore
= m_hCertStore
;
518 hCertStore
= CertOpenSystemStore( 0, "MY" ) ;
519 if(hCertStore
== NULL
|| !m_bEnableDefault
) continue ;
522 hCertStore
= CertOpenSystemStore( 0, "Root" ) ;
523 if(hCertStore
== NULL
|| !m_bEnableDefault
) continue ;
526 hCertStore
= CertOpenSystemStore( 0, "Trust" ) ;
527 if(hCertStore
== NULL
|| !m_bEnableDefault
) continue ;
530 hCertStore
= CertOpenSystemStore( 0, "CA" ) ;
531 if(hCertStore
== NULL
|| !m_bEnableDefault
) 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)
546 /*******************************************************************************
547 pCertContext = NULL ;
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 ;
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 ,
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 ,
587 continue ;// discard this cert;
590 if(strncmp(pszName , issuer , cbIssuer) != 0)
593 continue ;// discard this cert;
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;
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(
616 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
618 CERT_FIND_SUBJECT_CERT
,
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
) ;
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
;
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
,
691 if (hCollectionStore
!= NULL
)
693 CertAddStoreToCollection (
696 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
,
698 CertAddStoreToCollection (
701 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
,
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
;
714 hAdditionalStore
= NULL
;
716 //CertGetCertificateChain searches by default in MY, CA, ROOT and TRUST
717 bChain
= CertGetCertificateChain(
720 NULL
, //use current system time
723 CERT_CHAIN_REVOCATION_CHECK_CHAIN
| CERT_CHAIN_TIMESTAMP_TIME
,
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
;
747 pCertInChain
= NULL
;
749 if( pCertInChain
!= NULL
) {
750 pCert
= MswcryCertContextToXCert( pCertInChain
) ;
752 xCertChain
[i
] = pCert
;
756 CertFreeCertificateChain( pChainContext
) ;
757 pChainContext
= NULL
;
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
) ;
781 Reference
< XCertificate
> SecurityEnvironment_MSCryptImpl :: createCertificateFromAscii( const OUString
& asciiCertificate
) throw( SecurityException
, RuntimeException
) {
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
) ;
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
);
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
);
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
;
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
,
884 if (hCollectionStore
!= NULL
)
886 CertAddStoreToCollection (
889 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
,
891 CertAddStoreToCollection (
894 CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
,
896 CertAddStoreToCollection (
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(
911 NULL
, //use current system time
914 CERT_CHAIN_REVOCATION_CHECK_CHAIN
| CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
,
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(
948 NULL
, //use current system time
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
;
963 SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
968 //valid and revocation information available
969 SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
970 validity
= ::com::sun::star::security::CertificateValidity::VALID
;
976 SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
977 validity
= ::com::sun::star::security::CertificateValidity::INVALID
;
982 SAL_INFO("xmlsecurity.xmlsec", "CertGetCertificateChaine failed.");
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
);
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
;
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
;
1032 if( CryptAcquireCertificatePrivateKey( pCertContext
,
1037 &( fCallerFreeProv
) )
1039 characters
|= ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY
;
1041 if( hProv
!= NULL
&& fCallerFreeProv
)
1042 CryptReleaseContext( hProv
, 0 ) ;
1044 characters
&= ~ ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY
;
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
) ;
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
) {
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() ;
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: */