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