1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmlsecurity.hxx" 30 31 32 33 #include "nssrenam.h" 34 #include "nspr.h" 35 #include "nss.h" 36 #include "secder.h" 37 38 //MM : added by MM 39 #include "hasht.h" 40 #include "secoid.h" 41 #include "pk11func.h" 42 //MM : end 43 44 45 46 #include <sal/config.h> 47 #include <rtl/uuid.h> 48 #include "x509certificate_nssimpl.hxx" 49 50 #ifndef _CERTIFICATEEXTENSION_NSSIMPL_HXX_ 51 #include "certificateextension_xmlsecimpl.hxx" 52 #endif 53 54 #ifndef _SANEXTENSION_NSSIMPL_HXX_ 55 #include "sanextension_nssimpl.hxx" 56 #endif 57 58 using namespace ::com::sun::star::uno ; 59 using namespace ::com::sun::star::security ; 60 using ::rtl::OUString ; 61 62 using ::com::sun::star::security::XCertificate ; 63 using ::com::sun::star::util::DateTime ; 64 65 X509Certificate_NssImpl :: X509Certificate_NssImpl() : 66 m_pCert( NULL ) 67 { 68 } 69 70 X509Certificate_NssImpl :: ~X509Certificate_NssImpl() { 71 if( m_pCert != NULL ) { 72 CERT_DestroyCertificate( m_pCert ) ; 73 } 74 } 75 76 //Methods from XCertificate 77 sal_Int16 SAL_CALL X509Certificate_NssImpl :: getVersion() throw ( ::com::sun::star::uno::RuntimeException) { 78 if( m_pCert != NULL ) { 79 if( m_pCert->version.len > 0 ) { 80 return ( char )*( m_pCert->version.data ) ; 81 } else 82 return 0 ; 83 } else { 84 return -1 ; 85 } 86 } 87 88 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl :: getSerialNumber() throw ( ::com::sun::star::uno::RuntimeException) { 89 if( m_pCert != NULL && m_pCert->serialNumber.len > 0 ) { 90 Sequence< sal_Int8 > serial( m_pCert->serialNumber.len ) ; 91 for( unsigned int i = 0 ; i < m_pCert->serialNumber.len ; i ++ ) 92 serial[i] = *( m_pCert->serialNumber.data + i ) ; 93 94 return serial ; 95 } else { 96 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 97 } 98 } 99 100 ::rtl::OUString SAL_CALL X509Certificate_NssImpl :: getIssuerName() throw ( ::com::sun::star::uno::RuntimeException) { 101 if( m_pCert != NULL ) { 102 return OUString(m_pCert->issuerName , PL_strlen(m_pCert->issuerName) , RTL_TEXTENCODING_UTF8) ; 103 } else { 104 return OUString() ; 105 } 106 } 107 108 ::rtl::OUString SAL_CALL X509Certificate_NssImpl :: getSubjectName() throw ( ::com::sun::star::uno::RuntimeException) { 109 if( m_pCert != NULL ) { 110 return OUString(m_pCert->subjectName , PL_strlen(m_pCert->subjectName) , RTL_TEXTENCODING_UTF8); 111 } else { 112 return OUString() ; 113 } 114 } 115 116 ::com::sun::star::util::DateTime SAL_CALL X509Certificate_NssImpl :: getNotValidBefore() throw ( ::com::sun::star::uno::RuntimeException) { 117 if( m_pCert != NULL ) { 118 SECStatus rv ; 119 PRTime notBefore ; 120 PRExplodedTime explTime ; 121 DateTime dateTime ; 122 123 rv = DER_DecodeTimeChoice( ¬Before, &m_pCert->validity.notBefore ) ; 124 if( rv ) { 125 return DateTime() ; 126 } 127 128 //Convert the time to readable local time 129 PR_ExplodeTime( notBefore, PR_LocalTimeParameters, &explTime ) ; 130 131 dateTime.HundredthSeconds = static_cast< sal_Int16 >( explTime.tm_usec / 1000 ); 132 dateTime.Seconds = static_cast< sal_Int16 >( explTime.tm_sec ); 133 dateTime.Minutes = static_cast< sal_Int16 >( explTime.tm_min ); 134 dateTime.Hours = static_cast< sal_Int16 >( explTime.tm_hour ); 135 dateTime.Day = static_cast< sal_Int16 >( explTime.tm_mday ); 136 dateTime.Month = static_cast< sal_Int16 >( explTime.tm_month+1 ); 137 dateTime.Year = static_cast< sal_Int16 >( explTime.tm_year ); 138 139 return dateTime ; 140 } else { 141 return DateTime() ; 142 } 143 } 144 145 ::com::sun::star::util::DateTime SAL_CALL X509Certificate_NssImpl :: getNotValidAfter() throw ( ::com::sun::star::uno::RuntimeException) { 146 if( m_pCert != NULL ) { 147 SECStatus rv ; 148 PRTime notAfter ; 149 PRExplodedTime explTime ; 150 DateTime dateTime ; 151 152 rv = DER_DecodeTimeChoice( ¬After, &m_pCert->validity.notAfter ) ; 153 if( rv ) { 154 return DateTime() ; 155 } 156 157 //Convert the time to readable local time 158 PR_ExplodeTime( notAfter, PR_LocalTimeParameters, &explTime ) ; 159 160 dateTime.HundredthSeconds = static_cast< sal_Int16 >( explTime.tm_usec / 1000 ); 161 dateTime.Seconds = static_cast< sal_Int16 >( explTime.tm_sec ); 162 dateTime.Minutes = static_cast< sal_Int16 >( explTime.tm_min ); 163 dateTime.Hours = static_cast< sal_Int16 >( explTime.tm_hour ); 164 dateTime.Day = static_cast< sal_Int16 >( explTime.tm_mday ); 165 dateTime.Month = static_cast< sal_Int16 >( explTime.tm_month+1 ); 166 dateTime.Year = static_cast< sal_Int16 >( explTime.tm_year ); 167 168 return dateTime ; 169 } else { 170 return DateTime() ; 171 } 172 } 173 174 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl :: getIssuerUniqueID() throw ( ::com::sun::star::uno::RuntimeException) { 175 if( m_pCert != NULL && m_pCert->issuerID.len > 0 ) { 176 Sequence< sal_Int8 > issuerUid( m_pCert->issuerID.len ) ; 177 for( unsigned int i = 0 ; i < m_pCert->issuerID.len ; i ++ ) 178 issuerUid[i] = *( m_pCert->issuerID.data + i ) ; 179 180 return issuerUid ; 181 } else { 182 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 183 } 184 } 185 186 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl :: getSubjectUniqueID() throw ( ::com::sun::star::uno::RuntimeException) { 187 if( m_pCert != NULL && m_pCert->subjectID.len > 0 ) { 188 Sequence< sal_Int8 > subjectUid( m_pCert->subjectID.len ) ; 189 for( unsigned int i = 0 ; i < m_pCert->subjectID.len ; i ++ ) 190 subjectUid[i] = *( m_pCert->subjectID.data + i ) ; 191 192 return subjectUid ; 193 } else { 194 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 195 } 196 } 197 198 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificateExtension > > SAL_CALL X509Certificate_NssImpl :: getExtensions() throw ( ::com::sun::star::uno::RuntimeException) { 199 if( m_pCert != NULL && m_pCert->extensions != NULL ) { 200 CERTCertExtension** extns ; 201 CertificateExtension_XmlSecImpl* pExtn ; 202 sal_Bool crit ; 203 int len ; 204 205 for( len = 0, extns = m_pCert->extensions; *extns != NULL; len ++, extns ++ ) ; 206 Sequence< Reference< XCertificateExtension > > xExtns( len ) ; 207 208 for( extns = m_pCert->extensions, len = 0; *extns != NULL; extns ++, len ++ ) { 209 const SECItem id = (*extns)->id; 210 ::rtl::OString oidString(CERT_GetOidString(&id)); 211 212 // remove "OID." prefix if existing 213 ::rtl::OString objID; 214 ::rtl::OString oid("OID."); 215 if (oidString.match(oid)) 216 objID = oidString.copy(oid.getLength()); 217 else 218 objID = oidString; 219 220 if ( objID.equals("2.5.29.17") ) 221 pExtn = (CertificateExtension_XmlSecImpl*) new SanExtensionImpl() ; 222 else 223 pExtn = new CertificateExtension_XmlSecImpl() ; 224 225 if( (*extns)->critical.data == NULL ) 226 crit = sal_False ; 227 else 228 crit = ( (*extns)->critical.data[0] == 0xFF ) ? sal_True : sal_False ; 229 pExtn->setCertExtn( (*extns)->value.data, (*extns)->value.len, (unsigned char*)objID.getStr(), objID.getLength(), crit ) ; 230 231 xExtns[len] = pExtn ; 232 } 233 234 return xExtns ; 235 } else { 236 return ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificateExtension > > (); 237 } 238 } 239 240 ::com::sun::star::uno::Reference< ::com::sun::star::security::XCertificateExtension > SAL_CALL X509Certificate_NssImpl :: findCertificateExtension( const ::com::sun::star::uno::Sequence< sal_Int8 >& oid ) throw (::com::sun::star::uno::RuntimeException) { 241 if( m_pCert != NULL && m_pCert->extensions != NULL ) { 242 CertificateExtension_XmlSecImpl* pExtn ; 243 CERTCertExtension** extns ; 244 SECItem idItem ; 245 sal_Bool crit ; 246 247 idItem.data = ( unsigned char* )&oid[0] ; 248 idItem.len = oid.getLength() ; 249 250 pExtn = NULL ; 251 for( extns = m_pCert->extensions; *extns != NULL; extns ++ ) { 252 if( SECITEM_CompareItem( &idItem, &(*extns)->id ) == SECEqual ) { 253 const SECItem id = (*extns)->id; 254 ::rtl::OString objId(CERT_GetOidString(&id)); 255 if ( objId.equals("OID.2.5.29.17") ) 256 pExtn = (CertificateExtension_XmlSecImpl*) new SanExtensionImpl() ; 257 else 258 pExtn = new CertificateExtension_XmlSecImpl() ; 259 if( (*extns)->critical.data == NULL ) 260 crit = sal_False ; 261 else 262 crit = ( (*extns)->critical.data[0] == 0xFF ) ? sal_True : sal_False ; 263 pExtn->setCertExtn( (*extns)->value.data, (*extns)->value.len, (*extns)->id.data, (*extns)->id.len, crit ) ; 264 } 265 } 266 267 return pExtn ; 268 } else { 269 return NULL ; 270 } 271 } 272 273 274 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl :: getEncoded() throw ( ::com::sun::star::uno::RuntimeException) { 275 if( m_pCert != NULL && m_pCert->derCert.len > 0 ) { 276 Sequence< sal_Int8 > rawCert( m_pCert->derCert.len ) ; 277 278 for( unsigned int i = 0 ; i < m_pCert->derCert.len ; i ++ ) 279 rawCert[i] = *( m_pCert->derCert.data + i ) ; 280 281 return rawCert ; 282 } else { 283 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 284 } 285 } 286 287 //Helper methods 288 void X509Certificate_NssImpl :: setCert( CERTCertificate* cert ) { 289 if( m_pCert != NULL ) { 290 CERT_DestroyCertificate( m_pCert ) ; 291 m_pCert = NULL ; 292 } 293 294 if( cert != NULL ) { 295 m_pCert = CERT_DupCertificate( cert ) ; 296 } 297 } 298 299 const CERTCertificate* X509Certificate_NssImpl :: getNssCert() const { 300 if( m_pCert != NULL ) { 301 return m_pCert ; 302 } else { 303 return NULL ; 304 } 305 } 306 307 void X509Certificate_NssImpl :: setRawCert( Sequence< sal_Int8 > rawCert ) throw ( ::com::sun::star::uno::RuntimeException) { 308 CERTCertificate* cert ; 309 SECItem certItem ; 310 311 certItem.data = ( unsigned char* )&rawCert[0] ; 312 certItem.len = rawCert.getLength() ; 313 314 cert = CERT_DecodeDERCertificate( &certItem, PR_TRUE, NULL ) ; 315 if( cert == NULL ) 316 throw RuntimeException() ; 317 318 if( m_pCert != NULL ) { 319 CERT_DestroyCertificate( m_pCert ) ; 320 m_pCert = NULL ; 321 } 322 323 m_pCert = cert ; 324 } 325 326 /* XUnoTunnel */ 327 sal_Int64 SAL_CALL X509Certificate_NssImpl :: getSomething( const Sequence< sal_Int8 >& aIdentifier ) throw( RuntimeException ) { 328 if( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) { 329 return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this)); 330 } 331 return 0 ; 332 } 333 334 /* XUnoTunnel extension */ 335 const Sequence< sal_Int8>& X509Certificate_NssImpl :: getUnoTunnelId() { 336 static Sequence< sal_Int8 >* pSeq = 0 ; 337 if( !pSeq ) { 338 ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ) ; 339 if( !pSeq ) { 340 static Sequence< sal_Int8> aSeq( 16 ) ; 341 rtl_createUuid( ( sal_uInt8* )aSeq.getArray() , 0 , sal_True ) ; 342 pSeq = &aSeq ; 343 } 344 } 345 return *pSeq ; 346 } 347 348 /* XUnoTunnel extension */ 349 X509Certificate_NssImpl* X509Certificate_NssImpl :: getImplementation( const Reference< XInterface > xObj ) { 350 Reference< XUnoTunnel > xUT( xObj , UNO_QUERY ) ; 351 if( xUT.is() ) { 352 return reinterpret_cast<X509Certificate_NssImpl*>( 353 sal::static_int_cast<sal_uIntPtr>(xUT->getSomething( getUnoTunnelId() ))); 354 } else 355 return NULL ; 356 } 357 358 // MM : added by MM 359 ::rtl::OUString getAlgorithmDescription(SECAlgorithmID *aid) 360 { 361 SECOidTag tag; 362 tag = SECOID_GetAlgorithmTag(aid); 363 364 const char *pDesc = SECOID_FindOIDTagDescription(tag); 365 366 return rtl::OUString::createFromAscii( pDesc ) ; 367 } 368 369 ::com::sun::star::uno::Sequence< sal_Int8 > getThumbprint(CERTCertificate *pCert, SECOidTag id) 370 { 371 if( pCert != NULL ) 372 { 373 unsigned char fingerprint[20]; 374 //char *fpStr = NULL; 375 SECItem fpItem; 376 int length = ((id == SEC_OID_MD5)?MD5_LENGTH:SHA1_LENGTH); 377 378 memset(fingerprint, 0, sizeof fingerprint); 379 PK11_HashBuf(id, fingerprint, pCert->derCert.data, pCert->derCert.len); 380 fpItem.data = fingerprint; 381 fpItem.len = length; 382 //fpStr = CERT_Hexify(&fpItem, 1); 383 384 Sequence< sal_Int8 > thumbprint( length ) ; 385 for( int i = 0 ; i < length ; i ++ ) 386 { 387 thumbprint[i] = fingerprint[i]; 388 } 389 390 //PORT_Free(fpStr); 391 return thumbprint; 392 } 393 else 394 { 395 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 396 } 397 } 398 399 ::rtl::OUString SAL_CALL X509Certificate_NssImpl::getSubjectPublicKeyAlgorithm() 400 throw ( ::com::sun::star::uno::RuntimeException) 401 { 402 if( m_pCert != NULL ) 403 { 404 return getAlgorithmDescription(&(m_pCert->subjectPublicKeyInfo.algorithm)); 405 } 406 else 407 { 408 return OUString() ; 409 } 410 } 411 412 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSubjectPublicKeyValue() 413 throw ( ::com::sun::star::uno::RuntimeException) 414 { 415 if( m_pCert != NULL ) 416 { 417 SECItem spk = m_pCert->subjectPublicKeyInfo.subjectPublicKey; 418 DER_ConvertBitString(&spk); 419 420 if ( spk.len>0) 421 { 422 Sequence< sal_Int8 > key( spk.len ) ; 423 for( unsigned int i = 0 ; i < spk.len ; i ++ ) 424 { 425 key[i] = *( spk.data + i ) ; 426 } 427 428 return key ; 429 } 430 } 431 432 return ::com::sun::star::uno::Sequence< sal_Int8 >(); 433 } 434 435 ::rtl::OUString SAL_CALL X509Certificate_NssImpl::getSignatureAlgorithm() 436 throw ( ::com::sun::star::uno::RuntimeException) 437 { 438 if( m_pCert != NULL ) 439 { 440 return getAlgorithmDescription(&(m_pCert->signature)); 441 } 442 else 443 { 444 return OUString() ; 445 } 446 } 447 448 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getSHA1Thumbprint() 449 throw ( ::com::sun::star::uno::RuntimeException) 450 { 451 return getThumbprint(m_pCert, SEC_OID_SHA1); 452 } 453 454 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_NssImpl::getMD5Thumbprint() 455 throw ( ::com::sun::star::uno::RuntimeException) 456 { 457 return getThumbprint(m_pCert, SEC_OID_MD5); 458 } 459 460 sal_Int32 SAL_CALL X509Certificate_NssImpl::getCertificateUsage( ) 461 throw ( ::com::sun::star::uno::RuntimeException) 462 { 463 SECStatus rv; 464 SECItem tmpitem; 465 sal_Int32 usage; 466 467 rv = CERT_FindKeyUsageExtension(m_pCert, &tmpitem); 468 if ( rv == SECSuccess ) 469 { 470 usage = tmpitem.data[0]; 471 PORT_Free(tmpitem.data); 472 tmpitem.data = NULL; 473 } 474 else 475 { 476 usage = KU_ALL; 477 } 478 479 /* 480 * to make the nss implementation compatible with MSCrypto, 481 * the following usage is ignored 482 * 483 * 484 if ( CERT_GovtApprovedBitSet(m_pCert) ) 485 { 486 usage |= KU_NS_GOVT_APPROVED; 487 } 488 */ 489 490 return usage; 491 } 492 493 // MM : end 494 495