Line data Source code
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 "nssrenam.h"
21 : #include "cert.h"
22 : #include "secerr.h"
23 : #include "ocsp.h"
24 :
25 : #include <sal/config.h>
26 : #include <sal/macros.h>
27 : #include <osl/diagnose.h>
28 : #include "securityenvironment_nssimpl.hxx"
29 : #include "x509certificate_nssimpl.hxx"
30 : #include <comphelper/servicehelper.hxx>
31 :
32 : #include "xmlsecurity/xmlsec-wrapper.h"
33 :
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>
40 : #include <vector>
41 : #include <boost/scoped_array.hpp>
42 : #include <osl/thread.h>
43 :
44 : #include "secerror.hxx"
45 :
46 : // added for password exception
47 : #include <com/sun/star/security/NoPasswordException.hpp>
48 : namespace csss = ::com::sun::star::security;
49 : using namespace ::com::sun::star::security;
50 : using namespace com::sun::star;
51 : using namespace ::com::sun::star::uno ;
52 : using namespace ::com::sun::star::lang ;
53 : using ::com::sun::star::lang::XMultiServiceFactory ;
54 : using ::com::sun::star::lang::XSingleServiceFactory ;
55 :
56 : using ::com::sun::star::xml::crypto::XSecurityEnvironment ;
57 : using ::com::sun::star::security::XCertificate ;
58 :
59 : extern X509Certificate_NssImpl* NssCertToXCert( CERTCertificate* cert ) ;
60 : extern X509Certificate_NssImpl* NssPrivKeyToXCert( SECKEYPrivateKey* ) ;
61 :
62 :
63 : struct UsageDescription
64 : {
65 : SECCertificateUsage usage;
66 : char const* description;
67 :
68 0 : UsageDescription()
69 : : usage( certificateUsageCheckAllUsages )
70 0 : , description( NULL )
71 0 : {}
72 :
73 0 : UsageDescription( SECCertificateUsage i_usage, char const* i_description )
74 : : usage( i_usage )
75 0 : , description( i_description )
76 0 : {}
77 : };
78 :
79 :
80 :
81 0 : char* GetPasswordFunction( PK11SlotInfo* pSlot, PRBool bRetry, void* /*arg*/ )
82 : {
83 0 : uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
84 : uno::Reference < task::XInteractionHandler2 > xInteractionHandler(
85 0 : task::InteractionHandler::createWithParent(xContext, 0) );
86 :
87 0 : task::PasswordRequestMode eMode = bRetry ? task::PasswordRequestMode_PASSWORD_REENTER : task::PasswordRequestMode_PASSWORD_ENTER;
88 : ::comphelper::DocPasswordRequest* pPasswordRequest = new ::comphelper::DocPasswordRequest(
89 0 : ::comphelper::DocPasswordRequestType_STANDARD, eMode, OUString::createFromAscii(PK11_GetTokenName(pSlot)) );
90 :
91 0 : uno::Reference< task::XInteractionRequest > xRequest( pPasswordRequest );
92 0 : xInteractionHandler->handle( xRequest );
93 :
94 0 : if ( pPasswordRequest->isPassword() )
95 : {
96 : OString aPassword(OUStringToOString(
97 : pPasswordRequest->getPassword(),
98 0 : osl_getThreadTextEncoding()));
99 0 : sal_Int32 nLen = aPassword.getLength();
100 0 : char* pPassword = static_cast<char*>(PORT_Alloc( nLen+1 ) );
101 0 : pPassword[nLen] = 0;
102 0 : memcpy( pPassword, aPassword.getStr(), nLen );
103 0 : return pPassword;
104 : }
105 0 : return NULL;
106 : }
107 :
108 1 : SecurityEnvironment_NssImpl :: SecurityEnvironment_NssImpl() :
109 1 : m_pHandler( NULL ) , m_tSymKeyList() , m_tPubKeyList() , m_tPriKeyList() {
110 :
111 1 : PK11_SetPasswordFunc( GetPasswordFunction ) ;
112 1 : }
113 :
114 3 : SecurityEnvironment_NssImpl :: ~SecurityEnvironment_NssImpl() {
115 :
116 1 : PK11_SetPasswordFunc( NULL ) ;
117 :
118 1 : for (CIT_SLOTS i = m_Slots.begin(); i != m_Slots.end(); i++)
119 : {
120 0 : PK11_FreeSlot(*i);
121 : }
122 :
123 1 : if( !m_tSymKeyList.empty() ) {
124 0 : std::list< PK11SymKey* >::iterator symKeyIt ;
125 :
126 0 : for( symKeyIt = m_tSymKeyList.begin() ; symKeyIt != m_tSymKeyList.end() ; ++symKeyIt )
127 0 : PK11_FreeSymKey( *symKeyIt ) ;
128 : }
129 :
130 1 : if( !m_tPubKeyList.empty() ) {
131 0 : std::list< SECKEYPublicKey* >::iterator pubKeyIt ;
132 :
133 0 : for( pubKeyIt = m_tPubKeyList.begin() ; pubKeyIt != m_tPubKeyList.end() ; ++pubKeyIt )
134 0 : SECKEY_DestroyPublicKey( *pubKeyIt ) ;
135 : }
136 :
137 1 : if( !m_tPriKeyList.empty() ) {
138 0 : std::list< SECKEYPrivateKey* >::iterator priKeyIt ;
139 :
140 0 : for( priKeyIt = m_tPriKeyList.begin() ; priKeyIt != m_tPriKeyList.end() ; ++priKeyIt )
141 0 : SECKEY_DestroyPrivateKey( *priKeyIt ) ;
142 : }
143 2 : }
144 :
145 : /* XServiceInfo */
146 1 : OUString SAL_CALL SecurityEnvironment_NssImpl :: getImplementationName() throw( RuntimeException, std::exception ) {
147 1 : return impl_getImplementationName() ;
148 : }
149 :
150 : /* XServiceInfo */
151 0 : sal_Bool SAL_CALL SecurityEnvironment_NssImpl :: supportsService( const OUString& serviceName) throw( RuntimeException, std::exception ) {
152 0 : Sequence< OUString > seqServiceNames = getSupportedServiceNames() ;
153 0 : const OUString* pArray = seqServiceNames.getConstArray() ;
154 0 : for( sal_Int32 i = 0 ; i < seqServiceNames.getLength() ; i ++ ) {
155 0 : if( *( pArray + i ) == serviceName )
156 0 : return sal_True ;
157 : }
158 0 : return sal_False ;
159 : }
160 :
161 : /* XServiceInfo */
162 1 : Sequence< OUString > SAL_CALL SecurityEnvironment_NssImpl :: getSupportedServiceNames() throw( RuntimeException, std::exception ) {
163 1 : return impl_getSupportedServiceNames() ;
164 : }
165 :
166 : //Helper for XServiceInfo
167 2 : Sequence< OUString > SecurityEnvironment_NssImpl :: impl_getSupportedServiceNames() {
168 2 : ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ;
169 2 : Sequence< OUString > seqServiceNames( 1 ) ;
170 2 : seqServiceNames[0] = "com.sun.star.xml.crypto.SecurityEnvironment";
171 2 : return seqServiceNames ;
172 : }
173 :
174 4 : OUString SecurityEnvironment_NssImpl :: impl_getImplementationName() throw( RuntimeException ) {
175 4 : return OUString("com.sun.star.xml.security.bridge.xmlsec.SecurityEnvironment_NssImpl") ;
176 : }
177 :
178 : //Helper for registry
179 1 : Reference< XInterface > SAL_CALL SecurityEnvironment_NssImpl :: impl_createInstance( const Reference< XMultiServiceFactory >& ) throw( RuntimeException ) {
180 1 : return Reference< XInterface >( *new SecurityEnvironment_NssImpl ) ;
181 : }
182 :
183 1 : Reference< XSingleServiceFactory > SecurityEnvironment_NssImpl :: impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) {
184 1 : return ::cppu::createSingleFactory( aServiceManager , impl_getImplementationName() , impl_createInstance , impl_getSupportedServiceNames() ) ;
185 : }
186 :
187 : /* XUnoTunnel */
188 0 : sal_Int64 SAL_CALL SecurityEnvironment_NssImpl :: getSomething( const Sequence< sal_Int8 >& aIdentifier )
189 : throw( RuntimeException, std::exception )
190 : {
191 0 : if( aIdentifier.getLength() == 16 && 0 == memcmp( getUnoTunnelId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) {
192 0 : return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this));
193 : }
194 0 : return 0 ;
195 : }
196 :
197 : /* XUnoTunnel extension */
198 :
199 : namespace
200 : {
201 : class theSecurityEnvironment_NssImplUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSecurityEnvironment_NssImplUnoTunnelId > {};
202 : }
203 :
204 0 : const Sequence< sal_Int8>& SecurityEnvironment_NssImpl :: getUnoTunnelId() {
205 0 : return theSecurityEnvironment_NssImplUnoTunnelId::get().getSeq();
206 : }
207 :
208 0 : OUString SecurityEnvironment_NssImpl::getSecurityEnvironmentInformation() throw( ::com::sun::star::uno::RuntimeException, std::exception )
209 : {
210 0 : OUStringBuffer buff;
211 0 : for (CIT_SLOTS is = m_Slots.begin(); is != m_Slots.end(); is++)
212 : {
213 0 : buff.append(OUString::createFromAscii(PK11_GetTokenName(*is)));
214 0 : buff.appendAscii("\n");
215 : }
216 0 : return buff.makeStringAndClear();
217 : }
218 :
219 0 : void SecurityEnvironment_NssImpl::addCryptoSlot( PK11SlotInfo* aSlot) throw( Exception , RuntimeException )
220 : {
221 0 : PK11_ReferenceSlot(aSlot);
222 0 : m_Slots.push_back(aSlot);
223 0 : }
224 :
225 0 : CERTCertDBHandle* SecurityEnvironment_NssImpl :: getCertDb() throw( Exception , RuntimeException ) {
226 0 : return m_pHandler ;
227 : }
228 :
229 : //Could we have multiple cert dbs?
230 0 : void SecurityEnvironment_NssImpl :: setCertDb( CERTCertDBHandle* aCertDb ) throw( Exception , RuntimeException ) {
231 0 : m_pHandler = aCertDb ;
232 0 : }
233 :
234 0 : void SecurityEnvironment_NssImpl :: adoptSymKey( PK11SymKey* aSymKey ) throw( Exception , RuntimeException ) {
235 0 : std::list< PK11SymKey* >::iterator keyIt ;
236 :
237 0 : if( aSymKey != NULL ) {
238 : //First try to find the key in the list
239 0 : for( keyIt = m_tSymKeyList.begin() ; keyIt != m_tSymKeyList.end() ; ++keyIt ) {
240 0 : if( *keyIt == aSymKey )
241 0 : return ;
242 : }
243 :
244 : //If we do not find the key in the list, add a new node
245 0 : PK11SymKey* symkey = PK11_ReferenceSymKey( aSymKey ) ;
246 0 : if( symkey == NULL )
247 0 : throw RuntimeException() ;
248 :
249 : try {
250 0 : m_tSymKeyList.push_back( symkey ) ;
251 0 : } catch ( Exception& ) {
252 0 : PK11_FreeSymKey( symkey ) ;
253 : }
254 : }
255 : }
256 :
257 0 : PK11SymKey* SecurityEnvironment_NssImpl :: getSymKey( unsigned int position ) throw( Exception , RuntimeException ) {
258 : PK11SymKey* symkey ;
259 0 : std::list< PK11SymKey* >::iterator keyIt ;
260 : unsigned int pos ;
261 :
262 0 : symkey = NULL ;
263 0 : for( pos = 0, keyIt = m_tSymKeyList.begin() ; pos < position && keyIt != m_tSymKeyList.end() ; pos ++ , ++keyIt ) ;
264 :
265 0 : if( pos == position && keyIt != m_tSymKeyList.end() )
266 0 : symkey = *keyIt ;
267 :
268 0 : return symkey ;
269 : }
270 :
271 0 : SECKEYPublicKey* SecurityEnvironment_NssImpl :: getPubKey( unsigned int position ) throw( Exception , RuntimeException ) {
272 : SECKEYPublicKey* pubkey ;
273 0 : std::list< SECKEYPublicKey* >::iterator keyIt ;
274 : unsigned int pos ;
275 :
276 0 : pubkey = NULL ;
277 0 : for( pos = 0, keyIt = m_tPubKeyList.begin() ; pos < position && keyIt != m_tPubKeyList.end() ; pos ++ , ++keyIt ) ;
278 :
279 0 : if( pos == position && keyIt != m_tPubKeyList.end() )
280 0 : pubkey = *keyIt ;
281 :
282 0 : return pubkey ;
283 : }
284 :
285 0 : SECKEYPrivateKey* SecurityEnvironment_NssImpl :: getPriKey( unsigned int position ) throw( ::com::sun::star::uno::Exception , ::com::sun::star::uno::RuntimeException ) {
286 : SECKEYPrivateKey* prikey ;
287 0 : std::list< SECKEYPrivateKey* >::iterator keyIt ;
288 : unsigned int pos ;
289 :
290 0 : prikey = NULL ;
291 0 : for( pos = 0, keyIt = m_tPriKeyList.begin() ; pos < position && keyIt != m_tPriKeyList.end() ; pos ++ , ++keyIt ) ;
292 :
293 0 : if( pos == position && keyIt != m_tPriKeyList.end() )
294 0 : prikey = *keyIt ;
295 :
296 0 : return prikey ;
297 : }
298 :
299 0 : void SecurityEnvironment_NssImpl::updateSlots()
300 : {
301 : //In case new tokens are present then we can obtain the corresponding slot
302 0 : osl::MutexGuard guard(m_mutex);
303 :
304 0 : m_Slots.clear();
305 0 : m_tSymKeyList.clear();
306 :
307 0 : PK11SlotList * soltList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL ) ;
308 0 : if( soltList != NULL )
309 : {
310 0 : for (PK11SlotListElement* soltEle = soltList->head ; soltEle != NULL; soltEle = soltEle->next)
311 : {
312 0 : PK11SlotInfo * pSlot = soltEle->slot ;
313 :
314 0 : if(pSlot != NULL)
315 : {
316 : SAL_INFO(
317 : "xmlsecurity.xmlsec",
318 : "Found a slot: SlotName=" << PK11_GetSlotName(pSlot)
319 : << ", TokenName=" << PK11_GetTokenName(pSlot));
320 :
321 : //The following code which is commented out checks if a slot, that is a smart card for example, is
322 : // able to generate a symmetric key of type CKM_DES3_CBC. If this fails then this token
323 : // will not be used. This key is possibly used for the encryption service. However, all
324 : // interfaces and services used for public key signature and encryption are not published
325 : // and the encryption is not used in OOo. Therefore it does not do any harm to remove
326 : // this code, hence allowing smart cards which cannot generate this type of key.
327 : //
328 : // By doing this, the encryption may fail if a smart card is being used which does not
329 : // support this key generation.
330 : //
331 0 : PK11SymKey * pSymKey = PK11_KeyGen( pSlot , CKM_DES3_CBC, NULL, 128, NULL ) ;
332 : // if( pSymKey == NULL )
333 : // {
334 : // PK11_FreeSlot( pSlot ) ;
335 : // SAL_INFO( "xmlsecurity", "XMLSEC: Error - pSymKey is NULL" );
336 : // continue;
337 : // }
338 0 : addCryptoSlot(pSlot);
339 0 : PK11_FreeSlot( pSlot ) ;
340 0 : pSlot = NULL;
341 :
342 0 : if (pSymKey != NULL)
343 : {
344 0 : adoptSymKey( pSymKey ) ;
345 0 : PK11_FreeSymKey( pSymKey ) ;
346 0 : pSymKey = NULL;
347 : }
348 :
349 : }// end of if(pSlot != NULL)
350 : }// end of for
351 0 : }// end of if( soltList != NULL )
352 0 : }
353 :
354 : Sequence< Reference < XCertificate > >
355 0 : SecurityEnvironment_NssImpl::getPersonalCertificates() throw( SecurityException , RuntimeException, std::exception )
356 : {
357 : sal_Int32 length ;
358 : X509Certificate_NssImpl* xcert ;
359 0 : std::list< X509Certificate_NssImpl* > certsList ;
360 :
361 0 : updateSlots();
362 : //firstly, we try to find private keys in slot
363 0 : for (CIT_SLOTS is = m_Slots.begin(); is != m_Slots.end(); is++)
364 : {
365 0 : PK11SlotInfo *slot = *is;
366 : SECKEYPrivateKeyList* priKeyList ;
367 :
368 0 : if( PK11_NeedLogin(slot ) ) {
369 0 : SECStatus nRet = PK11_Authenticate(slot, PR_TRUE, NULL);
370 : //PK11_Authenticate may fail in case the a slot has not been initialized.
371 : //this is the case if the user has a new profile, so that they have never
372 : //added a personal certificate.
373 0 : if( nRet != SECSuccess && PORT_GetError() != SEC_ERROR_IO) {
374 0 : throw NoPasswordException();
375 : }
376 : }
377 :
378 0 : priKeyList = PK11_ListPrivateKeysInSlot(slot) ;
379 0 : if( priKeyList != NULL )
380 : {
381 0 : for (SECKEYPrivateKeyListNode* curPri = PRIVKEY_LIST_HEAD(priKeyList);
382 0 : !PRIVKEY_LIST_END( curPri, priKeyList ) && curPri != NULL;
383 : curPri = PRIVKEY_LIST_NEXT(curPri))
384 : {
385 0 : xcert = NssPrivKeyToXCert( curPri->key ) ;
386 0 : if( xcert != NULL )
387 0 : certsList.push_back( xcert ) ;
388 : }
389 0 : SECKEY_DestroyPrivateKeyList( priKeyList ) ;
390 : }
391 :
392 :
393 : }
394 :
395 : //secondly, we try to find certificate from registered private keys.
396 0 : if( !m_tPriKeyList.empty() ) {
397 0 : std::list< SECKEYPrivateKey* >::iterator priKeyIt ;
398 :
399 0 : for( priKeyIt = m_tPriKeyList.begin() ; priKeyIt != m_tPriKeyList.end() ; ++priKeyIt ) {
400 0 : xcert = NssPrivKeyToXCert( *priKeyIt ) ;
401 0 : if( xcert != NULL )
402 0 : certsList.push_back( xcert ) ;
403 : }
404 : }
405 :
406 0 : length = certsList.size() ;
407 0 : if( length != 0 ) {
408 : int i ;
409 0 : std::list< X509Certificate_NssImpl* >::iterator xcertIt ;
410 0 : Sequence< Reference< XCertificate > > certSeq( length ) ;
411 :
412 0 : for( i = 0, xcertIt = certsList.begin(); xcertIt != certsList.end(); ++xcertIt, ++i ) {
413 0 : certSeq[i] = *xcertIt ;
414 : }
415 :
416 0 : return certSeq ;
417 : }
418 :
419 0 : return Sequence< Reference < XCertificate > > ();
420 : }
421 :
422 0 : Reference< XCertificate > SecurityEnvironment_NssImpl :: getCertificate( const OUString& issuerName, const Sequence< sal_Int8 >& serialNumber ) throw( SecurityException , RuntimeException, std::exception )
423 : {
424 0 : X509Certificate_NssImpl* xcert = NULL;
425 :
426 0 : if( m_pHandler != NULL ) {
427 : CERTIssuerAndSN issuerAndSN ;
428 : CERTCertificate* cert ;
429 : CERTName* nmIssuer ;
430 : char* chIssuer ;
431 : SECItem* derIssuer ;
432 : PRArenaPool* arena ;
433 :
434 0 : arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE ) ;
435 0 : if( arena == NULL )
436 0 : throw RuntimeException() ;
437 :
438 : // Create cert info from issue and serial
439 0 : OString ostr = OUStringToOString( issuerName , RTL_TEXTENCODING_UTF8 ) ;
440 0 : chIssuer = PL_strndup( ostr.getStr(), ( int )ostr.getLength() ) ;
441 0 : nmIssuer = CERT_AsciiToName( chIssuer ) ;
442 0 : if( nmIssuer == NULL ) {
443 0 : PL_strfree( chIssuer ) ;
444 0 : PORT_FreeArena( arena, PR_FALSE ) ;
445 0 : return NULL; // no need for exception cf. i40394
446 : }
447 :
448 0 : derIssuer = SEC_ASN1EncodeItem( arena, NULL, static_cast<void*>(nmIssuer), SEC_ASN1_GET( CERT_NameTemplate ) ) ;
449 0 : if( derIssuer == NULL ) {
450 0 : PL_strfree( chIssuer ) ;
451 0 : CERT_DestroyName( nmIssuer ) ;
452 0 : PORT_FreeArena( arena, PR_FALSE ) ;
453 0 : throw RuntimeException() ;
454 : }
455 :
456 0 : memset( &issuerAndSN, 0, sizeof( issuerAndSN ) ) ;
457 :
458 0 : issuerAndSN.derIssuer.data = derIssuer->data ;
459 0 : issuerAndSN.derIssuer.len = derIssuer->len ;
460 :
461 0 : issuerAndSN.serialNumber.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(serialNumber.getConstArray()));
462 0 : issuerAndSN.serialNumber.len = serialNumber.getLength() ;
463 :
464 0 : cert = CERT_FindCertByIssuerAndSN( m_pHandler, &issuerAndSN ) ;
465 0 : if( cert != NULL ) {
466 0 : xcert = NssCertToXCert( cert ) ;
467 : } else {
468 0 : xcert = NULL ;
469 : }
470 :
471 0 : PL_strfree( chIssuer ) ;
472 0 : CERT_DestroyName( nmIssuer ) ;
473 : //SECITEM_FreeItem( derIssuer, PR_FALSE ) ;
474 0 : CERT_DestroyCertificate( cert ) ;
475 0 : PORT_FreeArena( arena, PR_FALSE ) ;
476 : } else {
477 0 : xcert = NULL ;
478 : }
479 :
480 0 : return xcert ;
481 : }
482 :
483 0 : Reference< XCertificate > SecurityEnvironment_NssImpl :: getCertificate( const OUString& issuerName, const OUString& serialNumber ) throw( SecurityException , RuntimeException ) {
484 0 : Sequence< sal_Int8 > serial = numericStringToBigInteger( serialNumber ) ;
485 0 : return getCertificate( issuerName, serial ) ;
486 : }
487 :
488 0 : Sequence< Reference < XCertificate > > SecurityEnvironment_NssImpl :: buildCertificatePath( const Reference< XCertificate >& begin ) throw( SecurityException , RuntimeException, std::exception ) {
489 : const X509Certificate_NssImpl* xcert ;
490 : const CERTCertificate* cert ;
491 : CERTCertList* certChain ;
492 :
493 0 : Reference< XUnoTunnel > xCertTunnel( begin, UNO_QUERY ) ;
494 0 : if( !xCertTunnel.is() ) {
495 0 : throw RuntimeException() ;
496 : }
497 :
498 : xcert = reinterpret_cast<X509Certificate_NssImpl*>(
499 0 : sal::static_int_cast<sal_uIntPtr>(xCertTunnel->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
500 0 : if( xcert == NULL ) {
501 0 : throw RuntimeException() ;
502 : }
503 :
504 0 : cert = xcert->getNssCert() ;
505 0 : if( cert != NULL ) {
506 : int64 timeboundary ;
507 :
508 : //Get the system clock time
509 0 : timeboundary = PR_Now() ;
510 :
511 0 : certChain = CERT_GetCertChainFromCert( const_cast<CERTCertificate*>(cert), timeboundary, certUsageAnyCA ) ;
512 : } else {
513 0 : certChain = NULL ;
514 : }
515 :
516 0 : if( certChain != NULL ) {
517 : X509Certificate_NssImpl* pCert ;
518 : CERTCertListNode* node ;
519 : int len ;
520 :
521 0 : for( len = 0, node = CERT_LIST_HEAD( certChain ); !CERT_LIST_END( node, certChain ); node = CERT_LIST_NEXT( node ), len ++ ) ;
522 0 : Sequence< Reference< XCertificate > > xCertChain( len ) ;
523 :
524 0 : for( len = 0, node = CERT_LIST_HEAD( certChain ); !CERT_LIST_END( node, certChain ); node = CERT_LIST_NEXT( node ), len ++ ) {
525 0 : pCert = new X509Certificate_NssImpl() ;
526 0 : if( pCert == NULL ) {
527 0 : CERT_DestroyCertList( certChain ) ;
528 0 : throw RuntimeException() ;
529 : }
530 :
531 0 : pCert->setCert( node->cert ) ;
532 :
533 0 : xCertChain[len] = pCert ;
534 : }
535 :
536 0 : CERT_DestroyCertList( certChain ) ;
537 :
538 0 : return xCertChain ;
539 : }
540 :
541 0 : return Sequence< Reference < XCertificate > >();
542 : }
543 :
544 0 : Reference< XCertificate > SecurityEnvironment_NssImpl :: createCertificateFromRaw( const Sequence< sal_Int8 >& rawCertificate ) throw( SecurityException , RuntimeException, std::exception ) {
545 : X509Certificate_NssImpl* xcert ;
546 :
547 0 : if( rawCertificate.getLength() > 0 ) {
548 0 : xcert = new X509Certificate_NssImpl() ;
549 0 : if( xcert == NULL )
550 0 : throw RuntimeException() ;
551 :
552 0 : xcert->setRawCert( rawCertificate ) ;
553 : } else {
554 0 : xcert = NULL ;
555 : }
556 :
557 0 : return xcert ;
558 : }
559 :
560 0 : Reference< XCertificate > SecurityEnvironment_NssImpl :: createCertificateFromAscii( const OUString& asciiCertificate ) throw( SecurityException , RuntimeException, std::exception )
561 : {
562 0 : OString oscert = OUStringToOString( asciiCertificate , RTL_TEXTENCODING_ASCII_US ) ;
563 0 : xmlChar* chCert = xmlStrndup( reinterpret_cast<const xmlChar*>(oscert.getStr()), ( int )oscert.getLength() ) ;
564 0 : int certSize = xmlSecBase64Decode( chCert, reinterpret_cast<xmlSecByte*>(chCert), xmlStrlen( chCert ) ) ;
565 0 : if (certSize > 0)
566 : {
567 0 : Sequence< sal_Int8 > rawCert(certSize) ;
568 0 : for (int i = 0 ; i < certSize; ++i)
569 0 : rawCert[i] = *( chCert + i ) ;
570 :
571 0 : xmlFree( chCert ) ;
572 :
573 0 : return createCertificateFromRaw( rawCert ) ;
574 : }
575 : else
576 : {
577 0 : return NULL;
578 0 : }
579 : }
580 :
581 0 : sal_Int32 SecurityEnvironment_NssImpl ::
582 : verifyCertificate( const Reference< csss::XCertificate >& aCert,
583 : const Sequence< Reference< csss::XCertificate > >& intermediateCerts )
584 : throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException, std::exception )
585 : {
586 0 : sal_Int32 validity = csss::CertificateValidity::INVALID;
587 : const X509Certificate_NssImpl* xcert ;
588 : const CERTCertificate* cert ;
589 0 : ::std::vector<CERTCertificate*> vecTmpNSSCertificates;
590 0 : Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
591 0 : if( !xCertTunnel.is() ) {
592 0 : throw RuntimeException() ;
593 : }
594 :
595 : SAL_INFO("xmlsecurity.xmlsec", "Start verification of certificate: " << aCert->getSubjectName());
596 :
597 : xcert = reinterpret_cast<X509Certificate_NssImpl*>(
598 0 : sal::static_int_cast<sal_uIntPtr>(xCertTunnel->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
599 0 : if( xcert == NULL ) {
600 0 : throw RuntimeException() ;
601 : }
602 :
603 : //CERT_PKIXVerifyCert does not take a db as argument. It will therefore
604 : //internally use CERT_GetDefaultCertDB
605 : //Make sure m_pHandler is the default DB
606 : OSL_ASSERT(m_pHandler == CERT_GetDefaultCertDB());
607 0 : CERTCertDBHandle * certDb = m_pHandler != NULL ? m_pHandler : CERT_GetDefaultCertDB();
608 0 : cert = xcert->getNssCert() ;
609 0 : if( cert != NULL )
610 : {
611 :
612 : //prepare the intermediate certificates
613 0 : for (sal_Int32 i = 0; i < intermediateCerts.getLength(); i++)
614 : {
615 0 : Sequence<sal_Int8> der = intermediateCerts[i]->getEncoded();
616 : SECItem item;
617 0 : item.type = siBuffer;
618 0 : item.data = reinterpret_cast<unsigned char*>(der.getArray());
619 0 : item.len = der.getLength();
620 :
621 : CERTCertificate* certTmp = CERT_NewTempCertificate(certDb, &item,
622 : NULL /* nickname */,
623 : PR_FALSE /* isPerm */,
624 0 : PR_TRUE /* copyDER */);
625 0 : if (!certTmp)
626 : {
627 : SAL_INFO("xmlsecurity.xmlsec", "Failed to add a temporary certificate: " << intermediateCerts[i]->getIssuerName());
628 :
629 : }
630 : else
631 : {
632 : SAL_INFO("xmlsecurity.xmlsec", "Added temporary certificate: " <<
633 : (certTmp->subjectName ? certTmp->subjectName : ""));
634 0 : vecTmpNSSCertificates.push_back(certTmp);
635 : }
636 0 : }
637 :
638 :
639 : SECStatus status ;
640 :
641 : CERTVerifyLog log;
642 0 : log.arena = PORT_NewArena(512);
643 0 : log.head = log.tail = NULL;
644 0 : log.count = 0;
645 :
646 0 : CERT_EnableOCSPChecking(certDb);
647 0 : CERT_DisableOCSPDefaultResponder(certDb);
648 : CERTValOutParam cvout[5];
649 : CERTValInParam cvin[3];
650 0 : int ncvinCount=0;
651 :
652 : #if ( NSS_VMAJOR > 3 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR > 12 ) || ( NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH > 0 )
653 0 : cvin[ncvinCount].type = cert_pi_useAIACertFetch;
654 0 : cvin[ncvinCount].value.scalar.b = PR_TRUE;
655 0 : ncvinCount++;
656 : #endif
657 :
658 : PRUint64 revFlagsLeaf[2];
659 : PRUint64 revFlagsChain[2];
660 : CERTRevocationFlags rev;
661 0 : rev.leafTests.number_of_defined_methods = 2;
662 0 : rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf;
663 : //the flags are defined in cert.h
664 : //We check both leaf and chain.
665 : //It is enough if one revocation method has fresh info,
666 : //but at least one must have some. Otherwise validation fails.
667 : //!!! using leaf test and CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE
668 : // when validating a root certificate will result in "revoked". Usually
669 : //there is no revocation information available for the root cert because
670 : //it must be trusted anyway and it does itself issue revocation information.
671 : //When we use the flag here and OOo shows the certification path then the root
672 : //cert is invalid while all other can be valid. It would probably best if
673 : //this interface method returned the whole chain.
674 : //Otherwise we need to check if the certificate is self-signed and if it is
675 : //then not use the flag when doing the leaf-test.
676 0 : rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
677 : CERT_REV_M_TEST_USING_THIS_METHOD
678 0 : | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
679 0 : rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
680 : CERT_REV_M_TEST_USING_THIS_METHOD
681 0 : | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
682 0 : rev.leafTests.number_of_preferred_methods = 0;
683 0 : rev.leafTests.preferred_methods = NULL;
684 : rev.leafTests.cert_rev_method_independent_flags =
685 0 : CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
686 :
687 0 : rev.chainTests.number_of_defined_methods = 2;
688 0 : rev.chainTests.cert_rev_flags_per_method = revFlagsChain;
689 0 : rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
690 : CERT_REV_M_TEST_USING_THIS_METHOD
691 0 : | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
692 0 : rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
693 : CERT_REV_M_TEST_USING_THIS_METHOD
694 0 : | CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
695 0 : rev.chainTests.number_of_preferred_methods = 0;
696 0 : rev.chainTests.preferred_methods = NULL;
697 : rev.chainTests.cert_rev_method_independent_flags =
698 0 : CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
699 :
700 :
701 0 : cvin[ncvinCount].type = cert_pi_revocationFlags;
702 0 : cvin[ncvinCount].value.pointer.revocation = &rev;
703 0 : ncvinCount++;
704 : // does not work, not implemented yet in 3.12.4
705 : // cvin[ncvinCount].type = cert_pi_keyusage;
706 : // cvin[ncvinCount].value.scalar.ui = KU_DIGITAL_SIGNATURE;
707 : // ncvinCount++;
708 0 : cvin[ncvinCount].type = cert_pi_end;
709 :
710 0 : cvout[0].type = cert_po_trustAnchor;
711 0 : cvout[0].value.pointer.cert = NULL;
712 0 : cvout[1].type = cert_po_errorLog;
713 0 : cvout[1].value.pointer.log = &log;
714 0 : cvout[2].type = cert_po_end;
715 :
716 : // We check SSL server certificates, CA certificates and signing sertificates.
717 : //
718 : // ToDo check keyusage, looking at CERT_KeyUsageAndTypeForCertUsage (
719 : // mozilla/security/nss/lib/certdb/certdb.c indicates that
720 : // certificateUsageSSLClient, certificateUsageSSLServer and certificateUsageSSLCA
721 : // are sufficient. They cover the key usages for digital signature, key agreement
722 : // and encipherment and certificate signature
723 :
724 : //never use the following usages because they are not checked properly
725 : // certificateUsageUserCertImport
726 : // certificateUsageVerifyCA
727 : // certificateUsageAnyCA
728 : // certificateUsageProtectedObjectSigner
729 :
730 0 : UsageDescription arUsages[5];
731 0 : arUsages[0] = UsageDescription( certificateUsageSSLClient, "certificateUsageSSLClient" );
732 0 : arUsages[1] = UsageDescription( certificateUsageSSLServer, "certificateUsageSSLServer" );
733 0 : arUsages[2] = UsageDescription( certificateUsageSSLCA, "certificateUsageSSLCA" );
734 0 : arUsages[3] = UsageDescription( certificateUsageEmailSigner, "certificateUsageEmailSigner" );
735 0 : arUsages[4] = UsageDescription( certificateUsageEmailRecipient, "certificateUsageEmailRecipient" );
736 :
737 0 : int numUsages = SAL_N_ELEMENTS(arUsages);
738 0 : for (int i = 0; i < numUsages; i++)
739 : {
740 : SAL_INFO("xmlsecurity.xmlsec", "Testing usage " << i+1 <<
741 : " of " << numUsages << ": " <<
742 : arUsages[i].description <<
743 : " (0x" << std::hex << (int) arUsages[i].usage << ")" << std::dec);
744 :
745 : status = CERT_PKIXVerifyCert(const_cast<CERTCertificate *>(cert), arUsages[i].usage,
746 0 : cvin, cvout, NULL);
747 0 : if( status == SECSuccess )
748 : {
749 : SAL_INFO("xmlsecurity.xmlsec", "CERT_PKIXVerifyCert returned SECSuccess.");
750 : //When an intermediate or root certificate is checked then we expect the usage
751 : //certificateUsageSSLCA. This, however, will be only set when in the trust settings dialog
752 : //the button "This certificate can identify websites" is checked. If for example only
753 : //"This certificate can identify mail users" is set then the end certificate can
754 : //be validated and the returned usage will conain certificateUsageEmailRecipient.
755 : //But checking directly the root or intermediate certificate will fail. In the
756 : //certificate path view the end certificate will be shown as valid but the others
757 : //will be displayed as invalid.
758 :
759 0 : validity = csss::CertificateValidity::VALID;
760 : SAL_INFO("xmlsecurity.xmlsec", "Certificate is valid.");
761 0 : CERTCertificate * issuerCert = cvout[0].value.pointer.cert;
762 0 : if (issuerCert)
763 : {
764 : SAL_INFO("xmlsecurity.xmlsec", "Root certificate: " << issuerCert->subjectName);
765 0 : CERT_DestroyCertificate(issuerCert);
766 : };
767 :
768 0 : break;
769 : }
770 : else
771 : {
772 0 : PRIntn err = PR_GetError();
773 : SAL_INFO("xmlsecurity.xmlsec", "Error: " << err << ": " << getCertError(err));
774 :
775 : /* Display validation results */
776 0 : if ( log.count > 0)
777 : {
778 0 : CERTVerifyLogNode *node = NULL;
779 0 : printChainFailure(&log);
780 :
781 0 : for (node = log.head; node; node = node->next) {
782 0 : if (node->cert)
783 0 : CERT_DestroyCertificate(node->cert);
784 : }
785 0 : log.head = log.tail = NULL;
786 0 : log.count = 0;
787 : }
788 : SAL_INFO("xmlsecurity.xmlsec", "Certificate is invalid.");
789 : }
790 : }
791 :
792 : }
793 : else
794 : {
795 0 : validity = ::com::sun::star::security::CertificateValidity::INVALID ;
796 : }
797 :
798 : //Destroying the temporary certificates
799 0 : std::vector<CERTCertificate*>::const_iterator cert_i;
800 0 : for (cert_i = vecTmpNSSCertificates.begin(); cert_i != vecTmpNSSCertificates.end(); ++cert_i)
801 : {
802 : SAL_INFO("xmlsecurity.xmlsec", "Destroying temporary certificate");
803 0 : CERT_DestroyCertificate(*cert_i);
804 : }
805 0 : return validity ;
806 : }
807 :
808 0 : sal_Int32 SecurityEnvironment_NssImpl::getCertificateCharacters(
809 : const ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificate >& aCert ) throw( ::com::sun::star::uno::SecurityException, ::com::sun::star::uno::RuntimeException, std::exception ) {
810 : sal_Int32 characters ;
811 : const X509Certificate_NssImpl* xcert ;
812 : const CERTCertificate* cert ;
813 :
814 0 : Reference< XUnoTunnel > xCertTunnel( aCert, UNO_QUERY ) ;
815 0 : if( !xCertTunnel.is() ) {
816 0 : throw RuntimeException() ;
817 : }
818 :
819 : xcert = reinterpret_cast<X509Certificate_NssImpl*>(
820 0 : sal::static_int_cast<sal_uIntPtr>(xCertTunnel->getSomething( X509Certificate_NssImpl::getUnoTunnelId() ))) ;
821 0 : if( xcert == NULL ) {
822 0 : throw RuntimeException() ;
823 : }
824 :
825 0 : cert = xcert->getNssCert() ;
826 :
827 0 : characters = 0x00000000 ;
828 :
829 : //Firstly, find out whether or not the cert is self-signed.
830 0 : if( SECITEM_CompareItem( &(cert->derIssuer), &(cert->derSubject) ) == SECEqual ) {
831 0 : characters |= ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
832 : } else {
833 0 : characters &= ~ ::com::sun::star::security::CertificateCharacters::SELF_SIGNED ;
834 : }
835 :
836 : //Secondly, find out whether or not the cert has a private key.
837 :
838 : /*
839 : * i40394
840 : *
841 : * mmi : need to check whether the cert's slot is valid first
842 : */
843 0 : SECKEYPrivateKey* priKey = NULL;
844 :
845 0 : if (cert->slot != NULL)
846 : {
847 0 : priKey = PK11_FindPrivateKeyFromCert( cert->slot, const_cast<CERTCertificate*>(cert), NULL ) ;
848 : }
849 0 : if(priKey == NULL)
850 : {
851 0 : for (CIT_SLOTS is = m_Slots.begin(); is != m_Slots.end(); is++)
852 : {
853 0 : priKey = PK11_FindPrivateKeyFromCert(*is, const_cast<CERTCertificate*>(cert), NULL);
854 0 : if (priKey)
855 0 : break;
856 : }
857 : }
858 0 : if( priKey != NULL ) {
859 0 : characters |= ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;
860 :
861 0 : SECKEY_DestroyPrivateKey( priKey ) ;
862 : } else {
863 0 : characters &= ~ ::com::sun::star::security::CertificateCharacters::HAS_PRIVATE_KEY ;
864 : }
865 :
866 0 : return characters ;
867 : }
868 :
869 0 : X509Certificate_NssImpl* NssCertToXCert( CERTCertificate* cert )
870 : {
871 : X509Certificate_NssImpl* xcert ;
872 :
873 0 : if( cert != NULL ) {
874 0 : xcert = new X509Certificate_NssImpl() ;
875 0 : if( xcert == NULL ) {
876 0 : xcert = NULL ;
877 : } else {
878 0 : xcert->setCert( cert ) ;
879 : }
880 : } else {
881 0 : xcert = NULL ;
882 : }
883 :
884 0 : return xcert ;
885 : }
886 :
887 0 : X509Certificate_NssImpl* NssPrivKeyToXCert( SECKEYPrivateKey* priKey )
888 : {
889 : X509Certificate_NssImpl* xcert ;
890 :
891 0 : if( priKey != NULL ) {
892 0 : CERTCertificate* cert = PK11_GetCertFromPrivateKey( priKey ) ;
893 :
894 0 : if( cert != NULL ) {
895 0 : xcert = NssCertToXCert( cert ) ;
896 : } else {
897 0 : xcert = NULL ;
898 : }
899 :
900 0 : CERT_DestroyCertificate( cert ) ;
901 : } else {
902 0 : xcert = NULL ;
903 : }
904 :
905 0 : return xcert ;
906 : }
907 :
908 :
909 : /* Native methods */
910 0 : xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() throw( Exception, RuntimeException ) {
911 :
912 : unsigned int i ;
913 0 : CERTCertDBHandle* handler = NULL ;
914 0 : PK11SymKey* symKey = NULL ;
915 0 : SECKEYPublicKey* pubKey = NULL ;
916 0 : SECKEYPrivateKey* priKey = NULL ;
917 0 : xmlSecKeysMngrPtr pKeysMngr = NULL ;
918 :
919 0 : handler = this->getCertDb() ;
920 :
921 : /*-
922 : * The following lines is based on the private version of xmlSec-NSS
923 : * crypto engine
924 : */
925 0 : int cSlots = m_Slots.size();
926 0 : boost::scoped_array<PK11SlotInfo*> sarSlots(new PK11SlotInfo*[cSlots]);
927 0 : PK11SlotInfo** slots = sarSlots.get();
928 0 : int count = 0;
929 0 : for (CIT_SLOTS islots = m_Slots.begin();islots != m_Slots.end(); islots++, count++)
930 0 : slots[count] = *islots;
931 :
932 0 : pKeysMngr = xmlSecNssAppliedKeysMngrCreate(slots, cSlots, handler ) ;
933 0 : if( pKeysMngr == NULL )
934 0 : throw RuntimeException() ;
935 :
936 : /*-
937 : * Adopt symmetric key into keys manager
938 : */
939 0 : for( i = 0 ; ( symKey = this->getSymKey( i ) ) != NULL ; i ++ ) {
940 0 : if( xmlSecNssAppliedKeysMngrSymKeyLoad( pKeysMngr, symKey ) < 0 ) {
941 0 : throw RuntimeException() ;
942 : }
943 : }
944 :
945 : /*-
946 : * Adopt asymmetric public key into keys manager
947 : */
948 0 : for( i = 0 ; ( pubKey = this->getPubKey( i ) ) != NULL ; i ++ ) {
949 0 : if( xmlSecNssAppliedKeysMngrPubKeyLoad( pKeysMngr, pubKey ) < 0 ) {
950 0 : throw RuntimeException() ;
951 : }
952 : }
953 :
954 : /*-
955 : * Adopt asymmetric private key into keys manager
956 : */
957 0 : for( i = 0 ; ( priKey = this->getPriKey( i ) ) != NULL ; i ++ ) {
958 0 : if( xmlSecNssAppliedKeysMngrPriKeyLoad( pKeysMngr, priKey ) < 0 ) {
959 0 : throw RuntimeException() ;
960 : }
961 : }
962 0 : return pKeysMngr ;
963 : }
964 0 : void SecurityEnvironment_NssImpl::destroyKeysManager(xmlSecKeysMngrPtr pKeysMngr) throw( Exception, RuntimeException ) {
965 0 : if( pKeysMngr != NULL ) {
966 0 : xmlSecKeysMngrDestroy( pKeysMngr ) ;
967 : }
968 0 : }
969 :
970 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|