Bump version to 5.0-14
[LibreOffice.git] / xmlsecurity / source / xmlsec / mscrypt / x509certificate_mscryptimpl.cxx
blob2259c1d704db5c7abe3a7e73900227954bd4602a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <string.h>
22 #include <sal/config.h>
23 #include <comphelper/servicehelper.hxx>
24 #include "x509certificate_mscryptimpl.hxx"
25 #include "certificateextension_xmlsecimpl.hxx"
26 #include "sanextension_mscryptimpl.hxx"
28 #include "oid.hxx"
30 #include <rtl/locale.h>
31 #include <osl/nlsupport.h>
32 #include <osl/process.h>
33 #include <utility>
34 #include <tools/time.hxx>
36 using namespace ::com::sun::star::uno ;
37 using namespace ::com::sun::star::security ;
39 using ::com::sun::star::security::XCertificate ;
40 using ::com::sun::star::util::DateTime ;
42 /*Resturns the index within rRawString where sTypeName starts and where it ends.
43 The starting index is pair.first. The ending index in pair.second points
44 one char after the last character of the type.
45 sTypeName can be
46 "S" or "CN" (without ""). Do not use spaces at the beginning of the type name.
47 If the type name is not found then pair.first and pair.second are -1.
49 std::pair< sal_Int32, sal_Int32 >
50 findTypeInDN(const OUString& rRawString, const OUString& sTypeName)
52 std::pair< sal_Int32, sal_Int32 > retVal;
53 bool bInEscape = false;
54 bool bInValue = false;
55 bool bFound = false;
56 sal_Int32 nTypeNameStart = 0;
57 sal_Int32 length = rRawString.getLength();
59 for (sal_Int32 i = 0; i < length; i++)
61 sal_Unicode c = rRawString[i];
63 if (c == '=')
65 if (! bInValue)
67 OUString sType = rRawString.copy(nTypeNameStart, i - nTypeNameStart);
68 sType = sType.trim();
69 if (sType.equalsIgnoreAsciiCase(sTypeName))
71 bFound = true;
72 break;
76 else if (c == '"')
78 if (!bInEscape)
80 //If this is the quote is the first of the couple which enclose the
81 //whole value, because the value contains special characters
82 //then we just drop it. That is, this character must be followed by
83 //a character which is not '"'.
84 if ( i + 1 < length && rRawString[i+1] == '"')
85 bInEscape = true;
86 else
87 bInValue = !bInValue; //value is enclosed in " "
89 else
91 //This quote is escaped by a preceding quote and therefore is
92 //part of the value
93 bInEscape = false;
96 else if (c == ',' || c == '+')
98 //The comma separate the attribute value pairs.
99 //If the comma is not part of a value (the value would then be enclosed in '"'),
100 //then we have reached the end of the value
101 if (!bInValue)
103 //The next char is the start of the new type
104 nTypeNameStart = i + 1;
109 //Found the Type Name, but there can still be spaces after the last comma
110 //and the beginning of the type.
111 if (bFound)
113 while (true)
115 sal_Unicode c = rRawString[nTypeNameStart];
116 if (c != ' ' && c != '\t')
117 //found
118 break;
119 nTypeNameStart ++;
121 // search end (one after last letter)
122 sal_Int32 nTypeNameEnd = nTypeNameStart;
123 nTypeNameEnd++;
124 while (true)
126 sal_Unicode c = rRawString[nTypeNameEnd];
127 if (c == ' ' || c == '\t' || c == '=')
128 break;
129 nTypeNameEnd++;
131 retVal = std::make_pair(nTypeNameStart, nTypeNameEnd);
133 else
135 retVal = std::make_pair(-1, -1);
137 return retVal;
142 MS Crypto uses the 'S' tag (equal to the 'ST' tag in NSS), but the NSS can't recognise
143 it, so the 'S' tag should be changed to 'ST' tag. However I am not sure if this is necessary
144 anymore, because we provide always the signers certificate when signing. So libmlsec can find
145 the private key based on the provided certificate (X509Certificate element) and does not need
146 the issuer name (X509IssuerName element). The issuer name in the xml signature has also no
147 effect for the signature nor the certificate validation.
148 In many RFCs, for example 4519, on speaks of 'ST'. However, the certificate does not contain
149 strings for type names. Instead it uses OIDs.
152 OUString replaceTagSWithTagST(OUString oldDN)
154 std::pair<sal_Int32, sal_Int32 > pairIndex = findTypeInDN(oldDN, "S");
156 if (pairIndex.first != -1)
158 OUString newDN = oldDN.copy(0, pairIndex.first);
159 newDN += "ST";
160 newDN += oldDN.copy(pairIndex.second);
161 return newDN;
163 return oldDN;
165 /* end */
167 X509Certificate_MSCryptImpl :: X509Certificate_MSCryptImpl() :
168 m_pCertContext( NULL )
172 X509Certificate_MSCryptImpl :: ~X509Certificate_MSCryptImpl() {
173 if( m_pCertContext != NULL ) {
174 CertFreeCertificateContext( m_pCertContext ) ;
178 //Methods from XCertificate
179 sal_Int16 SAL_CALL X509Certificate_MSCryptImpl :: getVersion() throw ( ::com::sun::star::uno::RuntimeException) {
180 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
181 return ( char )m_pCertContext->pCertInfo->dwVersion ;
182 } else {
183 return -1 ;
187 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl :: getSerialNumber() throw ( ::com::sun::star::uno::RuntimeException) {
188 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
189 Sequence< sal_Int8 > serial( m_pCertContext->pCertInfo->SerialNumber.cbData ) ;
190 for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SerialNumber.cbData ; i ++ )
191 serial[i] = *( m_pCertContext->pCertInfo->SerialNumber.pbData + m_pCertContext->pCertInfo->SerialNumber.cbData - i - 1 ) ;
193 return serial ;
194 } else {
195 return Sequence< sal_Int8 >();
199 OUString SAL_CALL X509Certificate_MSCryptImpl :: getIssuerName() throw ( ::com::sun::star::uno::RuntimeException) {
200 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
201 DWORD cbIssuer ;
203 cbIssuer = CertNameToStr(
204 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
205 &( m_pCertContext->pCertInfo->Issuer ),
206 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
207 NULL, 0
210 // Here the cbIssuer count the last 0x00 , take care.
211 if( cbIssuer != 0 ) {
212 char* issuer = new char[ cbIssuer ] ;
214 cbIssuer = CertNameToStr(
215 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
216 &( m_pCertContext->pCertInfo->Issuer ),
217 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
218 issuer, cbIssuer
221 if( cbIssuer <= 0 ) {
222 delete [] issuer ;
223 throw RuntimeException() ;
226 // for correct encoding
227 sal_uInt16 encoding ;
228 rtl_Locale *pLocale = NULL ;
229 osl_getProcessLocale( &pLocale ) ;
230 encoding = osl_getTextEncodingFromLocale( pLocale ) ;
232 if(issuer[cbIssuer-1] == 0) cbIssuer--; //delimit the last 0x00;
233 OUString xIssuer(issuer , cbIssuer ,encoding ) ;
234 delete [] issuer ;
236 return replaceTagSWithTagST(xIssuer);
237 } else {
238 return OUString() ;
240 } else {
241 return OUString() ;
245 OUString SAL_CALL X509Certificate_MSCryptImpl :: getSubjectName() throw ( ::com::sun::star::uno::RuntimeException)
247 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL )
249 DWORD cbSubject ;
251 cbSubject = CertNameToStrW(
252 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
253 &( m_pCertContext->pCertInfo->Subject ),
254 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
255 NULL, 0
258 if( cbSubject != 0 )
260 wchar_t* subject = new wchar_t[ cbSubject ] ;
262 cbSubject = CertNameToStrW(
263 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING ,
264 &( m_pCertContext->pCertInfo->Subject ),
265 CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG ,
266 subject, cbSubject
269 if( cbSubject <= 0 ) {
270 delete [] subject ;
271 throw RuntimeException() ;
274 OUString xSubject(reinterpret_cast<const sal_Unicode*>(subject));
275 delete [] subject ;
277 return replaceTagSWithTagST(xSubject);
278 } else
280 return OUString() ;
283 else
285 return OUString() ;
289 ::com::sun::star::util::DateTime SAL_CALL X509Certificate_MSCryptImpl :: getNotValidBefore() throw ( ::com::sun::star::uno::RuntimeException ) {
290 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
291 SYSTEMTIME explTime ;
292 DateTime dateTime ;
293 FILETIME localFileTime;
295 if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotBefore ), &localFileTime))
297 if( FileTimeToSystemTime( &localFileTime, &explTime ) ) {
298 //Convert the time to readable local time
299 dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ;
300 dateTime.Seconds = explTime.wSecond ;
301 dateTime.Minutes = explTime.wMinute ;
302 dateTime.Hours = explTime.wHour ;
303 dateTime.Day = explTime.wDay ;
304 dateTime.Month = explTime.wMonth ;
305 dateTime.Year = explTime.wYear ;
309 return dateTime ;
310 } else {
311 return DateTime() ;
315 ::com::sun::star::util::DateTime SAL_CALL X509Certificate_MSCryptImpl :: getNotValidAfter() throw ( ::com::sun::star::uno::RuntimeException) {
316 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
317 SYSTEMTIME explTime ;
318 DateTime dateTime ;
319 FILETIME localFileTime;
321 if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotAfter ), &localFileTime))
323 if( FileTimeToSystemTime( &localFileTime, &explTime ) ) {
324 //Convert the time to readable local time
325 dateTime.NanoSeconds = explTime.wMilliseconds * ::tools::Time::nanoPerMilli ;
326 dateTime.Seconds = explTime.wSecond ;
327 dateTime.Minutes = explTime.wMinute ;
328 dateTime.Hours = explTime.wHour ;
329 dateTime.Day = explTime.wDay ;
330 dateTime.Month = explTime.wMonth ;
331 dateTime.Year = explTime.wYear ;
335 return dateTime ;
336 } else {
337 return DateTime() ;
341 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl :: getIssuerUniqueID() throw ( ::com::sun::star::uno::RuntimeException) {
342 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
343 Sequence< sal_Int8 > issuerUid( m_pCertContext->pCertInfo->IssuerUniqueId.cbData ) ;
344 for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->IssuerUniqueId.cbData; i ++ )
345 issuerUid[i] = *( m_pCertContext->pCertInfo->IssuerUniqueId.pbData + i ) ;
347 return issuerUid ;
348 } else {
349 return Sequence< sal_Int8 >();
353 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl :: getSubjectUniqueID() throw ( ::com::sun::star::uno::RuntimeException ) {
354 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL ) {
355 Sequence< sal_Int8 > subjectUid( m_pCertContext->pCertInfo->SubjectUniqueId.cbData ) ;
356 for( unsigned int i = 0 ; i < m_pCertContext->pCertInfo->SubjectUniqueId.cbData; i ++ )
357 subjectUid[i] = *( m_pCertContext->pCertInfo->SubjectUniqueId.pbData + i ) ;
359 return subjectUid ;
360 } else {
361 return Sequence< sal_Int8 >();
365 ::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 ) {
366 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL && m_pCertContext->pCertInfo->cExtension != 0 ) {
367 CertificateExtension_XmlSecImpl* xExtn ;
368 Sequence< Reference< XCertificateExtension > > xExtns( m_pCertContext->pCertInfo->cExtension ) ;
370 for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
371 CERT_EXTENSION* pExtn = &(m_pCertContext->pCertInfo->rgExtension[i]) ;
374 OUString objId = OUString::createFromAscii( pExtn->pszObjId );
376 if ( objId == "2.5.29.17" )
377 xExtn = (CertificateExtension_XmlSecImpl*) new SanExtensionImpl() ;
378 else
379 xExtn = new CertificateExtension_XmlSecImpl() ;
380 if( xExtn == NULL )
381 throw RuntimeException() ;
383 xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, ( unsigned char* )pExtn->pszObjId, strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
385 xExtns[i] = xExtn ;
388 return xExtns ;
389 } else {
390 return Sequence< Reference< XCertificateExtension > >();
394 ::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) {
395 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL && m_pCertContext->pCertInfo->cExtension != 0 ) {
396 CertificateExtension_XmlSecImpl* xExtn ;
397 Sequence< Reference< XCertificateExtension > > xExtns( m_pCertContext->pCertInfo->cExtension ) ;
399 xExtn = NULL ;
400 for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
401 CERT_EXTENSION* pExtn = &( m_pCertContext->pCertInfo->rgExtension[i] ) ;
403 //TODO: Compare the oid
404 if( 0 ) {
405 xExtn = new CertificateExtension_XmlSecImpl() ;
406 if( xExtn == NULL )
407 throw RuntimeException() ;
409 xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, ( unsigned char* )pExtn->pszObjId, strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
413 return xExtn ;
414 } else {
415 return NULL ;
420 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl :: getEncoded() throw ( ::com::sun::star::uno::RuntimeException) {
421 if( m_pCertContext != NULL && m_pCertContext->cbCertEncoded > 0 ) {
422 Sequence< sal_Int8 > rawCert( m_pCertContext->cbCertEncoded ) ;
424 for( unsigned int i = 0 ; i < m_pCertContext->cbCertEncoded ; i ++ )
425 rawCert[i] = *( m_pCertContext->pbCertEncoded + i ) ;
427 return rawCert ;
428 } else {
429 return Sequence< sal_Int8 >();
433 //Helper methods
434 void X509Certificate_MSCryptImpl :: setMswcryCert( const CERT_CONTEXT* cert ) {
435 if( m_pCertContext != NULL ) {
436 CertFreeCertificateContext( m_pCertContext ) ;
437 m_pCertContext = NULL ;
440 if( cert != NULL ) {
441 m_pCertContext = CertDuplicateCertificateContext( cert ) ;
445 const CERT_CONTEXT* X509Certificate_MSCryptImpl :: getMswcryCert() const {
446 if( m_pCertContext != NULL ) {
447 return m_pCertContext ;
448 } else {
449 return NULL ;
453 void X509Certificate_MSCryptImpl :: setRawCert( Sequence< sal_Int8 > rawCert ) throw ( ::com::sun::star::uno::RuntimeException) {
454 if( m_pCertContext != NULL ) {
455 CertFreeCertificateContext( m_pCertContext ) ;
456 m_pCertContext = NULL ;
459 if( rawCert.getLength() != 0 ) {
460 m_pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING, ( const sal_uInt8* )&rawCert[0], rawCert.getLength() ) ;
464 /* XUnoTunnel */
465 sal_Int64 SAL_CALL X509Certificate_MSCryptImpl :: getSomething( const Sequence< sal_Int8 >& aIdentifier ) throw( RuntimeException ) {
466 if( aIdentifier.getLength() == 16 && 0 == memcmp( getUnoTunnelId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) {
467 return ( sal_Int64 )this ;
469 return 0 ;
472 /* XUnoTunnel extension */
474 namespace
476 class theX509Certificate_MSCryptImplUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theX509Certificate_MSCryptImplUnoTunnelId > {};
479 const Sequence< sal_Int8>& X509Certificate_MSCryptImpl :: getUnoTunnelId() {
480 return theX509Certificate_MSCryptImplUnoTunnelId::get().getSeq();
483 /* XUnoTunnel extension */
484 X509Certificate_MSCryptImpl* X509Certificate_MSCryptImpl :: getImplementation( const Reference< XInterface >& rObj ) {
485 Reference< XUnoTunnel > xUT( rObj , UNO_QUERY ) ;
486 if( xUT.is() ) {
487 return ( X509Certificate_MSCryptImpl* )xUT->getSomething( getUnoTunnelId() ) ;
488 } else
489 return NULL ;
492 OUString findOIDDescription(char *oid)
494 OUString ouOID = OUString::createFromAscii( oid );
495 for (int i=0; i<nOID; i++)
497 OUString item = OUString::createFromAscii( OIDs[i].oid );
498 if (ouOID == item)
500 return OUString::createFromAscii( OIDs[i].desc );
504 return OUString() ;
507 ::com::sun::star::uno::Sequence< sal_Int8 > getThumbprint(const CERT_CONTEXT* pCertContext, DWORD dwPropId)
509 if( pCertContext != NULL )
511 DWORD cbData = 20;
512 unsigned char fingerprint[20];
513 if (CertGetCertificateContextProperty(pCertContext, dwPropId, (void*)fingerprint, &cbData))
515 Sequence< sal_Int8 > thumbprint( cbData ) ;
516 for( unsigned int i = 0 ; i < cbData ; i ++ )
518 thumbprint[i] = fingerprint[i];
521 return thumbprint;
523 else
525 DWORD e = GetLastError();
526 cbData = e;
530 return Sequence< sal_Int8 >();
533 OUString SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyAlgorithm()
534 throw ( ::com::sun::star::uno::RuntimeException)
536 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL )
538 CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm;
539 return findOIDDescription( algorithm.pszObjId ) ;
541 else
543 return OUString() ;
547 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyValue()
548 throw ( ::com::sun::star::uno::RuntimeException)
550 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL )
552 CRYPT_BIT_BLOB publicKey = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey;
554 Sequence< sal_Int8 > key( publicKey.cbData ) ;
555 for( unsigned int i = 0 ; i < publicKey.cbData ; i++ )
557 key[i] = *(publicKey.pbData + i) ;
560 return key;
562 else
564 return Sequence< sal_Int8 >();
568 OUString SAL_CALL X509Certificate_MSCryptImpl::getSignatureAlgorithm()
569 throw ( ::com::sun::star::uno::RuntimeException)
571 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL )
573 CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SignatureAlgorithm;
574 return findOIDDescription( algorithm.pszObjId ) ;
576 else
578 return OUString() ;
582 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSHA1Thumbprint()
583 throw ( ::com::sun::star::uno::RuntimeException)
585 return getThumbprint(m_pCertContext, CERT_SHA1_HASH_PROP_ID);
588 ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getMD5Thumbprint()
589 throw ( ::com::sun::star::uno::RuntimeException)
591 return getThumbprint(m_pCertContext, CERT_MD5_HASH_PROP_ID);
594 sal_Int32 SAL_CALL X509Certificate_MSCryptImpl::getCertificateUsage( )
595 throw ( ::com::sun::star::uno::RuntimeException)
597 sal_Int32 usage =
598 CERT_DATA_ENCIPHERMENT_KEY_USAGE |
599 CERT_DIGITAL_SIGNATURE_KEY_USAGE |
600 CERT_KEY_AGREEMENT_KEY_USAGE |
601 CERT_KEY_CERT_SIGN_KEY_USAGE |
602 CERT_KEY_ENCIPHERMENT_KEY_USAGE |
603 CERT_NON_REPUDIATION_KEY_USAGE |
604 CERT_OFFLINE_CRL_SIGN_KEY_USAGE;
606 if( m_pCertContext != NULL && m_pCertContext->pCertInfo != NULL && m_pCertContext->pCertInfo->cExtension != 0 )
608 CERT_EXTENSION* pExtn = CertFindExtension(
609 szOID_KEY_USAGE,
610 m_pCertContext->pCertInfo->cExtension,
611 m_pCertContext->pCertInfo->rgExtension);
613 if (pExtn != NULL)
615 CERT_KEY_USAGE_RESTRICTION_INFO keyUsage;
616 DWORD length = sizeof(CERT_KEY_USAGE_RESTRICTION_INFO);
618 bool rc = CryptDecodeObject(
619 X509_ASN_ENCODING,
620 X509_KEY_USAGE,
621 pExtn->Value.pbData,
622 pExtn->Value.cbData,
623 CRYPT_DECODE_NOCOPY_FLAG,
624 (void *)&keyUsage,
625 &length);
627 if (rc && keyUsage.RestrictedKeyUsage.cbData!=0)
629 usage = (sal_Int32)keyUsage.RestrictedKeyUsage.pbData;
634 return usage;
637 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */