xref: /trunk/main/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx (revision a5b190bfa3e1bed4623e2958a8877664a3b5506c)
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