1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
28 #include <sal/config.h>
29 #include <comphelper/servicehelper.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <rtl/ref.hxx>
32 #include "x509certificate_nssimpl.hxx"
34 #include <certificateextension_xmlsecimpl.hxx>
36 #include "sanextension_nssimpl.hxx"
37 #include <tools/time.hxx>
38 #include <svl/sigstruct.hxx>
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::security
;
44 using ::com::sun::star::security::XCertificate
;
45 using ::com::sun::star::util::DateTime
;
47 X509Certificate_NssImpl::X509Certificate_NssImpl() :
52 X509Certificate_NssImpl::~X509Certificate_NssImpl() {
53 if( m_pCert
!= nullptr ) {
54 CERT_DestroyCertificate( m_pCert
) ;
58 //Methods from XCertificate
59 sal_Int16 SAL_CALL
X509Certificate_NssImpl::getVersion() {
60 if( m_pCert
!= nullptr ) {
61 if( m_pCert
->version
.len
> 0 ) {
62 return static_cast<char>(*( m_pCert
->version
.data
)) ;
70 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getSerialNumber() {
71 if( m_pCert
!= nullptr && m_pCert
->serialNumber
.len
> 0 ) {
72 Sequence
< sal_Int8
> serial( m_pCert
->serialNumber
.len
) ;
73 for( unsigned int i
= 0 ; i
< m_pCert
->serialNumber
.len
; i
++ )
74 serial
[i
] = *( m_pCert
->serialNumber
.data
+ i
) ;
78 return css::uno::Sequence
< sal_Int8
>();
82 OUString SAL_CALL
X509Certificate_NssImpl::getIssuerName() {
83 if( m_pCert
!= nullptr ) {
84 return OUString(m_pCert
->issuerName
, PL_strlen(m_pCert
->issuerName
) , RTL_TEXTENCODING_UTF8
) ;
90 OUString SAL_CALL
X509Certificate_NssImpl::getSubjectName() {
91 if( m_pCert
!= nullptr ) {
92 return OUString(m_pCert
->subjectName
, PL_strlen(m_pCert
->subjectName
) , RTL_TEXTENCODING_UTF8
);
98 css::util::DateTime SAL_CALL
X509Certificate_NssImpl::getNotValidBefore() {
99 if( m_pCert
!= nullptr ) {
102 PRExplodedTime explTime
;
105 rv
= DER_DecodeTimeChoice( ¬Before
, &m_pCert
->validity
.notBefore
) ;
110 //Convert the time to readable local time
111 PR_ExplodeTime( notBefore
, PR_LocalTimeParameters
, &explTime
) ;
113 dateTime
.NanoSeconds
= static_cast< sal_Int32
>( explTime
.tm_usec
* ::tools::Time::nanoPerMicro
);
114 dateTime
.Seconds
= static_cast< sal_Int16
>( explTime
.tm_sec
);
115 dateTime
.Minutes
= static_cast< sal_Int16
>( explTime
.tm_min
);
116 dateTime
.Hours
= static_cast< sal_Int16
>( explTime
.tm_hour
);
117 dateTime
.Day
= static_cast< sal_Int16
>( explTime
.tm_mday
);
118 dateTime
.Month
= static_cast< sal_Int16
>( explTime
.tm_month
+1 );
119 dateTime
.Year
= static_cast< sal_Int16
>( explTime
.tm_year
);
127 css::util::DateTime SAL_CALL
X509Certificate_NssImpl::getNotValidAfter() {
128 if( m_pCert
!= nullptr ) {
131 PRExplodedTime explTime
;
134 rv
= DER_DecodeTimeChoice( ¬After
, &m_pCert
->validity
.notAfter
) ;
139 //Convert the time to readable local time
140 PR_ExplodeTime( notAfter
, PR_LocalTimeParameters
, &explTime
) ;
142 dateTime
.NanoSeconds
= static_cast< sal_Int16
>( explTime
.tm_usec
* ::tools::Time::nanoPerMicro
);
143 dateTime
.Seconds
= static_cast< sal_Int16
>( explTime
.tm_sec
);
144 dateTime
.Minutes
= static_cast< sal_Int16
>( explTime
.tm_min
);
145 dateTime
.Hours
= static_cast< sal_Int16
>( explTime
.tm_hour
);
146 dateTime
.Day
= static_cast< sal_Int16
>( explTime
.tm_mday
);
147 dateTime
.Month
= static_cast< sal_Int16
>( explTime
.tm_month
+1 );
148 dateTime
.Year
= static_cast< sal_Int16
>( explTime
.tm_year
);
156 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getIssuerUniqueID() {
157 if( m_pCert
!= nullptr && m_pCert
->issuerID
.len
> 0 ) {
158 Sequence
< sal_Int8
> issuerUid( m_pCert
->issuerID
.len
) ;
159 for( unsigned int i
= 0 ; i
< m_pCert
->issuerID
.len
; i
++ )
160 issuerUid
[i
] = *( m_pCert
->issuerID
.data
+ i
) ;
164 return css::uno::Sequence
< sal_Int8
>();
168 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getSubjectUniqueID() {
169 if( m_pCert
!= nullptr && m_pCert
->subjectID
.len
> 0 ) {
170 Sequence
< sal_Int8
> subjectUid( m_pCert
->subjectID
.len
) ;
171 for( unsigned int i
= 0 ; i
< m_pCert
->subjectID
.len
; i
++ )
172 subjectUid
[i
] = *( m_pCert
->subjectID
.data
+ i
) ;
176 return css::uno::Sequence
< sal_Int8
>();
180 css::uno::Sequence
< css::uno::Reference
< css::security::XCertificateExtension
> > SAL_CALL
X509Certificate_NssImpl::getExtensions() {
181 if( m_pCert
!= nullptr && m_pCert
->extensions
!= nullptr ) {
182 CERTCertExtension
** extns
;
185 for( len
= 0, extns
= m_pCert
->extensions
; *extns
!= nullptr; len
++, extns
++ ) ;
186 Sequence
< Reference
< XCertificateExtension
> > xExtns( len
) ;
188 for( extns
= m_pCert
->extensions
, len
= 0; *extns
!= nullptr; extns
++, len
++ ) {
189 const SECItem id
= (*extns
)->id
;
190 OString
oidString(CERT_GetOidString(&id
));
193 if( (*extns
)->critical
.data
== nullptr )
196 crit
= (*extns
)->critical
.data
[0] == 0xFF;
198 // remove "OID." prefix if existing
201 if (oidString
.match(oid
))
202 objID
= oidString
.copy(oid
.getLength());
206 unsigned char* value
= (*extns
)->value
.data
;
207 unsigned int vlen
= (*extns
)->value
.len
;
208 unsigned char* objid
= reinterpret_cast<unsigned char *>(const_cast<char *>(objID
.getStr()));
209 unsigned int objidlen
= objID
.getLength();
211 if (objID
== "2.5.29.17")
213 SanExtensionImpl
* pExtn
= new SanExtensionImpl
;
214 pExtn
->setCertExtn(value
, vlen
, objid
, objidlen
, crit
);
215 xExtns
[len
] = pExtn
;
219 CertificateExtension_XmlSecImpl
* pExtn
= new CertificateExtension_XmlSecImpl
;
220 pExtn
->setCertExtn(value
, vlen
, objid
, objidlen
, crit
);
227 return css::uno::Sequence
< css::uno::Reference
< css::security::XCertificateExtension
> > ();
231 css::uno::Reference
< css::security::XCertificateExtension
> SAL_CALL
X509Certificate_NssImpl::findCertificateExtension( const css::uno::Sequence
< sal_Int8
>& oid
) {
232 if( m_pCert
!= nullptr && m_pCert
->extensions
!= nullptr ) {
233 CERTCertExtension
** extns
;
236 idItem
.data
= reinterpret_cast<unsigned char *>(const_cast<sal_Int8
*>(oid
.getConstArray()));
237 idItem
.len
= oid
.getLength() ;
239 css::uno::Reference
<css::security::XCertificateExtension
> xExtn
;
240 for( extns
= m_pCert
->extensions
; *extns
!= nullptr; extns
++ ) {
241 if( SECITEM_CompareItem( &idItem
, &(*extns
)->id
) == SECEqual
) {
242 const SECItem id
= (*extns
)->id
;
243 OString
objId(CERT_GetOidString(&id
));
246 if( (*extns
)->critical
.data
== nullptr )
249 crit
= (*extns
)->critical
.data
[0] == 0xFF;
251 unsigned char* value
= (*extns
)->value
.data
;
252 unsigned int vlen
= (*extns
)->value
.len
;
253 unsigned char* objid
= (*extns
)->id
.data
;
254 unsigned int objidlen
= (*extns
)->id
.len
;
256 if ( objId
== "OID.2.5.29.17" )
258 rtl::Reference
<SanExtensionImpl
> xSanImpl(
259 new SanExtensionImpl
);
260 xSanImpl
->setCertExtn(value
, vlen
, objid
, objidlen
, crit
);
261 xExtn
= xSanImpl
.get();
265 rtl::Reference
<CertificateExtension_XmlSecImpl
> xSecImpl(
266 new CertificateExtension_XmlSecImpl
);
267 xSecImpl
->setCertExtn(value
, vlen
, objid
, objidlen
, crit
);
268 xExtn
= xSecImpl
.get();
281 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getEncoded() {
282 if( m_pCert
!= nullptr && m_pCert
->derCert
.len
> 0 ) {
283 Sequence
< sal_Int8
> rawCert( m_pCert
->derCert
.len
) ;
285 for( unsigned int i
= 0 ; i
< m_pCert
->derCert
.len
; i
++ )
286 rawCert
[i
] = *( m_pCert
->derCert
.data
+ i
) ;
290 return css::uno::Sequence
< sal_Int8
>();
295 void X509Certificate_NssImpl::setCert( CERTCertificate
* cert
) {
296 if( m_pCert
!= nullptr ) {
297 CERT_DestroyCertificate( m_pCert
) ;
301 if( cert
!= nullptr ) {
302 m_pCert
= CERT_DupCertificate( cert
) ;
306 const CERTCertificate
* X509Certificate_NssImpl::getNssCert() const {
307 if( m_pCert
!= nullptr ) {
314 void X509Certificate_NssImpl::setRawCert( const Sequence
< sal_Int8
>& rawCert
) {
315 CERTCertificate
* cert
;
318 certItem
.data
= reinterpret_cast<unsigned char *>(const_cast<sal_Int8
*>(rawCert
.getConstArray()));
319 certItem
.len
= rawCert
.getLength() ;
321 cert
= CERT_DecodeDERCertificate( &certItem
, PR_TRUE
, nullptr ) ;
322 if( cert
== nullptr )
323 throw RuntimeException() ;
325 if( m_pCert
!= nullptr ) {
326 CERT_DestroyCertificate( m_pCert
) ;
333 SECKEYPrivateKey
* X509Certificate_NssImpl::getPrivateKey()
335 if (m_pCert
&& m_pCert
->slot
)
337 SECKEYPrivateKey
* pPrivateKey
= PK11_FindPrivateKeyFromCert(m_pCert
->slot
, m_pCert
, nullptr);
345 sal_Int64 SAL_CALL
X509Certificate_NssImpl::getSomething( const Sequence
< sal_Int8
>& aIdentifier
) {
346 if( isUnoTunnelId
<X509Certificate_NssImpl
>(aIdentifier
) ) {
347 return sal::static_int_cast
<sal_Int64
>(reinterpret_cast<sal_uIntPtr
>(this));
352 /* XUnoTunnel extension */
356 class theX509Certificate_NssImplUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theX509Certificate_NssImplUnoTunnelId
> {};
359 const Sequence
< sal_Int8
>& X509Certificate_NssImpl::getUnoTunnelId() {
360 return theX509Certificate_NssImplUnoTunnelId::get().getSeq();
363 static OUString
getAlgorithmDescription(SECAlgorithmID
const *aid
)
366 tag
= SECOID_GetAlgorithmTag(aid
);
368 const char *pDesc
= SECOID_FindOIDTagDescription(tag
);
370 return OUString::createFromAscii( pDesc
) ;
373 static css::uno::Sequence
< sal_Int8
> getThumbprint(CERTCertificate
const *pCert
, SECOidTag id
)
375 if( pCert
!= nullptr )
378 unsigned char fingerprint
[32];
386 length
= SHA1_LENGTH
;
389 length
= SHA256_LENGTH
;
395 memset(fingerprint
, 0, sizeof fingerprint
);
396 rv
= PK11_HashBuf(id
, fingerprint
, pCert
->derCert
.data
, pCert
->derCert
.len
);
399 Sequence
< sal_Int8
> thumbprint( length
) ;
400 for( int i
= 0 ; i
< length
; i
++ )
401 thumbprint
[i
] = fingerprint
[i
];
406 return css::uno::Sequence
< sal_Int8
>();
409 OUString SAL_CALL
X509Certificate_NssImpl::getSubjectPublicKeyAlgorithm()
411 if( m_pCert
!= nullptr )
413 return getAlgorithmDescription(&(m_pCert
->subjectPublicKeyInfo
.algorithm
));
421 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getSubjectPublicKeyValue()
423 if( m_pCert
!= nullptr )
425 SECItem spk
= m_pCert
->subjectPublicKeyInfo
.subjectPublicKey
;
426 DER_ConvertBitString(&spk
);
430 Sequence
< sal_Int8
> key( spk
.len
) ;
431 for( unsigned int i
= 0 ; i
< spk
.len
; i
++ )
433 key
[i
] = *( spk
.data
+ i
) ;
440 return css::uno::Sequence
< sal_Int8
>();
443 OUString SAL_CALL
X509Certificate_NssImpl::getSignatureAlgorithm()
445 if( m_pCert
!= nullptr )
447 return getAlgorithmDescription(&(m_pCert
->signature
));
455 svl::crypto::SignatureMethodAlgorithm
X509Certificate_NssImpl::getSignatureMethodAlgorithm()
457 svl::crypto::SignatureMethodAlgorithm nRet
= svl::crypto::SignatureMethodAlgorithm::RSA
;
462 SECOidTag eTag
= SECOID_GetAlgorithmTag(&m_pCert
->subjectPublicKeyInfo
.algorithm
);
463 if (eTag
== SEC_OID_ANSIX962_EC_PUBLIC_KEY
)
464 nRet
= svl::crypto::SignatureMethodAlgorithm::ECDSA
;
469 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getSHA1Thumbprint()
471 return getThumbprint(m_pCert
, SEC_OID_SHA1
);
474 uno::Sequence
<sal_Int8
> X509Certificate_NssImpl::getSHA256Thumbprint()
476 return getThumbprint(m_pCert
, SEC_OID_SHA256
);
479 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_NssImpl::getMD5Thumbprint()
481 return getThumbprint(m_pCert
, SEC_OID_MD5
);
484 CertificateKind SAL_CALL
X509Certificate_NssImpl::getCertificateKind()
486 return CertificateKind_X509
;
489 sal_Int32 SAL_CALL
X509Certificate_NssImpl::getCertificateUsage( )
495 rv
= CERT_FindKeyUsageExtension(m_pCert
, &tmpitem
);
496 if ( rv
== SECSuccess
)
498 usage
= tmpitem
.data
[0];
499 PORT_Free(tmpitem
.data
);
500 tmpitem
.data
= nullptr;
508 * to make the nss implementation compatible with MSCrypto,
509 * the following usage is ignored
512 if ( CERT_GovtApprovedBitSet(m_pCert) )
514 usage |= KU_NS_GOVT_APPROVED;
522 OUString SAL_CALL
X509Certificate_NssImpl::getImplementationName()
524 return "com.sun.star.xml.security.gpg.XCertificate_NssImpl";
528 sal_Bool SAL_CALL
X509Certificate_NssImpl::supportsService(const OUString
& serviceName
)
530 return cppu::supportsService(this, serviceName
);
534 Sequence
<OUString
> SAL_CALL
X509Certificate_NssImpl::getSupportedServiceNames() { return { OUString() }; }
536 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */