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