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 .
20 #include "nssrenam.h" // rename problematic symbols
25 #include <sal/config.h>
26 #include <sal/macros.h>
27 #include "securityenvironment_nssimpl.hxx"
28 #include "x509certificate_nssimpl.hxx"
29 #include <comphelper/servicehelper.hxx>
30 #include "../diagnose.hxx"
32 #include "xmlsecurity/xmlsec-wrapper.h"
34 #include <rtl/ustrbuf.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/docpasswordrequest.hxx>
37 #include <xmlsecurity/biginteger.hxx>
38 #include <sal/log.hxx>
39 #include <com/sun/star/task/InteractionHandler.hpp>
41 #include "boost/scoped_array.hpp"
42 #include <osl/thread.h>
44 #include "secerror.hxx"
46 // added for password exception
47 #include <com/sun/star/security/NoPasswordException.hpp>
48 namespace csss
= ::com::sun::star::security
;
49 using namespace xmlsecurity
;
50 using namespace ::com::sun::star::security
;
51 using namespace com::sun::star
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::lang
;
54 using ::com::sun::star::lang::XMultiServiceFactory
;
55 using ::com::sun::star::lang::XSingleServiceFactory
;
57 using ::com::sun::star::xml::crypto::XSecurityEnvironment
;
58 using ::com::sun::star::security::XCertificate
;
60 extern X509Certificate_NssImpl
* NssCertToXCert( CERTCertificate
* cert
) ;
61 extern X509Certificate_NssImpl
* NssPrivKeyToXCert( SECKEYPrivateKey
* ) ;
64 struct UsageDescription
66 SECCertificateUsage usage
;
67 char const* description
;
70 : usage( certificateUsageCheckAllUsages
)
74 UsageDescription( SECCertificateUsage i_usage
, char const* i_description
)
76 , description( i_description
)
79 UsageDescription( const UsageDescription
& aDescription
)
80 : usage( aDescription
.usage
)
81 , description( aDescription
.description
)
84 UsageDescription
& operator =( const UsageDescription
& aDescription
)
86 usage
= aDescription
.usage
;
87 description
= aDescription
.description
;
94 char* GetPasswordFunction( PK11SlotInfo
* pSlot
, PRBool bRetry
, void* /*arg*/ )
96 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
97 uno::Reference
< task::XInteractionHandler2
> xInteractionHandler(
98 task::InteractionHandler::createWithParent(xContext
, 0) );
100 task::PasswordRequestMode eMode
= bRetry
? task::PasswordRequestMode_PASSWORD_REENTER
: task::PasswordRequestMode_PASSWORD_ENTER
;
101 ::comphelper::DocPasswordRequest
* pPasswordRequest
= new ::comphelper::DocPasswordRequest(
102 ::comphelper::DocPasswordRequestType_STANDARD
, eMode
, OUString::createFromAscii(PK11_GetTokenName(pSlot
)) );
104 uno::Reference
< task::XInteractionRequest
> xRequest( pPasswordRequest
);
105 xInteractionHandler
->handle( xRequest
);
107 if ( pPasswordRequest
->isPassword() )
109 OString
aPassword(OUStringToOString(
110 pPasswordRequest
->getPassword(),
111 osl_getThreadTextEncoding()));
112 sal_Int32 nLen
= aPassword
.getLength();
113 char* pPassword
= (char*) PORT_Alloc( nLen
+1 ) ;
115 memcpy( pPassword
, aPassword
.getStr(), nLen
);
121 SecurityEnvironment_NssImpl :: SecurityEnvironment_NssImpl( const Reference
< XMultiServiceFactory
>& ) :
122 m_pHandler( NULL
) , m_tSymKeyList() , m_tPubKeyList() , m_tPriKeyList() {
124 PK11_SetPasswordFunc( GetPasswordFunction
) ;
127 SecurityEnvironment_NssImpl :: ~SecurityEnvironment_NssImpl() {
129 PK11_SetPasswordFunc( NULL
) ;
131 for (CIT_SLOTS i
= m_Slots
.begin(); i
!= m_Slots
.end(); i
++)
136 if( !m_tSymKeyList
.empty() ) {
137 std::list
< PK11SymKey
* >::iterator symKeyIt
;
139 for( symKeyIt
= m_tSymKeyList
.begin() ; symKeyIt
!= m_tSymKeyList
.end() ; ++symKeyIt
)
140 PK11_FreeSymKey( *symKeyIt
) ;
143 if( !m_tPubKeyList
.empty() ) {
144 std::list
< SECKEYPublicKey
* >::iterator pubKeyIt
;
146 for( pubKeyIt
= m_tPubKeyList
.begin() ; pubKeyIt
!= m_tPubKeyList
.end() ; ++pubKeyIt
)
147 SECKEY_DestroyPublicKey( *pubKeyIt
) ;
150 if( !m_tPriKeyList
.empty() ) {
151 std::list
< SECKEYPrivateKey
* >::iterator priKeyIt
;
153 for( priKeyIt
= m_tPriKeyList
.begin() ; priKeyIt
!= m_tPriKeyList
.end() ; ++priKeyIt
)
154 SECKEY_DestroyPrivateKey( *priKeyIt
) ;
158 /* XInitialization */
159 void SAL_CALL
SecurityEnvironment_NssImpl :: initialize( const Sequence
< Any
>& ) throw( Exception
, RuntimeException
) {
164 OUString SAL_CALL
SecurityEnvironment_NssImpl :: getImplementationName() throw( RuntimeException
) {
165 return impl_getImplementationName() ;
169 sal_Bool SAL_CALL
SecurityEnvironment_NssImpl :: supportsService( const OUString
& serviceName
) throw( RuntimeException
) {
170 Sequence
< OUString
> seqServiceNames
= getSupportedServiceNames() ;
171 const OUString
* pArray
= seqServiceNames
.getConstArray() ;
172 for( sal_Int32 i
= 0 ; i
< seqServiceNames
.getLength() ; i
++ ) {
173 if( *( pArray
+ i
) == serviceName
)
180 Sequence
< OUString
> SAL_CALL
SecurityEnvironment_NssImpl :: getSupportedServiceNames() throw( RuntimeException
) {
181 return impl_getSupportedServiceNames() ;
184 //Helper for XServiceInfo
185 Sequence
< OUString
> SecurityEnvironment_NssImpl :: impl_getSupportedServiceNames() {
186 ::osl::Guard
< ::osl::Mutex
> aGuard( ::osl::Mutex::getGlobalMutex() ) ;
187 Sequence
< OUString
> seqServiceNames( 1 ) ;
188 seqServiceNames
.getArray()[0] = OUString("com.sun.star.xml.crypto.SecurityEnvironment") ;
189 return seqServiceNames
;
192 OUString
SecurityEnvironment_NssImpl :: impl_getImplementationName() throw( RuntimeException
) {
193 return OUString("com.sun.star.xml.security.bridge.xmlsec.SecurityEnvironment_NssImpl") ;
196 //Helper for registry
197 Reference
< XInterface
> SAL_CALL
SecurityEnvironment_NssImpl :: impl_createInstance( const Reference
< XMultiServiceFactory
>& aServiceManager
) throw( RuntimeException
) {
198 return Reference
< XInterface
>( *new SecurityEnvironment_NssImpl( aServiceManager
) ) ;
201 Reference
< XSingleServiceFactory
> SecurityEnvironment_NssImpl :: impl_createFactory( const Reference
< XMultiServiceFactory
>& aServiceManager
) {
202 return ::cppu::createSingleFactory( aServiceManager
, impl_getImplementationName() , impl_createInstance
, impl_getSupportedServiceNames() ) ;
206 sal_Int64 SAL_CALL
SecurityEnvironment_NssImpl :: getSomething( const Sequence
< sal_Int8
>& aIdentifier
)
207 throw( RuntimeException
)
209 if( aIdentifier
.getLength() == 16 && 0 == memcmp( getUnoTunnelId().getConstArray(), aIdentifier
.getConstArray(), 16 ) ) {
210 return sal::static_int_cast
<sal_Int64
>(reinterpret_cast<sal_uIntPtr
>(this));
215 /* XUnoTunnel extension */
219 class theSecurityEnvironment_NssImplUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theSecurityEnvironment_NssImplUnoTunnelId
> {};
222 const Sequence
< sal_Int8
>& SecurityEnvironment_NssImpl :: getUnoTunnelId() {
223 return theSecurityEnvironment_NssImplUnoTunnelId::get().getSeq();
226 OUString
SecurityEnvironment_NssImpl::getSecurityEnvironmentInformation() throw( ::com::sun::star::uno::RuntimeException
)
229 for (CIT_SLOTS is
= m_Slots
.begin(); is
!= m_Slots
.end(); is
++)
231 buff
.append(OUString::createFromAscii(PK11_GetTokenName(*is
)));
232 buff
.appendAscii("\n");
234 return buff
.makeStringAndClear();
237 void SecurityEnvironment_NssImpl::addCryptoSlot( PK11SlotInfo
* aSlot
) throw( Exception
, RuntimeException
)
239 PK11_ReferenceSlot(aSlot
);
240 m_Slots
.push_back(aSlot
);
243 CERTCertDBHandle
* SecurityEnvironment_NssImpl :: getCertDb() throw( Exception
, RuntimeException
) {
247 //Could we have multiple cert dbs?
248 void SecurityEnvironment_NssImpl :: setCertDb( CERTCertDBHandle
* aCertDb
) throw( Exception
, RuntimeException
) {
249 m_pHandler
= aCertDb
;
252 void SecurityEnvironment_NssImpl :: adoptSymKey( PK11SymKey
* aSymKey
) throw( Exception
, RuntimeException
) {
254 std::list
< PK11SymKey
* >::iterator keyIt
;
256 if( aSymKey
!= NULL
) {
257 //First try to find the key in the list
258 for( keyIt
= m_tSymKeyList
.begin() ; keyIt
!= m_tSymKeyList
.end() ; ++keyIt
) {
259 if( *keyIt
== aSymKey
)
263 //If we do not find the key in the list, add a new node
264 symkey
= PK11_ReferenceSymKey( aSymKey
) ;
266 throw RuntimeException() ;
269 m_tSymKeyList
.push_back( symkey
) ;
270 } catch ( Exception
& ) {
271 PK11_FreeSymKey( symkey
) ;
276 void SecurityEnvironment_NssImpl :: rejectSymKey( PK11SymKey
* aSymKey
) throw( Exception
, RuntimeException
) {
278 std::list
< PK11SymKey
* >::iterator keyIt
;
280 if( aSymKey
!= NULL
) {
281 for( keyIt
= m_tSymKeyList
.begin() ; keyIt
!= m_tSymKeyList
.end() ; ++keyIt
) {
282 if( *keyIt
== aSymKey
) {
284 PK11_FreeSymKey( symkey
) ;
285 m_tSymKeyList
.erase( keyIt
) ;
292 PK11SymKey
* SecurityEnvironment_NssImpl :: getSymKey( unsigned int position
) throw( Exception
, RuntimeException
) {
294 std::list
< PK11SymKey
* >::iterator keyIt
;
298 for( pos
= 0, keyIt
= m_tSymKeyList
.begin() ; pos
< position
&& keyIt
!= m_tSymKeyList
.end() ; pos
++ , keyIt
++ ) ;
300 if( pos
== position
&& keyIt
!= m_tSymKeyList
.end() )
306 void SecurityEnvironment_NssImpl :: adoptPubKey( SECKEYPublicKey
* aPubKey
) throw( Exception
, RuntimeException
) {
307 SECKEYPublicKey
* pubkey
;
308 std::list
< SECKEYPublicKey
* >::iterator keyIt
;
310 if( aPubKey
!= NULL
) {
311 //First try to find the key in the list
312 for( keyIt
= m_tPubKeyList
.begin() ; keyIt
!= m_tPubKeyList
.end() ; ++keyIt
) {
313 if( *keyIt
== aPubKey
)
317 //If we do not find the key in the list, add a new node
318 pubkey
= SECKEY_CopyPublicKey( aPubKey
) ;
320 throw RuntimeException() ;
323 m_tPubKeyList
.push_back( pubkey
) ;
324 } catch ( Exception
& ) {
325 SECKEY_DestroyPublicKey( pubkey
) ;
330 void SecurityEnvironment_NssImpl :: rejectPubKey( SECKEYPublicKey
* aPubKey
) throw( Exception
, RuntimeException
) {
331 SECKEYPublicKey
* pubkey
;
332 std::list
< SECKEYPublicKey
* >::iterator keyIt
;
334 if( aPubKey
!= NULL
) {
335 for( keyIt
= m_tPubKeyList
.begin() ; keyIt
!= m_tPubKeyList
.end() ; ++keyIt
) {
336 if( *keyIt
== aPubKey
) {
338 SECKEY_DestroyPublicKey( pubkey
) ;
339 m_tPubKeyList
.erase( keyIt
) ;
346 SECKEYPublicKey
* SecurityEnvironment_NssImpl :: getPubKey( unsigned int position
) throw( Exception
, RuntimeException
) {
347 SECKEYPublicKey
* pubkey
;
348 std::list
< SECKEYPublicKey
* >::iterator keyIt
;
352 for( pos
= 0, keyIt
= m_tPubKeyList
.begin() ; pos
< position
&& keyIt
!= m_tPubKeyList
.end() ; pos
++ , keyIt
++ ) ;
354 if( pos
== position
&& keyIt
!= m_tPubKeyList
.end() )
360 void SecurityEnvironment_NssImpl :: adoptPriKey( SECKEYPrivateKey
* aPriKey
) throw( Exception
, RuntimeException
) {
361 SECKEYPrivateKey
* prikey
;
362 std::list
< SECKEYPrivateKey
* >::iterator keyIt
;
364 if( aPriKey
!= NULL
) {
365 //First try to find the key in the list
366 for( keyIt
= m_tPriKeyList
.begin() ; keyIt
!= m_tPriKeyList
.end() ; ++keyIt
) {
367 if( *keyIt
== aPriKey
)
371 //If we do not find the key in the list, add a new node
372 prikey
= SECKEY_CopyPrivateKey( aPriKey
) ;
374 throw RuntimeException() ;
377 m_tPriKeyList
.push_back( prikey
) ;
378 } catch ( Exception
& ) {
379 SECKEY_DestroyPrivateKey( prikey
) ;
384 void SecurityEnvironment_NssImpl :: rejectPriKey( SECKEYPrivateKey
* aPriKey
) throw( Exception
, RuntimeException
) {
385 SECKEYPrivateKey
* prikey
;
386 std::list
< SECKEYPrivateKey
* >::iterator keyIt
;
388 if( aPriKey
!= NULL
) {
389 for( keyIt
= m_tPriKeyList
.begin() ; keyIt
!= m_tPriKeyList
.end() ; ++keyIt
) {
390 if( *keyIt
== aPriKey
) {
392 SECKEY_DestroyPrivateKey( prikey
) ;
393 m_tPriKeyList
.erase( keyIt
) ;
400 SECKEYPrivateKey
* SecurityEnvironment_NssImpl :: getPriKey( unsigned int position
) throw( ::com::sun::star::uno::Exception
, ::com::sun::star::uno::RuntimeException
) {
401 SECKEYPrivateKey
* prikey
;
402 std::list
< SECKEYPrivateKey
* >::iterator keyIt
;
406 for( pos
= 0, keyIt
= m_tPriKeyList
.begin() ; pos
< position
&& keyIt
!= m_tPriKeyList
.end() ; pos
++ , keyIt
++ ) ;
408 if( pos
== position
&& keyIt
!= m_tPriKeyList
.end() )
414 void SecurityEnvironment_NssImpl::updateSlots()
416 //In case new tokens are present then we can obtain the corresponding slot
417 PK11SlotList
* soltList
= NULL
;
418 PK11SlotListElement
* soltEle
= NULL
;
419 PK11SlotInfo
* pSlot
= NULL
;
420 PK11SymKey
* pSymKey
= NULL
;
422 osl::MutexGuard
guard(m_mutex
);
425 m_tSymKeyList
.clear();
427 soltList
= PK11_GetAllTokens( CKM_INVALID_MECHANISM
, PR_FALSE
, PR_FALSE
, NULL
) ;
428 if( soltList
!= NULL
)
430 for( soltEle
= soltList
->head
; soltEle
!= NULL
; soltEle
= soltEle
->next
)
432 pSlot
= soltEle
->slot
;
437 "xmlsecurity.xmlsec",
438 "Found a slot: SlotName=" << PK11_GetSlotName(pSlot
)
439 << ", TokenName=" << PK11_GetTokenName(pSlot
));
441 //The following code which is commented out checks if a slot, that is a smart card for example, is
442 // able to generate a symmetric key of type CKM_DES3_CBC. If this fails then this token
443 // will not be used. This key is possibly used for the encryption service. However, all
444 // interfaces and services used for public key signature and encryption are not published
445 // and the encryption is not used in OOo. Therefore it does not do any harm to remove
446 // this code, hence allowing smart cards which cannot generate this type of key.
448 // By doing this, the encryption may fail if a smart card is being used which does not
449 // support this key generation.
451 pSymKey
= PK11_KeyGen( pSlot
, CKM_DES3_CBC
, NULL
, 128, NULL
) ;
452 // if( pSymKey == NULL )
454 // PK11_FreeSlot( pSlot ) ;
455 // RTL_LOGFILE_TRACE( "XMLSEC: Error - pSymKey is NULL" );
458 addCryptoSlot(pSlot
);
459 PK11_FreeSlot( pSlot
) ;
464 adoptSymKey( pSymKey
) ;
465 PK11_FreeSymKey( pSymKey
) ;
469 }// end of if(pSlot != NULL)
471 }// end of if( soltList != NULL )
476 Sequence
< Reference
< XCertificate
> >
477 SecurityEnvironment_NssImpl::getPersonalCertificates() throw( SecurityException
, RuntimeException
)
480 X509Certificate_NssImpl
* xcert
;
481 std::list
< X509Certificate_NssImpl
* > certsList
;
484 //firstly, we try to find private keys in slot
485 for (CIT_SLOTS is
= m_Slots
.begin(); is
!= m_Slots
.end(); is
++)
487 PK11SlotInfo
*slot
= *is
;
488 SECKEYPrivateKeyList
* priKeyList
;
489 SECKEYPrivateKeyListNode
* curPri
;
491 if( PK11_NeedLogin(slot
) ) {
492 SECStatus nRet
= PK11_Authenticate(slot
, PR_TRUE
, NULL
);
493 //PK11_Authenticate may fail in case the a slot has not been initialized.
494 //this is the case if the user has a new profile, so that they have never
495 //added a personal certificate.
496 if( nRet
!= SECSuccess
&& PORT_GetError() != SEC_ERROR_IO
) {
497 throw NoPasswordException();
501 priKeyList
= PK11_ListPrivateKeysInSlot(slot
) ;
502 if( priKeyList
!= NULL
)
504 for( curPri
= PRIVKEY_LIST_HEAD( priKeyList
);
505 !PRIVKEY_LIST_END( curPri
, priKeyList
) && curPri
!= NULL
;
506 curPri
= PRIVKEY_LIST_NEXT( curPri
) )
508 xcert
= NssPrivKeyToXCert( curPri
->key
) ;
510 certsList
.push_back( xcert
) ;
512 SECKEY_DestroyPrivateKeyList( priKeyList
) ;
518 //secondly, we try to find certificate from registered private keys.
519 if( !m_tPriKeyList
.empty() ) {
520 std::list
< SECKEYPrivateKey
* >::iterator priKeyIt
;
522 for( priKeyIt
= m_tPriKeyList
.begin() ; priKeyIt
!= m_tPriKeyList
.end() ; ++priKeyIt
) {
523 xcert
= NssPrivKeyToXCert( *priKeyIt
) ;
525 certsList
.push_back( xcert
) ;
529 length
= certsList
.size() ;
532 std::list
< X509Certificate_NssImpl
* >::iterator xcertIt
;
533 Sequence
< Reference
< XCertificate
> > certSeq( length
) ;
535 for( i
= 0, xcertIt
= certsList
.begin(); xcertIt
!= certsList
.end(); ++xcertIt
, ++i
) {
536 certSeq
[i
] = *xcertIt
;
542 return Sequence
< Reference
< XCertificate
> > ();
545 Reference
< XCertificate
> SecurityEnvironment_NssImpl :: getCertificate( const OUString
& issuerName
, const Sequence
< sal_Int8
>& serialNumber
) throw( SecurityException
, RuntimeException
)
547 X509Certificate_NssImpl
* xcert
= NULL
;
549 if( m_pHandler
!= NULL
) {
550 CERTIssuerAndSN issuerAndSN
;
551 CERTCertificate
* cert
;
557 arena
= PORT_NewArena( DER_DEFAULT_CHUNKSIZE
) ;
559 throw RuntimeException() ;
561 // Create cert info from issue and serial
562 OString ostr
= OUStringToOString( issuerName
, RTL_TEXTENCODING_UTF8
) ;
563 chIssuer
= PL_strndup( ( char* )ostr
.getStr(), ( int )ostr
.getLength() ) ;
564 nmIssuer
= CERT_AsciiToName( chIssuer
) ;
565 if( nmIssuer
== NULL
) {
566 PL_strfree( chIssuer
) ;
567 PORT_FreeArena( arena
, PR_FALSE
) ;
568 return NULL
; // no need for exception cf. i40394
571 derIssuer
= SEC_ASN1EncodeItem( arena
, NULL
, ( void* )nmIssuer
, SEC_ASN1_GET( CERT_NameTemplate
) ) ;
572 if( derIssuer
== NULL
) {
573 PL_strfree( chIssuer
) ;
574 CERT_DestroyName( nmIssuer
) ;
575 PORT_FreeArena( arena
, PR_FALSE
) ;
576 throw RuntimeException() ;
579 memset( &issuerAndSN
, 0, sizeof( issuerAndSN
) ) ;
581 issuerAndSN
.derIssuer
.data
= derIssuer
->data
;
582 issuerAndSN
.derIssuer
.len
= derIssuer
->len
;
584 issuerAndSN
.serialNumber
.data
= ( unsigned char* )&serialNumber
[0] ;
585 issuerAndSN
.serialNumber
.len
= serialNumber
.getLength() ;
587 cert
= CERT_FindCertByIssuerAndSN( m_pHandler
, &issuerAndSN
) ;
589 xcert
= NssCertToXCert( cert
) ;
594 PL_strfree( chIssuer
) ;
595 CERT_DestroyName( nmIssuer
) ;
596 //SECITEM_FreeItem( derIssuer, PR_FALSE ) ;
597 CERT_DestroyCertificate( cert
) ;
598 PORT_FreeArena( arena
, PR_FALSE
) ;
606 Reference
< XCertificate
> SecurityEnvironment_NssImpl :: getCertificate( const OUString
& issuerName
, const OUString
& serialNumber
) throw( SecurityException
, RuntimeException
) {
607 Sequence
< sal_Int8
> serial
= numericStringToBigInteger( serialNumber
) ;
608 return getCertificate( issuerName
, serial
) ;
611 Sequence
< Reference
< XCertificate
> > SecurityEnvironment_NssImpl :: buildCertificatePath( const Reference
< XCertificate
>& begin
) throw( SecurityException
, RuntimeException
) {
612 const X509Certificate_NssImpl
* xcert
;
613 const CERTCertificate
* cert
;
614 CERTCertList
* certChain
;
616 Reference
< XUnoTunnel
> xCertTunnel( begin
, UNO_QUERY
) ;
617 if( !xCertTunnel
.is() ) {
618 throw RuntimeException() ;
621 xcert
= reinterpret_cast<X509Certificate_NssImpl
*>(
622 sal::static_int_cast
<sal_uIntPtr
>(xCertTunnel
->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
623 if( xcert
== NULL
) {
624 throw RuntimeException() ;
627 cert
= xcert
->getNssCert() ;
631 //Get the system clock time
632 timeboundary
= PR_Now() ;
634 certChain
= CERT_GetCertChainFromCert( ( CERTCertificate
* )cert
, timeboundary
, certUsageAnyCA
) ;
639 if( certChain
!= NULL
) {
640 X509Certificate_NssImpl
* pCert
;
641 CERTCertListNode
* node
;
644 for( len
= 0, node
= CERT_LIST_HEAD( certChain
); !CERT_LIST_END( node
, certChain
); node
= CERT_LIST_NEXT( node
), len
++ ) ;
645 Sequence
< Reference
< XCertificate
> > xCertChain( len
) ;
647 for( len
= 0, node
= CERT_LIST_HEAD( certChain
); !CERT_LIST_END( node
, certChain
); node
= CERT_LIST_NEXT( node
), len
++ ) {
648 pCert
= new X509Certificate_NssImpl() ;
649 if( pCert
== NULL
) {
650 CERT_DestroyCertList( certChain
) ;
651 throw RuntimeException() ;
654 pCert
->setCert( node
->cert
) ;
656 xCertChain
[len
] = pCert
;
659 CERT_DestroyCertList( certChain
) ;
664 return Sequence
< Reference
< XCertificate
> >();
667 Reference
< XCertificate
> SecurityEnvironment_NssImpl :: createCertificateFromRaw( const Sequence
< sal_Int8
>& rawCertificate
) throw( SecurityException
, RuntimeException
) {
668 X509Certificate_NssImpl
* xcert
;
670 if( rawCertificate
.getLength() > 0 ) {
671 xcert
= new X509Certificate_NssImpl() ;
673 throw RuntimeException() ;
675 xcert
->setRawCert( rawCertificate
) ;
683 Reference
< XCertificate
> SecurityEnvironment_NssImpl :: createCertificateFromAscii( const OUString
& asciiCertificate
) throw( SecurityException
, RuntimeException
)
686 xmlSecSize certSize
;
688 OString oscert
= OUStringToOString( asciiCertificate
, RTL_TEXTENCODING_ASCII_US
) ;
690 chCert
= xmlStrndup( ( const xmlChar
* )oscert
.getStr(), ( int )oscert
.getLength() ) ;
692 certSize
= xmlSecBase64Decode( chCert
, ( xmlSecByte
* )chCert
, xmlStrlen( chCert
) ) ;
696 Sequence
< sal_Int8
> rawCert( certSize
) ;
697 for( unsigned int i
= 0 ; i
< certSize
; i
++ )
698 rawCert
[i
] = *( chCert
+ i
) ;
702 return createCertificateFromRaw( rawCert
) ;
710 sal_Int32
SecurityEnvironment_NssImpl ::
711 verifyCertificate( const Reference
< csss::XCertificate
>& aCert
,
712 const Sequence
< Reference
< csss::XCertificate
> >& intermediateCerts
)
713 throw( ::com::sun::star::uno::SecurityException
, ::com::sun::star::uno::RuntimeException
)
715 sal_Int32 validity
= csss::CertificateValidity::INVALID
;
716 const X509Certificate_NssImpl
* xcert
;
717 const CERTCertificate
* cert
;
718 ::std::vector
<CERTCertificate
*> vecTmpNSSCertificates
;
719 Reference
< XUnoTunnel
> xCertTunnel( aCert
, UNO_QUERY
) ;
720 if( !xCertTunnel
.is() ) {
721 throw RuntimeException() ;
724 xmlsec_trace("Start verification of certificate: \n %s \n",
726 aCert
->getSubjectName(), osl_getThreadTextEncoding()).getStr());
728 xcert
= reinterpret_cast<X509Certificate_NssImpl
*>(
729 sal::static_int_cast
<sal_uIntPtr
>(xCertTunnel
->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
730 if( xcert
== NULL
) {
731 throw RuntimeException() ;
734 //CERT_PKIXVerifyCert does not take a db as argument. It will therefore
735 //internally use CERT_GetDefaultCertDB
736 //Make sure m_pHandler is the default DB
737 OSL_ASSERT(m_pHandler
== CERT_GetDefaultCertDB());
738 CERTCertDBHandle
* certDb
= m_pHandler
!= NULL
? m_pHandler
: CERT_GetDefaultCertDB();
739 cert
= xcert
->getNssCert() ;
743 //prepare the intermediate certificates
744 for (sal_Int32 i
= 0; i
< intermediateCerts
.getLength(); i
++)
746 Sequence
<sal_Int8
> der
= intermediateCerts
[i
]->getEncoded();
748 item
.type
= siBuffer
;
749 item
.data
= (unsigned char*)der
.getArray();
750 item
.len
= der
.getLength();
752 CERTCertificate
* certTmp
= CERT_NewTempCertificate(certDb
, &item
,
754 PR_FALSE
/* isPerm */,
755 PR_TRUE
/* copyDER */);
758 xmlsec_trace("Failed to add a temporary certificate: %s",
759 OUStringToOString(intermediateCerts
[i
]->getIssuerName(),
760 osl_getThreadTextEncoding()).getStr());
765 xmlsec_trace("Added temporary certificate: %s",
766 certTmp
->subjectName
? certTmp
->subjectName
: "");
767 vecTmpNSSCertificates
.push_back(certTmp
);
775 log
.arena
= PORT_NewArena(512);
776 log
.head
= log
.tail
= NULL
;
779 CERT_EnableOCSPChecking(certDb
);
780 CERT_DisableOCSPDefaultResponder(certDb
);
781 CERTValOutParam cvout
[5];
782 CERTValInParam cvin
[3];
785 #if ( NSS_VMAJOR > 3 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR > 12 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH > 0 )
786 cvin
[ncvinCount
].type
= cert_pi_useAIACertFetch
;
787 cvin
[ncvinCount
].value
.scalar
.b
= PR_TRUE
;
791 PRUint64 revFlagsLeaf
[2];
792 PRUint64 revFlagsChain
[2];
793 CERTRevocationFlags rev
;
794 rev
.leafTests
.number_of_defined_methods
= 2;
795 rev
.leafTests
.cert_rev_flags_per_method
= revFlagsLeaf
;
796 //the flags are defined in cert.h
797 //We check both leaf and chain.
798 //It is enough if one revocation method has fresh info,
799 //but at least one must have some. Otherwise validation fails.
800 //!!! using leaf test and CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE
801 // when validating a root certificate will result in "revoked". Usually
802 //there is no revocation information available for the root cert because
803 //it must be trusted anyway and it does itself issue revocation information.
804 //When we use the flag here and OOo shows the certification path then the root
805 //cert is invalid while all other can be valid. It would probably best if
806 //this interface method returned the whole chain.
807 //Otherwise we need to check if the certificate is self-signed and if it is
808 //then not use the flag when doing the leaf-test.
809 rev
.leafTests
.cert_rev_flags_per_method
[cert_revocation_method_crl
] =
810 CERT_REV_M_TEST_USING_THIS_METHOD
811 | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE
;
812 rev
.leafTests
.cert_rev_flags_per_method
[cert_revocation_method_ocsp
] =
813 CERT_REV_M_TEST_USING_THIS_METHOD
814 | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE
;
815 rev
.leafTests
.number_of_preferred_methods
= 0;
816 rev
.leafTests
.preferred_methods
= NULL
;
817 rev
.leafTests
.cert_rev_method_independent_flags
=
818 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
;
820 rev
.chainTests
.number_of_defined_methods
= 2;
821 rev
.chainTests
.cert_rev_flags_per_method
= revFlagsChain
;
822 rev
.chainTests
.cert_rev_flags_per_method
[cert_revocation_method_crl
] =
823 CERT_REV_M_TEST_USING_THIS_METHOD
824 | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE
;
825 rev
.chainTests
.cert_rev_flags_per_method
[cert_revocation_method_ocsp
] =
826 CERT_REV_M_TEST_USING_THIS_METHOD
827 | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE
;
828 rev
.chainTests
.number_of_preferred_methods
= 0;
829 rev
.chainTests
.preferred_methods
= NULL
;
830 rev
.chainTests
.cert_rev_method_independent_flags
=
831 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
;
834 cvin
[ncvinCount
].type
= cert_pi_revocationFlags
;
835 cvin
[ncvinCount
].value
.pointer
.revocation
= &rev
;
837 // does not work, not implemented yet in 3.12.4
838 // cvin[ncvinCount].type = cert_pi_keyusage;
839 // cvin[ncvinCount].value.scalar.ui = KU_DIGITAL_SIGNATURE;
841 cvin
[ncvinCount
].type
= cert_pi_end
;
843 cvout
[0].type
= cert_po_trustAnchor
;
844 cvout
[0].value
.pointer
.cert
= NULL
;
845 cvout
[1].type
= cert_po_errorLog
;
846 cvout
[1].value
.pointer
.log
= &log
;
847 cvout
[2].type
= cert_po_end
;
849 // We check SSL server certificates, CA certificates and signing sertificates.
851 // ToDo check keyusage, looking at CERT_KeyUsageAndTypeForCertUsage (
852 // mozilla/security/nss/lib/certdb/certdb.c indicates that
853 // certificateUsageSSLClient, certificateUsageSSLServer and certificateUsageSSLCA
854 // are sufficient. They cover the key usages for digital signature, key agreement
855 // and encipherment and certificate signature
857 //never use the following usages because they are not checked properly
858 // certificateUsageUserCertImport
859 // certificateUsageVerifyCA
860 // certificateUsageAnyCA
861 // certificateUsageProtectedObjectSigner
863 UsageDescription arUsages
[5];
864 arUsages
[0] = UsageDescription( certificateUsageSSLClient
, "certificateUsageSSLClient" );
865 arUsages
[1] = UsageDescription( certificateUsageSSLServer
, "certificateUsageSSLServer" );
866 arUsages
[2] = UsageDescription( certificateUsageSSLCA
, "certificateUsageSSLCA" );
867 arUsages
[3] = UsageDescription( certificateUsageEmailSigner
, "certificateUsageEmailSigner" );
868 arUsages
[4] = UsageDescription( certificateUsageEmailRecipient
, "certificateUsageEmailRecipient" );
870 int numUsages
= SAL_N_ELEMENTS(arUsages
);
871 for (int i
= 0; i
< numUsages
; i
++)
873 xmlsec_trace("Testing usage %d of %d: %s (0x%x)", i
+ 1,
874 numUsages
, arUsages
[i
].description
, (int) arUsages
[i
].usage
);
876 status
= CERT_PKIXVerifyCert(const_cast<CERTCertificate
*>(cert
), arUsages
[i
].usage
,
878 if( status
== SECSuccess
)
880 xmlsec_trace("CERT_PKIXVerifyCert returned SECSuccess.");
881 //When an intermediate or root certificate is checked then we expect the usage
882 //certificateUsageSSLCA. This, however, will be only set when in the trust settings dialog
883 //the button "This certificate can identify websites" is checked. If for example only
884 //"This certificate can identify mail users" is set then the end certificate can
885 //be validated and the returned usage will conain certificateUsageEmailRecipient.
886 //But checking directly the root or intermediate certificate will fail. In the
887 //certificate path view the end certificate will be shown as valid but the others
888 //will be displayed as invalid.
890 validity
= csss::CertificateValidity::VALID
;
891 xmlsec_trace("Certificate is valid.\n");
892 CERTCertificate
* issuerCert
= cvout
[0].value
.pointer
.cert
;
895 xmlsec_trace("Root certificate: %s", issuerCert
->subjectName
);
896 CERT_DestroyCertificate(issuerCert
);
903 PRIntn err
= PR_GetError();
904 xmlsec_trace("Error: , %d = %s", err
, getCertError(err
));
906 /* Display validation results */
909 CERTVerifyLogNode
*node
= NULL
;
910 printChainFailure(&log
);
912 for (node
= log
.head
; node
; node
= node
->next
) {
914 CERT_DestroyCertificate(node
->cert
);
916 log
.head
= log
.tail
= NULL
;
919 xmlsec_trace("Certificate is invalid.\n");
926 validity
= ::com::sun::star::security::CertificateValidity::INVALID
;
929 //Destroying the temporary certificates
930 std::vector
<CERTCertificate
*>::const_iterator cert_i
;
931 for (cert_i
= vecTmpNSSCertificates
.begin(); cert_i
!= vecTmpNSSCertificates
.end(); ++cert_i
)
933 xmlsec_trace("Destroying temporary certificate");
934 CERT_DestroyCertificate(*cert_i
);
939 sal_Int32
SecurityEnvironment_NssImpl::getCertificateCharacters(
940 const ::com::sun::star::uno::Reference
< ::com::sun::star::security::XCertificate
>& aCert
) throw( ::com::sun::star::uno::SecurityException
, ::com::sun::star::uno::RuntimeException
) {
941 sal_Int32 characters
;
942 const X509Certificate_NssImpl
* xcert
;
943 const CERTCertificate
* cert
;
945 Reference
< XUnoTunnel
> xCertTunnel( aCert
, UNO_QUERY
) ;
946 if( !xCertTunnel
.is() ) {
947 throw RuntimeException() ;
950 xcert
= reinterpret_cast<X509Certificate_NssImpl
*>(
951 sal::static_int_cast
<sal_uIntPtr
>(xCertTunnel
->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
952 if( xcert
== NULL
) {
953 throw RuntimeException() ;
956 cert
= xcert
->getNssCert() ;
958 characters
= 0x00000000 ;
960 //Firstly, find out whether or not the cert is self-signed.
961 if( SECITEM_CompareItem( &(cert
->derIssuer
), &(cert
->derSubject
) ) == SECEqual
) {
962 characters
|= ::com::sun::star::security::CertificateCharacters::SELF_SIGNED
;
964 characters
&= ~ ::com::sun::star::security::CertificateCharacters::SELF_SIGNED
;
967 //Secondly, find out whether or not the cert has a private key.
972 * mmi : need to check whether the cert's slot is valid first
974 SECKEYPrivateKey
* priKey
= NULL
;
976 if (cert
->slot
!= NULL
)
978 priKey
= PK11_FindPrivateKeyFromCert( cert
->slot
, ( CERTCertificate
* )cert
, NULL
) ;
982 for (CIT_SLOTS is
= m_Slots
.begin(); is
!= m_Slots
.end(); is
++)
984 priKey
= PK11_FindPrivateKeyFromCert(*is
, (CERTCertificate
*)cert
, NULL
);
989 if( priKey
!= NULL
) {
990 characters
|= ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY
;
992 SECKEY_DestroyPrivateKey( priKey
) ;
994 characters
&= ~ ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY
;
1000 X509Certificate_NssImpl
* NssCertToXCert( CERTCertificate
* cert
)
1002 X509Certificate_NssImpl
* xcert
;
1004 if( cert
!= NULL
) {
1005 xcert
= new X509Certificate_NssImpl() ;
1006 if( xcert
== NULL
) {
1009 xcert
->setCert( cert
) ;
1018 X509Certificate_NssImpl
* NssPrivKeyToXCert( SECKEYPrivateKey
* priKey
)
1020 CERTCertificate
* cert
;
1021 X509Certificate_NssImpl
* xcert
;
1023 if( priKey
!= NULL
) {
1024 cert
= PK11_GetCertFromPrivateKey( priKey
) ;
1026 if( cert
!= NULL
) {
1027 xcert
= NssCertToXCert( cert
) ;
1032 CERT_DestroyCertificate( cert
) ;
1041 /* Native methods */
1042 xmlSecKeysMngrPtr
SecurityEnvironment_NssImpl::createKeysManager() throw( Exception
, RuntimeException
) {
1045 CERTCertDBHandle
* handler
= NULL
;
1046 PK11SymKey
* symKey
= NULL
;
1047 SECKEYPublicKey
* pubKey
= NULL
;
1048 SECKEYPrivateKey
* priKey
= NULL
;
1049 xmlSecKeysMngrPtr pKeysMngr
= NULL
;
1051 handler
= this->getCertDb() ;
1054 * The following lines is based on the private version of xmlSec-NSS
1057 int cSlots
= m_Slots
.size();
1058 boost::scoped_array
<PK11SlotInfo
*> sarSlots(new PK11SlotInfo
*[cSlots
]);
1059 PK11SlotInfo
** slots
= sarSlots
.get();
1061 for (CIT_SLOTS islots
= m_Slots
.begin();islots
!= m_Slots
.end(); islots
++, count
++)
1062 slots
[count
] = *islots
;
1064 pKeysMngr
= xmlSecNssAppliedKeysMngrCreate(slots
, cSlots
, handler
) ;
1065 if( pKeysMngr
== NULL
)
1066 throw RuntimeException() ;
1069 * Adopt symmetric key into keys manager
1071 for( i
= 0 ; ( symKey
= this->getSymKey( i
) ) != NULL
; i
++ ) {
1072 if( xmlSecNssAppliedKeysMngrSymKeyLoad( pKeysMngr
, symKey
) < 0 ) {
1073 throw RuntimeException() ;
1078 * Adopt asymmetric public key into keys manager
1080 for( i
= 0 ; ( pubKey
= this->getPubKey( i
) ) != NULL
; i
++ ) {
1081 if( xmlSecNssAppliedKeysMngrPubKeyLoad( pKeysMngr
, pubKey
) < 0 ) {
1082 throw RuntimeException() ;
1087 * Adopt asymmetric private key into keys manager
1089 for( i
= 0 ; ( priKey
= this->getPriKey( i
) ) != NULL
; i
++ ) {
1090 if( xmlSecNssAppliedKeysMngrPriKeyLoad( pKeysMngr
, priKey
) < 0 ) {
1091 throw RuntimeException() ;
1096 void SecurityEnvironment_NssImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr
) throw( Exception
, RuntimeException
) {
1097 if( pKeysMngr
!= NULL
) {
1098 xmlSecKeysMngrDestroy( pKeysMngr
) ;
1102 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */