1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmlsecurity.hxx"
30 #include <sal/config.h>
32 #include "x509certificate_mscryptimpl.hxx"
33 #include "certificateextension_xmlsecimpl.hxx"
40 #include <rtl/locale.h>
41 #include <osl/nlsupport.h>
42 #include <osl/process.h>
47 using namespace ::com::sun::star::uno
;
48 using namespace ::com::sun::star::security
;
49 using ::rtl::OUString
;
51 using ::com::sun::star::security::XCertificate
;
52 using ::com::sun::star::util::DateTime
;
54 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
56 /*Resturns the index withing rRawString where sTypeName starts and where it ends.
57 The starting index is pair.first. The ending index in pair.second points
58 one char after the last character of the type.
60 "S" or "CN" (without ""). Do not use spaces at the beginning of the type name.
61 If the type name is not found then pair.first and pair.second are -1.
63 std::pair
< sal_Int32
, sal_Int32
>
64 findTypeInDN(const OUString
& rRawString
, const OUString
& sTypeName
)
66 std::pair
< sal_Int32
, sal_Int32
> retVal
;
67 bool bInEscape
= false;
68 bool bInValue
= false;
70 sal_Int32 nTypeNameStart
= 0;
71 sal_Int32 length
= rRawString
.getLength();
73 for (sal_Int32 i
= 0; i
< length
; i
++)
75 sal_Unicode c
= rRawString
[i
];
81 OUString sType
= rRawString
.copy(nTypeNameStart
, i
- nTypeNameStart
);
83 if (sType
.equalsIgnoreAsciiCase(sTypeName
))
94 //If this is the quote is the first of the couple which enclose the
95 //whole value, because the value contains special characters
96 //then we just drop it. That is, this character must be followed by
97 //a character which is not '"'.
98 if ( i
+ 1 < length
&& rRawString
[i
+1] == '"')
101 bInValue
= !bInValue
; //value is enclosed in " "
105 //This quote is escaped by a preceding quote and therefore is
110 else if (c
== ',' || c
== '+')
112 //The comma separate the attribute value pairs.
113 //If the comma is not part of a value (the value would then be enclosed in '"'),
114 //then we have reached the end of the value
117 //The next char is the start of the new type
118 nTypeNameStart
= i
+ 1;
123 //Found the Type Name, but there can still be spaces after the last comma
124 //and the beginning of the type.
129 sal_Unicode c
= rRawString
[nTypeNameStart
];
130 if (c
!= ' ' && c
!= '\t')
135 // search end (one after last letter)
136 sal_Int32 nTypeNameEnd
= nTypeNameStart
;
140 sal_Unicode c
= rRawString
[nTypeNameEnd
];
141 if (c
== ' ' || c
== '\t' || c
== '=')
145 retVal
= std::make_pair(nTypeNameStart
, nTypeNameEnd
);
149 retVal
= std::make_pair(-1, -1);
156 MS Crypto uses the 'S' tag (equal to the 'ST' tag in NSS), but the NSS can't recognise
157 it, so the 'S' tag should be changed to 'ST' tag. However I am not sure if this is necessary
158 anymore, because we provide always the signers certificate when signing. So libmlsec can find
159 the private key based on the provided certificate (X509Certificate element) and does not need
160 the issuer name (X509IssuerName element). The issuer name in the xml signature has also no
161 effect for the signature nor the certificate validation.
162 In many RFCs, for example 4519, on speaks of 'ST'. However, the certificate does not contain
163 strings for type names. Instead it uses OIDs.
166 OUString
replaceTagSWithTagST(OUString oldDN
)
168 std::pair
<sal_Int32
, sal_Int32
> pairIndex
= findTypeInDN(oldDN
, OUSTR("S"));
170 if (pairIndex
.first
!= -1)
172 OUString newDN
= oldDN
.copy(0, pairIndex
.first
);
173 newDN
+= OUSTR("ST");
174 newDN
+= oldDN
.copy(pairIndex
.second
);
181 X509Certificate_MSCryptImpl :: X509Certificate_MSCryptImpl() :
182 m_pCertContext( NULL
)
186 X509Certificate_MSCryptImpl :: ~X509Certificate_MSCryptImpl() {
187 if( m_pCertContext
!= NULL
) {
188 CertFreeCertificateContext( m_pCertContext
) ;
192 //Methods from XCertificate
193 sal_Int16 SAL_CALL
X509Certificate_MSCryptImpl :: getVersion() throw ( ::com::sun::star::uno::RuntimeException
) {
194 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
195 return ( char )m_pCertContext
->pCertInfo
->dwVersion
;
201 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl :: getSerialNumber() throw ( ::com::sun::star::uno::RuntimeException
) {
202 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
203 Sequence
< sal_Int8
> serial( m_pCertContext
->pCertInfo
->SerialNumber
.cbData
) ;
204 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->SerialNumber
.cbData
; i
++ )
205 serial
[i
] = *( m_pCertContext
->pCertInfo
->SerialNumber
.pbData
+ m_pCertContext
->pCertInfo
->SerialNumber
.cbData
- i
- 1 ) ;
213 ::rtl::OUString SAL_CALL
X509Certificate_MSCryptImpl :: getIssuerName() throw ( ::com::sun::star::uno::RuntimeException
) {
214 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
218 cbIssuer
= CertNameToStr(
219 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
220 &( m_pCertContext
->pCertInfo
->Issuer
),
221 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
225 // Here the cbIssuer count the last 0x00 , take care.
226 if( cbIssuer
!= 0 ) {
227 issuer
= new char[ cbIssuer
] ;
229 throw RuntimeException() ;
231 cbIssuer
= CertNameToStr(
232 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
233 &( m_pCertContext
->pCertInfo
->Issuer
),
234 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
238 if( cbIssuer
<= 0 ) {
240 throw RuntimeException() ;
243 // By CP , for correct encoding
244 sal_uInt16 encoding
;
245 rtl_Locale
*pLocale
= NULL
;
246 osl_getProcessLocale( &pLocale
) ;
247 encoding
= osl_getTextEncodingFromLocale( pLocale
) ;
250 if(issuer
[cbIssuer
-1] == 0) cbIssuer
--; //delimit the last 0x00;
251 OUString
xIssuer(issuer
, cbIssuer
,encoding
) ; //By CP
254 return replaceTagSWithTagST(xIssuer
);
263 ::rtl::OUString SAL_CALL
X509Certificate_MSCryptImpl :: getSubjectName() throw ( ::com::sun::star::uno::RuntimeException
)
265 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
)
270 cbSubject
= CertNameToStrW(
271 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
272 &( m_pCertContext
->pCertInfo
->Subject
),
273 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
279 subject
= new wchar_t[ cbSubject
] ;
280 if( subject
== NULL
)
281 throw RuntimeException() ;
283 cbSubject
= CertNameToStrW(
284 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
285 &( m_pCertContext
->pCertInfo
->Subject
),
286 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
290 if( cbSubject
<= 0 ) {
292 throw RuntimeException() ;
295 OUString
xSubject(reinterpret_cast<const sal_Unicode
*>(subject
));
298 return replaceTagSWithTagST(xSubject
);
310 ::com::sun::star::util::DateTime SAL_CALL
X509Certificate_MSCryptImpl :: getNotValidBefore() throw ( ::com::sun::star::uno::RuntimeException
) {
311 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
312 SYSTEMTIME explTime
;
314 FILETIME localFileTime
;
316 if (FileTimeToLocalFileTime(&( m_pCertContext
->pCertInfo
->NotBefore
), &localFileTime
))
318 if( FileTimeToSystemTime( &localFileTime
, &explTime
) ) {
319 //Convert the time to readable local time
320 dateTime
.HundredthSeconds
= explTime
.wMilliseconds
/ 100 ;
321 dateTime
.Seconds
= explTime
.wSecond
;
322 dateTime
.Minutes
= explTime
.wMinute
;
323 dateTime
.Hours
= explTime
.wHour
;
324 dateTime
.Day
= explTime
.wDay
;
325 dateTime
.Month
= explTime
.wMonth
;
326 dateTime
.Year
= explTime
.wYear
;
336 ::com::sun::star::util::DateTime SAL_CALL
X509Certificate_MSCryptImpl :: getNotValidAfter() throw ( ::com::sun::star::uno::RuntimeException
) {
337 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
338 SYSTEMTIME explTime
;
340 FILETIME localFileTime
;
342 if (FileTimeToLocalFileTime(&( m_pCertContext
->pCertInfo
->NotAfter
), &localFileTime
))
344 if( FileTimeToSystemTime( &localFileTime
, &explTime
) ) {
345 //Convert the time to readable local time
346 dateTime
.HundredthSeconds
= explTime
.wMilliseconds
/ 100 ;
347 dateTime
.Seconds
= explTime
.wSecond
;
348 dateTime
.Minutes
= explTime
.wMinute
;
349 dateTime
.Hours
= explTime
.wHour
;
350 dateTime
.Day
= explTime
.wDay
;
351 dateTime
.Month
= explTime
.wMonth
;
352 dateTime
.Year
= explTime
.wYear
;
362 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl :: getIssuerUniqueID() throw ( ::com::sun::star::uno::RuntimeException
) {
363 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
364 Sequence
< sal_Int8
> issuerUid( m_pCertContext
->pCertInfo
->IssuerUniqueId
.cbData
) ;
365 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->IssuerUniqueId
.cbData
; i
++ )
366 issuerUid
[i
] = *( m_pCertContext
->pCertInfo
->IssuerUniqueId
.pbData
+ i
) ;
374 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl :: getSubjectUniqueID() throw ( ::com::sun::star::uno::RuntimeException
) {
375 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
) {
376 Sequence
< sal_Int8
> subjectUid( m_pCertContext
->pCertInfo
->SubjectUniqueId
.cbData
) ;
377 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->SubjectUniqueId
.cbData
; i
++ )
378 subjectUid
[i
] = *( m_pCertContext
->pCertInfo
->SubjectUniqueId
.pbData
+ i
) ;
386 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Reference
< ::com::sun::star::security::XCertificateExtension
> > SAL_CALL
X509Certificate_MSCryptImpl :: getExtensions() throw ( ::com::sun::star::uno::RuntimeException
) {
387 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
&& m_pCertContext
->pCertInfo
->cExtension
!= 0 ) {
388 CertificateExtension_XmlSecImpl
* xExtn
;
389 CERT_EXTENSION
* pExtn
;
390 Sequence
< Reference
< XCertificateExtension
> > xExtns( m_pCertContext
->pCertInfo
->cExtension
) ;
392 for( unsigned int i
= 0; i
< m_pCertContext
->pCertInfo
->cExtension
; i
++ ) {
393 pExtn
= &(m_pCertContext
->pCertInfo
->rgExtension
[i
]) ;
395 xExtn
= new CertificateExtension_XmlSecImpl() ;
397 throw RuntimeException() ;
399 xExtn
->setCertExtn( pExtn
->Value
.pbData
, pExtn
->Value
.cbData
, ( unsigned char* )pExtn
->pszObjId
, strlen( pExtn
->pszObjId
), sal::static_int_cast
<sal_Bool
>(pExtn
->fCritical
) ) ;
410 ::com::sun::star::uno::Reference
< ::com::sun::star::security::XCertificateExtension
> SAL_CALL
X509Certificate_MSCryptImpl :: findCertificateExtension( const ::com::sun::star::uno::Sequence
< sal_Int8
>& /*oid*/ ) throw (::com::sun::star::uno::RuntimeException
) {
411 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
&& m_pCertContext
->pCertInfo
->cExtension
!= 0 ) {
412 CertificateExtension_XmlSecImpl
* xExtn
;
413 CERT_EXTENSION
* pExtn
;
414 Sequence
< Reference
< XCertificateExtension
> > xExtns( m_pCertContext
->pCertInfo
->cExtension
) ;
417 for( unsigned int i
= 0; i
< m_pCertContext
->pCertInfo
->cExtension
; i
++ ) {
418 pExtn
= &( m_pCertContext
->pCertInfo
->rgExtension
[i
] ) ;
420 //TODO: Compare the oid
422 xExtn
= new CertificateExtension_XmlSecImpl() ;
424 throw RuntimeException() ;
426 xExtn
->setCertExtn( pExtn
->Value
.pbData
, pExtn
->Value
.cbData
, ( unsigned char* )pExtn
->pszObjId
, strlen( pExtn
->pszObjId
), sal::static_int_cast
<sal_Bool
>(pExtn
->fCritical
) ) ;
437 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl :: getEncoded() throw ( ::com::sun::star::uno::RuntimeException
) {
438 if( m_pCertContext
!= NULL
&& m_pCertContext
->cbCertEncoded
> 0 ) {
439 Sequence
< sal_Int8
> rawCert( m_pCertContext
->cbCertEncoded
) ;
441 for( unsigned int i
= 0 ; i
< m_pCertContext
->cbCertEncoded
; i
++ )
442 rawCert
[i
] = *( m_pCertContext
->pbCertEncoded
+ i
) ;
451 void X509Certificate_MSCryptImpl :: setMswcryCert( const CERT_CONTEXT
* cert
) {
452 if( m_pCertContext
!= NULL
) {
453 CertFreeCertificateContext( m_pCertContext
) ;
454 m_pCertContext
= NULL
;
458 m_pCertContext
= CertDuplicateCertificateContext( cert
) ;
462 const CERT_CONTEXT
* X509Certificate_MSCryptImpl :: getMswcryCert() const {
463 if( m_pCertContext
!= NULL
) {
464 return m_pCertContext
;
470 void X509Certificate_MSCryptImpl :: setRawCert( Sequence
< sal_Int8
> rawCert
) throw ( ::com::sun::star::uno::RuntimeException
) {
471 if( m_pCertContext
!= NULL
) {
472 CertFreeCertificateContext( m_pCertContext
) ;
473 m_pCertContext
= NULL
;
476 if( rawCert
.getLength() != 0 ) {
477 m_pCertContext
= CertCreateCertificateContext( X509_ASN_ENCODING
, ( const BYTE
* )&rawCert
[0], rawCert
.getLength() ) ;
482 sal_Int64 SAL_CALL
X509Certificate_MSCryptImpl :: getSomething( const Sequence
< sal_Int8
>& aIdentifier
) throw( RuntimeException
) {
483 if( aIdentifier
.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), aIdentifier
.getConstArray(), 16 ) ) {
484 return ( sal_Int64
)this ;
489 /* XUnoTunnel extension */
490 const Sequence
< sal_Int8
>& X509Certificate_MSCryptImpl :: getUnoTunnelId() {
491 static Sequence
< sal_Int8
>* pSeq
= 0 ;
493 ::osl::Guard
< ::osl::Mutex
> aGuard( ::osl::Mutex::getGlobalMutex() ) ;
495 static Sequence
< sal_Int8
> aSeq( 16 ) ;
496 rtl_createUuid( ( sal_uInt8
* )aSeq
.getArray() , 0 , sal_True
) ;
503 /* XUnoTunnel extension */
504 X509Certificate_MSCryptImpl
* X509Certificate_MSCryptImpl :: getImplementation( const Reference
< XInterface
> xObj
) {
505 Reference
< XUnoTunnel
> xUT( xObj
, UNO_QUERY
) ;
507 return ( X509Certificate_MSCryptImpl
* )xUT
->getSomething( getUnoTunnelId() ) ;
513 ::rtl::OUString
findOIDDescription(char *oid
)
515 OUString ouOID
= OUString::createFromAscii( oid
);
516 for (int i
=0; i
<nOID
; i
++)
518 OUString item
= OUString::createFromAscii( OIDs
[i
].oid
);
521 return OUString::createFromAscii( OIDs
[i
].desc
);
528 ::com::sun::star::uno::Sequence
< sal_Int8
> getThumbprint(const CERT_CONTEXT
* pCertContext
, DWORD dwPropId
)
530 if( pCertContext
!= NULL
)
533 unsigned char fingerprint
[20];
534 if (CertGetCertificateContextProperty(pCertContext
, dwPropId
, (void*)fingerprint
, &cbData
))
536 Sequence
< sal_Int8
> thumbprint( cbData
) ;
537 for( unsigned int i
= 0 ; i
< cbData
; i
++ )
539 thumbprint
[i
] = fingerprint
[i
];
546 DWORD e
= GetLastError();
554 ::rtl::OUString SAL_CALL
X509Certificate_MSCryptImpl::getSubjectPublicKeyAlgorithm()
555 throw ( ::com::sun::star::uno::RuntimeException
)
557 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
)
559 CRYPT_ALGORITHM_IDENTIFIER algorithm
= m_pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
;
560 return findOIDDescription( algorithm
.pszObjId
) ;
568 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSubjectPublicKeyValue()
569 throw ( ::com::sun::star::uno::RuntimeException
)
571 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
)
573 CRYPT_BIT_BLOB publicKey
= m_pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
;
575 Sequence
< sal_Int8
> key( publicKey
.cbData
) ;
576 for( unsigned int i
= 0 ; i
< publicKey
.cbData
; i
++ )
578 key
[i
] = *(publicKey
.pbData
+ i
) ;
589 ::rtl::OUString SAL_CALL
X509Certificate_MSCryptImpl::getSignatureAlgorithm()
590 throw ( ::com::sun::star::uno::RuntimeException
)
592 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
)
594 CRYPT_ALGORITHM_IDENTIFIER algorithm
= m_pCertContext
->pCertInfo
->SignatureAlgorithm
;
595 return findOIDDescription( algorithm
.pszObjId
) ;
603 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSHA1Thumbprint()
604 throw ( ::com::sun::star::uno::RuntimeException
)
606 return getThumbprint(m_pCertContext
, CERT_SHA1_HASH_PROP_ID
);
609 ::com::sun::star::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getMD5Thumbprint()
610 throw ( ::com::sun::star::uno::RuntimeException
)
612 return getThumbprint(m_pCertContext
, CERT_MD5_HASH_PROP_ID
);
615 sal_Int32 SAL_CALL
X509Certificate_MSCryptImpl::getCertificateUsage( )
616 throw ( ::com::sun::star::uno::RuntimeException
)
619 CERT_DATA_ENCIPHERMENT_KEY_USAGE
|
620 CERT_DIGITAL_SIGNATURE_KEY_USAGE
|
621 CERT_KEY_AGREEMENT_KEY_USAGE
|
622 CERT_KEY_CERT_SIGN_KEY_USAGE
|
623 CERT_KEY_ENCIPHERMENT_KEY_USAGE
|
624 CERT_NON_REPUDIATION_KEY_USAGE
|
625 CERT_OFFLINE_CRL_SIGN_KEY_USAGE
;
627 if( m_pCertContext
!= NULL
&& m_pCertContext
->pCertInfo
!= NULL
&& m_pCertContext
->pCertInfo
->cExtension
!= 0 )
629 CERT_EXTENSION
* pExtn
= CertFindExtension(
631 m_pCertContext
->pCertInfo
->cExtension
,
632 m_pCertContext
->pCertInfo
->rgExtension
);
636 CERT_KEY_USAGE_RESTRICTION_INFO keyUsage
;
637 DWORD length
= sizeof(CERT_KEY_USAGE_RESTRICTION_INFO
);
639 bool rc
= CryptDecodeObject(
644 CRYPT_DECODE_NOCOPY_FLAG
,
648 if (rc
&& keyUsage
.RestrictedKeyUsage
.cbData
!=0)
650 usage
= (sal_Int32
)keyUsage
.RestrictedKeyUsage
.pbData
;