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( &notBefore, &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( &notAfter, &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