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 .
22 #include <sal/config.h>
23 #include <sal/log.hxx>
24 #include <comphelper/servicehelper.hxx>
25 #include <comphelper/windowserrorstring.hxx>
26 #include <cppuhelper/supportsservice.hxx>
27 #include "x509certificate_mscryptimpl.hxx"
28 #include <certificateextension_xmlsecimpl.hxx>
29 #include <biginteger.hxx>
30 #include "sanextension_mscryptimpl.hxx"
34 #include <rtl/locale.h>
35 #include <rtl/ref.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <osl/nlsupport.h>
38 #include <osl/process.h>
39 #include <o3tl/char16_t2wchar_t.hxx>
40 #include <o3tl/string_view.hxx>
43 #include <string_view>
46 #include <tools/time.hxx>
47 #include <svl/sigstruct.hxx>
49 using namespace com::sun::star
;
50 using namespace ::com::sun::star::uno
;
51 using namespace ::com::sun::star::security
;
53 using ::com::sun::star::security::XCertificate
;
54 using ::com::sun::star::util::DateTime
;
56 /*Returns the index within 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 static std::pair
< sal_Int32
, sal_Int32
>
64 findTypeInDN(const OUString
& rRawString
, std::u16string_view 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 std::u16string_view sType
= rRawString
.subView(nTypeNameStart
, i
- nTypeNameStart
);
82 sType
= o3tl::trim(sType
);
83 if (o3tl::equalsIgnoreAsciiCase(sType
, 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 static OUString
replaceTagSWithTagST(OUString
const & oldDN
)
168 std::pair
<sal_Int32
, sal_Int32
> pairIndex
= findTypeInDN(oldDN
, u
"S");
170 if (pairIndex
.first
!= -1)
172 return OUString::Concat(oldDN
.subView(0, pairIndex
.first
))+"ST"
173 +oldDN
.subView(pairIndex
.second
);
179 X509Certificate_MSCryptImpl::X509Certificate_MSCryptImpl() :
180 m_pCertContext( nullptr )
184 X509Certificate_MSCryptImpl::~X509Certificate_MSCryptImpl() {
185 if( m_pCertContext
!= nullptr ) {
186 CertFreeCertificateContext( m_pCertContext
) ;
190 //Methods from XCertificate
191 sal_Int16 SAL_CALL
X509Certificate_MSCryptImpl::getVersion() {
192 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
193 return static_cast<char>(m_pCertContext
->pCertInfo
->dwVersion
) ;
199 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSerialNumber() {
200 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
201 Sequence
< sal_Int8
> serial( m_pCertContext
->pCertInfo
->SerialNumber
.cbData
) ;
202 auto serialRange
= asNonConstRange(serial
);
203 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->SerialNumber
.cbData
; i
++ )
204 serialRange
[i
] = *( m_pCertContext
->pCertInfo
->SerialNumber
.pbData
+ m_pCertContext
->pCertInfo
->SerialNumber
.cbData
- i
- 1 ) ;
208 return Sequence
< sal_Int8
>();
212 OUString SAL_CALL
X509Certificate_MSCryptImpl::getIssuerName() {
213 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
214 DWORD cchIssuer
= CertNameToStrW(
215 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
216 &( m_pCertContext
->pCertInfo
->Issuer
),
217 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
221 // Here the cbIssuer count the last 0x00 , take care.
222 if( cchIssuer
!= 0 ) {
223 auto issuer
= std::make_unique
<wchar_t[]>(cchIssuer
);
225 cchIssuer
= CertNameToStrW(
226 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
227 &( m_pCertContext
->pCertInfo
->Issuer
),
228 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
229 issuer
.get(), cchIssuer
232 if( cchIssuer
<= 0 ) {
233 throw RuntimeException() ;
236 if(issuer
.get()[cchIssuer
-1] == 0) cchIssuer
--; //delimit the last 0x00;
237 OUString
xIssuer(o3tl::toU(issuer
.get()), cchIssuer
) ;
239 return replaceTagSWithTagST(xIssuer
);
248 OUString SAL_CALL
X509Certificate_MSCryptImpl::getSubjectName()
250 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr )
252 DWORD cchSubject
= CertNameToStrW(
253 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
254 &( m_pCertContext
->pCertInfo
->Subject
),
255 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
259 if( cchSubject
!= 0 )
261 auto subject
= std::make_unique
<wchar_t[]>(cchSubject
);
263 cchSubject
= CertNameToStrW(
264 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
265 &( m_pCertContext
->pCertInfo
->Subject
),
266 CERT_X500_NAME_STR
| CERT_NAME_STR_REVERSE_FLAG
,
267 subject
.get(), cchSubject
270 if( cchSubject
<= 0 ) {
271 throw RuntimeException() ;
274 OUString
xSubject(o3tl::toU(subject
.get()));
276 return replaceTagSWithTagST(xSubject
);
288 css::util::DateTime SAL_CALL
X509Certificate_MSCryptImpl::getNotValidBefore() {
289 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
290 SYSTEMTIME explTime
;
292 FILETIME localFileTime
;
294 if (FileTimeToLocalFileTime(&( m_pCertContext
->pCertInfo
->NotBefore
), &localFileTime
))
296 if( FileTimeToSystemTime( &localFileTime
, &explTime
) ) {
297 //Convert the time to readable local time
298 dateTime
.NanoSeconds
= explTime
.wMilliseconds
* ::tools::Time::nanoPerMilli
;
299 dateTime
.Seconds
= explTime
.wSecond
;
300 dateTime
.Minutes
= explTime
.wMinute
;
301 dateTime
.Hours
= explTime
.wHour
;
302 dateTime
.Day
= explTime
.wDay
;
303 dateTime
.Month
= explTime
.wMonth
;
304 dateTime
.Year
= explTime
.wYear
;
314 css::util::DateTime SAL_CALL
X509Certificate_MSCryptImpl::getNotValidAfter() {
315 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
316 SYSTEMTIME explTime
;
318 FILETIME localFileTime
;
320 if (FileTimeToLocalFileTime(&( m_pCertContext
->pCertInfo
->NotAfter
), &localFileTime
))
322 if( FileTimeToSystemTime( &localFileTime
, &explTime
) ) {
323 //Convert the time to readable local time
324 dateTime
.NanoSeconds
= explTime
.wMilliseconds
* ::tools::Time::nanoPerMilli
;
325 dateTime
.Seconds
= explTime
.wSecond
;
326 dateTime
.Minutes
= explTime
.wMinute
;
327 dateTime
.Hours
= explTime
.wHour
;
328 dateTime
.Day
= explTime
.wDay
;
329 dateTime
.Month
= explTime
.wMonth
;
330 dateTime
.Year
= explTime
.wYear
;
340 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getIssuerUniqueID() {
341 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
342 Sequence
< sal_Int8
> issuerUid( m_pCertContext
->pCertInfo
->IssuerUniqueId
.cbData
) ;
343 auto issuerUidRange
= asNonConstRange(issuerUid
);
344 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->IssuerUniqueId
.cbData
; i
++ )
345 issuerUidRange
[i
] = *( m_pCertContext
->pCertInfo
->IssuerUniqueId
.pbData
+ i
) ;
349 return Sequence
< sal_Int8
>();
353 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSubjectUniqueID() {
354 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr ) {
355 Sequence
< sal_Int8
> subjectUid( m_pCertContext
->pCertInfo
->SubjectUniqueId
.cbData
) ;
356 auto subjectUidRange
= asNonConstRange(subjectUid
);
357 for( unsigned int i
= 0 ; i
< m_pCertContext
->pCertInfo
->SubjectUniqueId
.cbData
; i
++ )
358 subjectUidRange
[i
] = *( m_pCertContext
->pCertInfo
->SubjectUniqueId
.pbData
+ i
) ;
362 return Sequence
< sal_Int8
>();
366 css::uno::Sequence
< css::uno::Reference
< css::security::XCertificateExtension
> > SAL_CALL
X509Certificate_MSCryptImpl::getExtensions() {
367 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr && m_pCertContext
->pCertInfo
->cExtension
!= 0 ) {
368 rtl::Reference
<CertificateExtension_XmlSecImpl
> xExtn
;
369 Sequence
< Reference
< XCertificateExtension
> > xExtns( m_pCertContext
->pCertInfo
->cExtension
) ;
370 auto pExtns
= xExtns
.getArray();
372 for( unsigned int i
= 0; i
< m_pCertContext
->pCertInfo
->cExtension
; i
++ ) {
373 CERT_EXTENSION
* pExtn
= &(m_pCertContext
->pCertInfo
->rgExtension
[i
]) ;
376 OUString objId
= OUString::createFromAscii( pExtn
->pszObjId
);
378 if ( objId
== "2.5.29.17" )
379 xExtn
= reinterpret_cast<CertificateExtension_XmlSecImpl
*>(new SanExtensionImpl());
381 xExtn
= new CertificateExtension_XmlSecImpl
;
383 xExtn
->setCertExtn( pExtn
->Value
.pbData
, pExtn
->Value
.cbData
, reinterpret_cast<unsigned char*>(pExtn
->pszObjId
), strlen( pExtn
->pszObjId
), pExtn
->fCritical
) ;
390 return Sequence
< Reference
< XCertificateExtension
> >();
394 css::uno::Reference
< css::security::XCertificateExtension
> SAL_CALL
X509Certificate_MSCryptImpl::findCertificateExtension( const css::uno::Sequence
< sal_Int8
>& /*oid*/ ) {
395 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr && m_pCertContext
->pCertInfo
->cExtension
!= 0 ) {
396 rtl::Reference
<CertificateExtension_XmlSecImpl
> xExtn
;
398 for( unsigned int i
= 0; i
< m_pCertContext
->pCertInfo
->cExtension
; i
++ ) {
399 CERT_EXTENSION
* pExtn
= &( m_pCertContext
->pCertInfo
->rgExtension
[i
] ) ;
401 //TODO: Compare the oid
403 xExtn
= new CertificateExtension_XmlSecImpl
;
404 xExtn
->setCertExtn( pExtn
->Value
.pbData
, pExtn
->Value
.cbData
, reinterpret_cast<unsigned char*>(pExtn
->pszObjId
), strlen( pExtn
->pszObjId
), pExtn
->fCritical
) ;
415 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getEncoded() {
416 if( m_pCertContext
!= nullptr && m_pCertContext
->cbCertEncoded
> 0 ) {
417 Sequence
< sal_Int8
> rawCert( m_pCertContext
->cbCertEncoded
) ;
418 auto prawCert
= rawCert
.getArray();
420 for( unsigned int i
= 0 ; i
< m_pCertContext
->cbCertEncoded
; i
++ )
421 prawCert
[i
] = *( m_pCertContext
->pbCertEncoded
+ i
) ;
425 return Sequence
< sal_Int8
>();
430 void X509Certificate_MSCryptImpl::setMswcryCert( const CERT_CONTEXT
* cert
) {
431 if( m_pCertContext
!= nullptr ) {
432 CertFreeCertificateContext( m_pCertContext
) ;
433 m_pCertContext
= nullptr ;
436 if( cert
!= nullptr ) {
437 m_pCertContext
= CertDuplicateCertificateContext( cert
) ;
441 const CERT_CONTEXT
* X509Certificate_MSCryptImpl::getMswcryCert() const {
442 if( m_pCertContext
!= nullptr ) {
443 return m_pCertContext
;
449 void X509Certificate_MSCryptImpl::setRawCert( Sequence
< sal_Int8
> const & rawCert
) {
450 if( m_pCertContext
!= nullptr ) {
451 CertFreeCertificateContext( m_pCertContext
) ;
452 m_pCertContext
= nullptr ;
455 if( rawCert
.getLength() != 0 ) {
456 m_pCertContext
= CertCreateCertificateContext( X509_ASN_ENCODING
, reinterpret_cast<const sal_uInt8
*>(&rawCert
[0]), rawCert
.getLength() ) ;
460 static OUString
findOIDDescription(char const *oid
)
462 OUString ouOID
= OUString::createFromAscii( oid
);
463 for (int i
=0; i
<nOID
; i
++)
465 OUString item
= OUString::createFromAscii( OIDs
[i
].oid
);
468 return OUString::createFromAscii( OIDs
[i
].desc
);
475 static css::uno::Sequence
< sal_Int8
> getThumbprint(const CERT_CONTEXT
* pCertContext
, DWORD dwPropId
)
477 if( pCertContext
!= nullptr )
479 DWORD cbData
= dwPropId
== CERT_SHA256_HASH_PROP_ID
? 32 : 20;
480 unsigned char fingerprint
[32];
481 if (CertGetCertificateContextProperty(pCertContext
, dwPropId
, fingerprint
, &cbData
))
483 Sequence
< sal_Int8
> thumbprint( cbData
) ;
484 auto pthumbprint
= thumbprint
.getArray();
485 for( unsigned int i
= 0 ; i
< cbData
; i
++ )
487 pthumbprint
[i
] = fingerprint
[i
];
494 DWORD e
= GetLastError();
499 return Sequence
< sal_Int8
>();
502 OUString SAL_CALL
X509Certificate_MSCryptImpl::getSubjectPublicKeyAlgorithm()
504 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr )
506 CRYPT_ALGORITHM_IDENTIFIER algorithm
= m_pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
;
507 return findOIDDescription( algorithm
.pszObjId
) ;
515 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSubjectPublicKeyValue()
517 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr )
519 CRYPT_BIT_BLOB publicKey
= m_pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
;
521 Sequence
< sal_Int8
> key( publicKey
.cbData
) ;
522 auto keyRange
= asNonConstRange(key
);
523 for( unsigned int i
= 0 ; i
< publicKey
.cbData
; i
++ )
525 keyRange
[i
] = *(publicKey
.pbData
+ i
) ;
532 return Sequence
< sal_Int8
>();
536 OUString SAL_CALL
X509Certificate_MSCryptImpl::getSignatureAlgorithm()
538 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr )
540 CRYPT_ALGORITHM_IDENTIFIER algorithm
= m_pCertContext
->pCertInfo
->SignatureAlgorithm
;
541 return findOIDDescription( algorithm
.pszObjId
) ;
549 uno::Sequence
<sal_Int8
> X509Certificate_MSCryptImpl::getSHA256Thumbprint()
551 return getThumbprint(m_pCertContext
, CERT_SHA256_HASH_PROP_ID
);
554 svl::crypto::SignatureMethodAlgorithm
X509Certificate_MSCryptImpl::getSignatureMethodAlgorithm()
556 svl::crypto::SignatureMethodAlgorithm nRet
= svl::crypto::SignatureMethodAlgorithm::RSA
;
558 if (!m_pCertContext
|| !m_pCertContext
->pCertInfo
)
561 CRYPT_ALGORITHM_IDENTIFIER algorithm
= m_pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.Algorithm
;
562 OString
aObjId(algorithm
.pszObjId
);
563 if (aObjId
== szOID_ECC_PUBLIC_KEY
)
564 nRet
= svl::crypto::SignatureMethodAlgorithm::ECDSA
;
569 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getSHA1Thumbprint()
571 return getThumbprint(m_pCertContext
, CERT_SHA1_HASH_PROP_ID
);
574 css::uno::Sequence
< sal_Int8
> SAL_CALL
X509Certificate_MSCryptImpl::getMD5Thumbprint()
576 return getThumbprint(m_pCertContext
, CERT_MD5_HASH_PROP_ID
);
579 CertificateKind SAL_CALL
X509Certificate_MSCryptImpl::getCertificateKind()
581 return CertificateKind_X509
;
584 sal_Int32 SAL_CALL
X509Certificate_MSCryptImpl::getCertificateUsage( )
587 CERT_DATA_ENCIPHERMENT_KEY_USAGE
|
588 CERT_DIGITAL_SIGNATURE_KEY_USAGE
|
589 CERT_KEY_AGREEMENT_KEY_USAGE
|
590 CERT_KEY_CERT_SIGN_KEY_USAGE
|
591 CERT_KEY_ENCIPHERMENT_KEY_USAGE
|
592 CERT_NON_REPUDIATION_KEY_USAGE
|
593 CERT_OFFLINE_CRL_SIGN_KEY_USAGE
;
595 if( m_pCertContext
!= nullptr && m_pCertContext
->pCertInfo
!= nullptr && m_pCertContext
->pCertInfo
->cExtension
!= 0 )
597 CERT_EXTENSION
* pExtn
= CertFindExtension(
599 m_pCertContext
->pCertInfo
->cExtension
,
600 m_pCertContext
->pCertInfo
->rgExtension
);
602 if (pExtn
!= nullptr)
605 bool rc
= CryptDecodeObject(
615 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
618 std::vector
<char>buffer(length
);
620 rc
= CryptDecodeObject(
629 CRYPT_BIT_BLOB
*blob
= reinterpret_cast<CRYPT_BIT_BLOB
*>(buffer
.data());
631 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
632 else if (blob
->cbData
== 1)
633 usage
= blob
->pbData
[0];
635 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject(X509_KEY_USAGE) returned unexpected amount of data: " << blob
->cbData
);
644 OUString SAL_CALL
X509Certificate_MSCryptImpl::getImplementationName()
646 return "com.sun.star.xml.security.gpg.XCertificate_MsCryptImpl";
650 sal_Bool SAL_CALL
X509Certificate_MSCryptImpl::supportsService(const OUString
& serviceName
)
652 return cppu::supportsService(this, serviceName
);
656 Sequence
<OUString
> SAL_CALL
X509Certificate_MSCryptImpl::getSupportedServiceNames()
658 return { OUString() };
661 namespace xmlsecurity
{
663 // based on some guesswork and:
664 // https://datatracker.ietf.org/doc/html/rfc1485
665 // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certnametostra#CERT_X500_NAME_STR
666 // the main problem appears to be that in values NSS uses \ escapes but CryptoAPI requires " quotes around value
667 static OUString
CompatDNNSS(OUString
const& rDN
)
669 OUStringBuffer
buf(rDN
.getLength());
670 enum { DEFAULT
, INVALUE
, INQUOTE
} state(DEFAULT
);
671 for (sal_Int32 i
= 0; i
< rDN
.getLength(); ++i
)
673 if (state
== DEFAULT
)
678 if (rDN
.getLength() == i
+1)
689 else if (state
== INVALUE
)
691 if (rDN
[i
] == '+' || rDN
[i
] == ',' || rDN
[i
] == ';')
693 buf
.append("\"" + OUStringChar(rDN
[i
]));
696 else if (rDN
[i
] == '\\')
698 if (rDN
.getLength() == i
+1)
706 buf
.append(rDN
[i
+1]);
713 if (i
+1 == rDN
.getLength())
720 return buf
.makeStringAndClear();
723 static bool EncodeDistinguishedName(std::u16string_view
const rName
, CERT_NAME_BLOB
& rBlob
)
726 if (!CertStrToNameW(X509_ASN_ENCODING
,
727 reinterpret_cast<LPCWSTR
>(rName
.data()), CERT_X500_NAME_STR
,
728 nullptr, nullptr, &rBlob
.cbData
, &pszError
))
730 SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError
)));
733 rBlob
.pbData
= new BYTE
[rBlob
.cbData
];
734 if (!CertStrToNameW(X509_ASN_ENCODING
,
735 reinterpret_cast<LPCWSTR
>(rName
.data()), CERT_X500_NAME_STR
,
736 nullptr, rBlob
.pbData
, &rBlob
.cbData
, &pszError
))
738 SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError
)));
744 bool EqualDistinguishedNames(
745 std::u16string_view
const rName1
, std::u16string_view
const rName2
,
746 EqualMode
const eMode
)
748 if (eMode
== COMPAT_BOTH
&& !rName1
.empty() && rName1
== rName2
)
749 { // handle case where both need to be converted
752 CERT_NAME_BLOB blob1
;
753 if (!EncodeDistinguishedName(rName1
, blob1
))
757 CERT_NAME_BLOB blob2
;
759 if (EncodeDistinguishedName(rName2
, blob2
))
761 ret
= CertCompareCertificateName(X509_ASN_ENCODING
,
762 &blob1
, &blob2
) == TRUE
;
763 delete[] blob2
.pbData
;
765 if (!ret
&& eMode
== COMPAT_2ND
)
767 CERT_NAME_BLOB blob2compat
;
768 if (!EncodeDistinguishedName(CompatDNNSS(OUString(rName2
)), blob2compat
))
770 delete[] blob1
.pbData
;
773 ret
= CertCompareCertificateName(X509_ASN_ENCODING
,
774 &blob1
, &blob2compat
) == TRUE
;
775 delete[] blob2compat
.pbData
;
777 delete[] blob1
.pbData
;
781 } // namespace xmlsecurity
783 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */