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