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( ¬Before, &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( ¬After, &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