LibreOffice Module xmlsecurity (master) 1
x509certificate_mscryptimpl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <string.h>
21
22#include <sal/config.h>
23#include <sal/log.hxx>
29#include <biginteger.hxx>
31
32#include "oid.hxx"
33
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>
40#include <o3tl/string_view.hxx>
41
42#include <memory>
43#include <string_view>
44#include <utility>
45#include <vector>
46#include <tools/time.hxx>
47#include <svl/sigstruct.hxx>
48
49using namespace com::sun::star;
50using namespace ::com::sun::star::uno ;
51using namespace ::com::sun::star::security ;
52
53using ::com::sun::star::security::XCertificate ;
54using ::com::sun::star::util::DateTime ;
55
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.
59 sTypeName can be
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.
62*/
63static std::pair< sal_Int32, sal_Int32 >
64findTypeInDN(const OUString& rRawString, std::u16string_view sTypeName)
65{
66 std::pair< sal_Int32, sal_Int32 > retVal;
67 bool bInEscape = false;
68 bool bInValue = false;
69 bool bFound = false;
70 sal_Int32 nTypeNameStart = 0;
71 sal_Int32 length = rRawString.getLength();
72
73 for (sal_Int32 i = 0; i < length; i++)
74 {
75 sal_Unicode c = rRawString[i];
76
77 if (c == '=')
78 {
79 if (! bInValue)
80 {
81 std::u16string_view sType = rRawString.subView(nTypeNameStart, i - nTypeNameStart);
83 if (o3tl::equalsIgnoreAsciiCase(sType, sTypeName))
84 {
85 bFound = true;
86 break;
87 }
88 }
89 }
90 else if (c == '"')
91 {
92 if (!bInEscape)
93 {
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] == '"')
99 bInEscape = true;
100 else
101 bInValue = !bInValue; //value is enclosed in " "
102 }
103 else
104 {
105 //This quote is escaped by a preceding quote and therefore is
106 //part of the value
107 bInEscape = false;
108 }
109 }
110 else if (c == ',' || c == '+')
111 {
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
115 if (!bInValue)
116 {
117 //The next char is the start of the new type
118 nTypeNameStart = i + 1;
119 }
120 }
121 }
122
123 //Found the Type Name, but there can still be spaces after the last comma
124 //and the beginning of the type.
125 if (bFound)
126 {
127 while (true)
128 {
129 sal_Unicode c = rRawString[nTypeNameStart];
130 if (c != ' ' && c != '\t')
131 //found
132 break;
133 nTypeNameStart ++;
134 }
135 // search end (one after last letter)
136 sal_Int32 nTypeNameEnd = nTypeNameStart;
137 nTypeNameEnd++;
138 while (true)
139 {
140 sal_Unicode c = rRawString[nTypeNameEnd];
141 if (c == ' ' || c == '\t' || c == '=')
142 break;
143 nTypeNameEnd++;
144 }
145 retVal = std::make_pair(nTypeNameStart, nTypeNameEnd);
146 }
147 else
148 {
149 retVal = std::make_pair(-1, -1);
150 }
151 return retVal;
152}
153
154
155/*
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.
164 */
165
166static OUString replaceTagSWithTagST(OUString const & oldDN)
167{
168 std::pair<sal_Int32, sal_Int32 > pairIndex = findTypeInDN(oldDN, u"S");
169
170 if (pairIndex.first != -1)
171 {
172 return OUString::Concat(oldDN.subView(0, pairIndex.first))+"ST"
173 +oldDN.subView(pairIndex.second);
174 }
175 return oldDN;
176}
177/* end */
178
180 m_pCertContext( nullptr )
181{
182}
183
185 if( m_pCertContext != nullptr ) {
186 CertFreeCertificateContext( m_pCertContext ) ;
187 }
188}
189
190//Methods from XCertificate
192 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
193 return static_cast<char>(m_pCertContext->pCertInfo->dwVersion) ;
194 } else {
195 return -1 ;
196 }
197}
198
199css::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 ) ;
205
206 return serial ;
207 } else {
208 return Sequence< sal_Int8 >();
209 }
210}
211
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 ,
218 nullptr, 0
219 ) ;
220
221 // Here the cbIssuer count the last 0x00 , take care.
222 if( cchIssuer != 0 ) {
223 auto issuer = std::make_unique<wchar_t[]>(cchIssuer);
224
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
230 ) ;
231
232 if( cchIssuer <= 0 ) {
233 throw RuntimeException() ;
234 }
235
236 if(issuer.get()[cchIssuer -1] == 0) cchIssuer--; //delimit the last 0x00;
237 OUString xIssuer(o3tl::toU(issuer.get()), cchIssuer) ;
238
239 return replaceTagSWithTagST(xIssuer);
240 } else {
241 return OUString() ;
242 }
243 } else {
244 return OUString() ;
245 }
246}
247
249{
250 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
251 {
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 ,
256 nullptr, 0
257 ) ;
258
259 if( cchSubject != 0 )
260 {
261 auto subject = std::make_unique<wchar_t[]>(cchSubject);
262
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
268 ) ;
269
270 if( cchSubject <= 0 ) {
271 throw RuntimeException() ;
272 }
273
274 OUString xSubject(o3tl::toU(subject.get()));
275
276 return replaceTagSWithTagST(xSubject);
277 } else
278 {
279 return OUString() ;
280 }
281 }
282 else
283 {
284 return OUString() ;
285 }
286}
287
289 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
290 SYSTEMTIME explTime ;
291 DateTime dateTime ;
292 FILETIME localFileTime;
293
294 if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotBefore ), &localFileTime))
295 {
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 ;
305 }
306 }
307
308 return dateTime ;
309 } else {
310 return DateTime() ;
311 }
312}
313
314css::util::DateTime SAL_CALL X509Certificate_MSCryptImpl::getNotValidAfter() {
315 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr ) {
316 SYSTEMTIME explTime ;
317 DateTime dateTime ;
318 FILETIME localFileTime;
319
320 if (FileTimeToLocalFileTime(&( m_pCertContext->pCertInfo->NotAfter ), &localFileTime))
321 {
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 ;
331 }
332 }
333
334 return dateTime ;
335 } else {
336 return DateTime() ;
337 }
338}
339
340css::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 ) ;
346
347 return issuerUid ;
348 } else {
349 return Sequence< sal_Int8 >();
350 }
351}
352
353css::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 ) ;
359
360 return subjectUid ;
361 } else {
362 return Sequence< sal_Int8 >();
363 }
364}
365
366css::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 ) {
369 Sequence< Reference< XCertificateExtension > > xExtns( m_pCertContext->pCertInfo->cExtension ) ;
370 auto pExtns = xExtns.getArray();
371
372 for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
373 CERT_EXTENSION* pExtn = &(m_pCertContext->pCertInfo->rgExtension[i]) ;
374
375
376 OUString objId = OUString::createFromAscii( pExtn->pszObjId );
377
378 if ( objId == "2.5.29.17" )
379 xExtn = reinterpret_cast<CertificateExtension_XmlSecImpl*>(new SanExtensionImpl());
380 else
382
383 xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
384
385 pExtns[i] = xExtn ;
386 }
387
388 return xExtns ;
389 } else {
390 return Sequence< Reference< XCertificateExtension > >();
391 }
392}
393
394css::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 ) {
397
398 for( unsigned int i = 0; i < m_pCertContext->pCertInfo->cExtension; i++ ) {
399 CERT_EXTENSION* pExtn = &( m_pCertContext->pCertInfo->rgExtension[i] ) ;
400
401 //TODO: Compare the oid
402 if( false ) {
404 xExtn->setCertExtn( pExtn->Value.pbData, pExtn->Value.cbData, reinterpret_cast<unsigned char*>(pExtn->pszObjId), strlen( pExtn->pszObjId ), pExtn->fCritical ) ;
405 }
406 }
407
408 return xExtn ;
409 } else {
410 return nullptr ;
411 }
412}
413
414
415css::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();
419
420 for( unsigned int i = 0 ; i < m_pCertContext->cbCertEncoded ; i ++ )
421 prawCert[i] = *( m_pCertContext->pbCertEncoded + i ) ;
422
423 return rawCert ;
424 } else {
425 return Sequence< sal_Int8 >();
426 }
427}
428
429//Helper methods
430void X509Certificate_MSCryptImpl::setMswcryCert( const CERT_CONTEXT* cert ) {
431 if( m_pCertContext != nullptr ) {
432 CertFreeCertificateContext( m_pCertContext ) ;
433 m_pCertContext = nullptr ;
434 }
435
436 if( cert != nullptr ) {
437 m_pCertContext = CertDuplicateCertificateContext( cert ) ;
438 }
439}
440
442 if( m_pCertContext != nullptr ) {
443 return m_pCertContext ;
444 } else {
445 return nullptr ;
446 }
447}
448
450 if( m_pCertContext != nullptr ) {
451 CertFreeCertificateContext( m_pCertContext ) ;
452 m_pCertContext = nullptr ;
453 }
454
455 if( rawCert.getLength() != 0 ) {
456 m_pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING, reinterpret_cast<const sal_uInt8*>(&rawCert[0]), rawCert.getLength() ) ;
457 }
458}
459
460static OUString findOIDDescription(char const *oid)
461{
462 OUString ouOID = OUString::createFromAscii( oid );
463 for (int i=0; i<nOID; i++)
464 {
465 OUString item = OUString::createFromAscii( OIDs[i].oid );
466 if (ouOID == item)
467 {
468 return OUString::createFromAscii( OIDs[i].desc );
469 }
470 }
471
472 return OUString() ;
473}
474
475static css::uno::Sequence< sal_Int8 > getThumbprint(const CERT_CONTEXT* pCertContext, DWORD dwPropId)
476{
477 if( pCertContext != nullptr )
478 {
479 DWORD cbData = dwPropId == CERT_SHA256_HASH_PROP_ID ? 32 : 20;
480 unsigned char fingerprint[32];
481 if (CertGetCertificateContextProperty(pCertContext, dwPropId, fingerprint, &cbData))
482 {
483 Sequence< sal_Int8 > thumbprint( cbData ) ;
484 auto pthumbprint = thumbprint.getArray();
485 for( unsigned int i = 0 ; i < cbData ; i ++ )
486 {
487 pthumbprint[i] = fingerprint[i];
488 }
489
490 return thumbprint;
491 }
492 else
493 {
494 DWORD e = GetLastError();
495 cbData = e;
496 }
497 }
498
499 return Sequence< sal_Int8 >();
500}
501
503{
504 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
505 {
506 CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm;
507 return findOIDDescription( algorithm.pszObjId ) ;
508 }
509 else
510 {
511 return OUString() ;
512 }
513}
514
515css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSubjectPublicKeyValue()
516{
517 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
518 {
519 CRYPT_BIT_BLOB publicKey = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey;
520
521 Sequence< sal_Int8 > key( publicKey.cbData ) ;
522 auto keyRange = asNonConstRange(key);
523 for( unsigned int i = 0 ; i < publicKey.cbData ; i++ )
524 {
525 keyRange[i] = *(publicKey.pbData + i) ;
526 }
527
528 return key;
529 }
530 else
531 {
532 return Sequence< sal_Int8 >();
533 }
534}
535
537{
538 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr )
539 {
540 CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SignatureAlgorithm;
541 return findOIDDescription( algorithm.pszObjId ) ;
542 }
543 else
544 {
545 return OUString() ;
546 }
547}
548
550{
551 return getThumbprint(m_pCertContext, CERT_SHA256_HASH_PROP_ID);
552}
553
555{
557
558 if (!m_pCertContext || !m_pCertContext->pCertInfo)
559 return nRet;
560
561 CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm;
562 OString aObjId(algorithm.pszObjId);
563 if (aObjId == szOID_ECC_PUBLIC_KEY)
565
566 return nRet;
567}
568
569css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSHA1Thumbprint()
570{
571 return getThumbprint(m_pCertContext, CERT_SHA1_HASH_PROP_ID);
572}
573
574css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getMD5Thumbprint()
575{
576 return getThumbprint(m_pCertContext, CERT_MD5_HASH_PROP_ID);
577}
578
580{
581 return CertificateKind_X509;
582}
583
585{
586 sal_Int32 usage =
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;
594
595 if( m_pCertContext != nullptr && m_pCertContext->pCertInfo != nullptr && m_pCertContext->pCertInfo->cExtension != 0 )
596 {
597 CERT_EXTENSION* pExtn = CertFindExtension(
598 szOID_KEY_USAGE,
599 m_pCertContext->pCertInfo->cExtension,
600 m_pCertContext->pCertInfo->rgExtension);
601
602 if (pExtn != nullptr)
603 {
604 DWORD length = 0;
605 bool rc = CryptDecodeObject(
606 X509_ASN_ENCODING,
607 X509_KEY_USAGE,
608 pExtn->Value.pbData,
609 pExtn->Value.cbData,
610 0,
611 nullptr,
612 &length);
613
614 if (!rc)
615 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
616 else
617 {
618 std::vector<char>buffer(length);
619
620 rc = CryptDecodeObject(
621 X509_ASN_ENCODING,
622 X509_KEY_USAGE,
623 pExtn->Value.pbData,
624 pExtn->Value.cbData,
625 0,
626 buffer.data(),
627 &length);
628
629 CRYPT_BIT_BLOB *blob = reinterpret_cast<CRYPT_BIT_BLOB*>(buffer.data());
630 if (!rc)
631 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject failed: " << WindowsErrorString(GetLastError()));
632 else if (blob->cbData == 1)
633 usage = blob->pbData[0];
634 else
635 SAL_WARN("xmlsecurity.xmlsec", "CryptDecodeObject(X509_KEY_USAGE) returned unexpected amount of data: " << blob->cbData);
636 }
637 }
638 }
639
640 return usage;
641}
642
643/* XServiceInfo */
645{
646 return "com.sun.star.xml.security.gpg.XCertificate_MsCryptImpl";
647}
648
649/* XServiceInfo */
650sal_Bool SAL_CALL X509Certificate_MSCryptImpl::supportsService(const OUString& serviceName)
651{
652 return cppu::supportsService(this, serviceName);
653}
654
655/* XServiceInfo */
657{
658 return { OUString() };
659}
660
661namespace xmlsecurity {
662
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
667static OUString CompatDNNSS(OUString const& rDN)
668{
669 OUStringBuffer buf(rDN.getLength());
670 enum { DEFAULT, INVALUE, INQUOTE } state(DEFAULT);
671 for (sal_Int32 i = 0; i < rDN.getLength(); ++i)
672 {
673 if (state == DEFAULT)
674 {
675 buf.append(rDN[i]);
676 if (rDN[i] == '=')
677 {
678 if (rDN.getLength() == i+1)
679 {
680 break; // invalid?
681 }
682 else
683 {
684 buf.append('"');
685 state = INVALUE;
686 }
687 }
688 }
689 else if (state == INVALUE)
690 {
691 if (rDN[i] == '+' || rDN[i] == ',' || rDN[i] == ';')
692 {
693 buf.append("\"" + OUStringChar(rDN[i]));
694 state = DEFAULT;
695 }
696 else if (rDN[i] == '\\')
697 {
698 if (rDN.getLength() == i+1)
699 {
700 break; // invalid?
701 }
702 if (rDN[i+1] == '"')
703 {
704 buf.append('"');
705 }
706 buf.append(rDN[i+1]);
707 ++i;
708 }
709 else
710 {
711 buf.append(rDN[i]);
712 }
713 if (i+1 == rDN.getLength())
714 {
715 buf.append('"');
716 state = DEFAULT;
717 }
718 }
719 }
720 return buf.makeStringAndClear();
721}
722
723static bool EncodeDistinguishedName(std::u16string_view const rName, CERT_NAME_BLOB & rBlob)
724{
725 LPCWSTR pszError;
726 if (!CertStrToNameW(X509_ASN_ENCODING,
727 reinterpret_cast<LPCWSTR>(rName.data()), CERT_X500_NAME_STR,
728 nullptr, nullptr, &rBlob.cbData, &pszError))
729 {
730 SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError)));
731 return false;
732 }
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))
737 {
738 SAL_INFO("xmlsecurity.xmlsec", "CertStrToNameW failed: " << WindowsErrorString(GetLastError()) << "; " << OUString(o3tl::toU(pszError)));
739 return false;
740 }
741 return true;
742}
743
745 std::u16string_view const rName1, std::u16string_view const rName2,
746 EqualMode const eMode)
747{
748 if (eMode == COMPAT_BOTH && !rName1.empty() && rName1 == rName2)
749 { // handle case where both need to be converted
750 return true;
751 }
752 CERT_NAME_BLOB blob1;
753 if (!EncodeDistinguishedName(rName1, blob1))
754 {
755 return false;
756 }
757 CERT_NAME_BLOB blob2;
758 bool ret(false);
759 if (EncodeDistinguishedName(rName2, blob2))
760 {
761 ret = CertCompareCertificateName(X509_ASN_ENCODING,
762 &blob1, &blob2) == TRUE;
763 delete[] blob2.pbData;
764 }
765 if (!ret && eMode == COMPAT_2ND)
766 {
767 CERT_NAME_BLOB blob2compat;
768 if (!EncodeDistinguishedName(CompatDNNSS(OUString(rName2)), blob2compat))
769 {
770 delete[] blob1.pbData;
771 return false;
772 }
773 ret = CertCompareCertificateName(X509_ASN_ENCODING,
774 &blob1, &blob2compat) == TRUE;
775 delete[] blob2compat.pbData;
776 }
777 delete[] blob1.pbData;
778 return ret;
779}
780
781} // namespace xmlsecurity
782
783/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getMD5Thumbprint() override
virtual OUString SAL_CALL getSubjectName() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectUniqueID() override
void setMswcryCert(const CERT_CONTEXT *cert)
void setRawCert(css::uno::Sequence< sal_Int8 > const &rawCert)
virtual OUString SAL_CALL getSubjectPublicKeyAlgorithm() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSubjectPublicKeyValue() override
virtual sal_Int32 SAL_CALL getCertificateUsage() override
virtual css::uno::Sequence< sal_Int8 > getSHA256Thumbprint() override
virtual css::security::CertificateKind SAL_CALL getCertificateKind() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSHA1Thumbprint() override
virtual svl::crypto::SignatureMethodAlgorithm getSignatureMethodAlgorithm() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual css::util::DateTime SAL_CALL getNotValidBefore() override
virtual OUString SAL_CALL getIssuerName() override
virtual css::uno::Sequence< css::uno::Reference< css::security::XCertificateExtension > > SAL_CALL getExtensions() override
virtual OUString SAL_CALL getSignatureAlgorithm() override
virtual sal_Int16 SAL_CALL getVersion() override
virtual css::util::DateTime SAL_CALL getNotValidAfter() override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
const CERT_CONTEXT * getMswcryCert() const
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getEncoded() override
virtual css::uno::Reference< css::security::XCertificateExtension > SAL_CALL findCertificateExtension(const css::uno::Sequence< sal_Int8 > &oid) override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getSerialNumber() override
virtual OUString SAL_CALL getImplementationName() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getIssuerUniqueID() override
static const sal_Int64 nanoPerMilli
float u
#define TRUE
Mode eMode
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
static bool EncodeDistinguishedName(std::u16string_view const rName, CERT_NAME_BLOB &rBlob)
static OUString CompatDNNSS(OUString const &rDN)
bool EqualDistinguishedNames(std::u16string_view const rName1, std::u16string_view const rName2, EqualMode const eMode)
OIDItem OIDs[]
Definition: oid.hxx:29
const int nOID
Definition: oid.hxx:151
unsigned char sal_uInt8
unsigned char sal_Bool
sal_uInt16 sal_Unicode
unsigned char BYTE
static OUString replaceTagSWithTagST(OUString const &oldDN)
static OUString findOIDDescription(char const *oid)
static std::pair< sal_Int32, sal_Int32 > findTypeInDN(const OUString &rRawString, std::u16string_view sTypeName)
static css::uno::Sequence< sal_Int8 > getThumbprint(const CERT_CONTEXT *pCertContext, DWORD dwPropId)