1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40
41/*!
42 \class QSslCertificate
43 \brief The QSslCertificate class provides a convenient API for an X509 certificate.
44 \since 4.3
45
46 \reentrant
47 \ingroup network
48 \ingroup ssl
49 \ingroup shared
50 \inmodule QtNetwork
51
52 QSslCertificate stores an X509 certificate, and is commonly used
53 to verify the identity and store information about the local host,
54 a remotely connected peer, or a trusted third party Certificate
55 Authority.
56
57 There are many ways to construct a QSslCertificate. The most
58 common way is to call QSslSocket::peerCertificate(), which returns
59 a QSslCertificate object, or QSslSocket::peerCertificateChain(),
60 which returns a list of them. You can also load certificates from
61 a DER (binary) or PEM (Base64) encoded bundle, typically stored as
62 one or more local files, or in a Qt Resource.
63
64 You can call isNull() to check if your certificate is null. By default,
65 QSslCertificate constructs a null certificate. A null certificate is
66 invalid, but an invalid certificate is not necessarily null. If you want
67 to reset all contents in a certificate, call clear().
68
69 After loading a certificate, you can find information about the
70 certificate, its subject, and its issuer, by calling one of the
71 many accessor functions, including version(), serialNumber(),
72 issuerInfo() and subjectInfo(). You can call effectiveDate() and
73 expiryDate() to check when the certificate starts being
74 effective and when it expires.
75 The publicKey() function returns the certificate
76 subject's public key as a QSslKey. You can call issuerInfo() or
77 subjectInfo() to get detailed information about the certificate
78 issuer and its subject.
79
80 Internally, QSslCertificate is stored as an X509 structure. You
81 can access this handle by calling handle(), but the results are
82 likely to not be portable.
83
84 \sa QSslSocket, QSslKey, QSslCipher, QSslError
85*/
86
87/*!
88 \enum QSslCertificate::SubjectInfo
89
90 Describes keys that you can pass to QSslCertificate::issuerInfo() or
91 QSslCertificate::subjectInfo() to get information about the certificate
92 issuer or subject.
93
94 \value Organization "O" The name of the organization.
95
96 \value CommonName "CN" The common name; most often this is used to store
97 the host name.
98
99 \value LocalityName "L" The locality.
100
101 \value OrganizationalUnitName "OU" The organizational unit name.
102
103 \value CountryName "C" The country.
104
105 \value StateOrProvinceName "ST" The state or province.
106
107 \value DistinguishedNameQualifier The distinguished name qualifier
108
109 \value SerialNumber The certificate's serial number
110
111 \value EmailAddress The email address associated with the certificate
112*/
113
114/*!
115 \enum QSslCertificate::PatternSyntax
116 \since 5.15
117
118 The syntax used to interpret the meaning of the pattern.
119
120 \value RegularExpression A rich Perl-like pattern matching syntax.
121
122 \value Wildcard This provides a simple pattern matching syntax
123 similar to that used by shells (command interpreters) for "file
124 globbing". See \l {QRegularExpression#Wildcard matching}
125 {QRegularExpression Wildcard Matching}.
126
127 \value FixedString The pattern is a fixed string. This is
128 equivalent to using the RegularExpression pattern on a string in
129 which all metacharacters are escaped using escape(). This is the
130 default.
131*/
132
133#include <QtNetwork/qtnetworkglobal.h>
134#ifndef QT_NO_OPENSSL
135#include "qsslsocket_openssl_symbols_p.h"
136#endif
137#if defined(Q_OS_WINRT) && QT_CONFIG(ssl)
138#include "qsslsocket_winrt_p.h"
139#endif
140#ifdef QT_SECURETRANSPORT
141#include "qsslsocket_mac_p.h"
142#endif
143#if QT_CONFIG(schannel)
144#include "qsslsocket_schannel_p.h"
145#endif
146#if QT_CONFIG(regularexpression)
147#include "qregularexpression.h"
148#endif
149#include "qssl_p.h"
150#include "qsslcertificate.h"
151#include "qsslcertificate_p.h"
152#ifndef QT_NO_SSL
153#include "qsslkey_p.h"
154#endif
155
156#include <QtCore/qdir.h>
157#include <QtCore/qdiriterator.h>
158#include <QtCore/qfile.h>
159
160QT_BEGIN_NAMESPACE
161
162/*!
163 Constructs a QSslCertificate by reading \a format encoded data
164 from \a device and using the first certificate found. You can
165 later call isNull() to see if \a device contained a certificate,
166 and if this certificate was loaded successfully.
167*/
168QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
169 : d(new QSslCertificatePrivate)
170{
171#ifndef QT_NO_OPENSSL
172 QSslSocketPrivate::ensureInitialized();
173 if (device && QSslSocket::supportsSsl())
174#else
175 if (device)
176#endif
177 d->init(data: device->readAll(), format);
178}
179
180/*!
181 Constructs a QSslCertificate by parsing the \a format encoded
182 \a data and using the first available certificate found. You can
183 later call isNull() to see if \a data contained a certificate,
184 and if this certificate was loaded successfully.
185*/
186QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
187 : d(new QSslCertificatePrivate)
188{
189#ifndef QT_NO_OPENSSL
190 QSslSocketPrivate::ensureInitialized();
191 if (QSslSocket::supportsSsl())
192#endif
193 d->init(data, format);
194}
195
196/*!
197 Constructs an identical copy of \a other.
198*/
199QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
200{
201}
202
203/*!
204 Destroys the QSslCertificate.
205*/
206QSslCertificate::~QSslCertificate()
207{
208}
209
210/*!
211 Copies the contents of \a other into this certificate, making the two
212 certificates identical.
213*/
214QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
215{
216 d = other.d;
217 return *this;
218}
219
220/*!
221 \fn void QSslCertificate::swap(QSslCertificate &other)
222 \since 5.0
223
224 Swaps this certificate instance with \a other. This function is
225 very fast and never fails.
226*/
227
228/*!
229 \fn bool QSslCertificate::operator==(const QSslCertificate &other) const
230
231 Returns \c true if this certificate is the same as \a other; otherwise
232 returns \c false.
233*/
234
235/*!
236 \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
237
238 Returns \c true if this certificate is not the same as \a other; otherwise
239 returns \c false.
240*/
241
242/*!
243 \fn bool QSslCertificate::isNull() const
244
245 Returns \c true if this is a null certificate (i.e., a certificate
246 with no contents); otherwise returns \c false.
247
248 By default, QSslCertificate constructs a null certificate.
249
250 \sa clear()
251*/
252
253#if QT_DEPRECATED_SINCE(5,0)
254/*!
255 \fn bool QSslCertificate::isValid() const
256 \obsolete
257
258 To verify a certificate, use verify().
259 To check if a certificate is blacklisted, use isBlacklisted().
260 To check if a certificate has expired or is not yet valid, compare
261 expiryDate() and effectiveDate() with QDateTime::currentDateTime()
262
263 This function checks that the current
264 date-time is within the date-time range during which the
265 certificate is considered valid, and checks that the
266 certificate is not in a blacklist of fraudulent certificates.
267
268 \sa isNull(), verify(), isBlacklisted(), expiryDate(), effectiveDate()
269*/
270#endif
271
272/*!
273 Returns \c true if this certificate is blacklisted; otherwise
274 returns \c false.
275
276 \sa isNull()
277*/
278bool QSslCertificate::isBlacklisted() const
279{
280 return QSslCertificatePrivate::isBlacklisted(certificate: *this);
281}
282
283/*!
284 \fn bool QSslCertificate::isSelfSigned() const
285 \since 5.4
286
287 Returns \c true if this certificate is self signed; otherwise
288 returns \c false.
289
290 A certificate is considered self-signed its issuer and subject
291 are identical.
292*/
293
294/*!
295 Clears the contents of this certificate, making it a null
296 certificate.
297
298 \sa isNull()
299*/
300void QSslCertificate::clear()
301{
302 if (isNull())
303 return;
304 d = new QSslCertificatePrivate;
305}
306
307/*!
308 \fn QByteArray QSslCertificate::version() const
309 Returns the certificate's version string.
310*/
311
312/*!
313 \fn QByteArray QSslCertificate::serialNumber() const
314
315 Returns the certificate's serial number string in hexadecimal format.
316*/
317
318/*!
319 Returns a cryptographic digest of this certificate. By default,
320 an MD5 digest will be generated, but you can also specify a
321 custom \a algorithm.
322*/
323QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
324{
325 return QCryptographicHash::hash(data: toDer(), method: algorithm);
326}
327
328/*!
329 \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
330
331 Returns the issuer information for the \a subject from the
332 certificate, or an empty list if there is no information for
333 \a subject in the certificate. There can be more than one entry
334 of each type.
335
336 \sa subjectInfo()
337*/
338
339/*!
340 \fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
341
342 Returns the issuer information for \a attribute from the certificate,
343 or an empty list if there is no information for \a attribute in the
344 certificate. There can be more than one entry for an attribute.
345
346 \sa subjectInfo()
347*/
348
349/*!
350 \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
351
352 Returns the information for the \a subject, or an empty list if
353 there is no information for \a subject in the certificate. There
354 can be more than one entry of each type.
355
356 \sa issuerInfo()
357*/
358
359/*!
360 \fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
361
362 Returns the subject information for \a attribute, or an empty list if
363 there is no information for \a attribute in the certificate. There
364 can be more than one entry for an attribute.
365
366 \sa issuerInfo()
367*/
368
369/*!
370 \fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
371
372 \since 5.0
373 Returns a list of the attributes that have values in the subject
374 information of this certificate. The information associated
375 with a given attribute can be accessed using the subjectInfo()
376 method. Note that this list may include the OIDs for any
377 elements that are not known by the SSL backend.
378
379 \sa subjectInfo()
380*/
381
382/*!
383 \fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
384
385 \since 5.0
386 Returns a list of the attributes that have values in the issuer
387 information of this certificate. The information associated
388 with a given attribute can be accessed using the issuerInfo()
389 method. Note that this list may include the OIDs for any
390 elements that are not known by the SSL backend.
391
392 \sa subjectInfo()
393*/
394
395#if QT_DEPRECATED_SINCE(5,0)
396/*!
397 \fn QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
398 \obsolete
399
400 Use QSslCertificate::subjectAlternativeNames();
401*/
402#endif
403
404/*!
405 \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
406
407 Returns the list of alternative subject names for this
408 certificate. The alternative names typically contain host
409 names, optionally with wildcards, that are valid for this
410 certificate.
411
412 These names are tested against the connected peer's host name, if
413 either the subject information for \l CommonName doesn't define a
414 valid host name, or the subject info name doesn't match the peer's
415 host name.
416
417 \sa subjectInfo()
418*/
419
420/*!
421 \fn QDateTime QSslCertificate::effectiveDate() const
422
423 Returns the date-time that the certificate becomes valid, or an
424 empty QDateTime if this is a null certificate.
425
426 \sa expiryDate()
427*/
428
429/*!
430 \fn QDateTime QSslCertificate::expiryDate() const
431
432 Returns the date-time that the certificate expires, or an empty
433 QDateTime if this is a null certificate.
434
435 \sa effectiveDate()
436*/
437
438/*!
439 \fn Qt::HANDLE QSslCertificate::handle() const
440 Returns a pointer to the native certificate handle, if there is
441 one, else \nullptr.
442
443 You can use this handle, together with the native API, to access
444 extended information about the certificate.
445
446 \warning Use of this function has a high probability of being
447 non-portable, and its return value may vary from platform to
448 platform or change from minor release to minor release.
449*/
450
451/*!
452 \fn QSslKey QSslCertificate::publicKey() const
453 Returns the certificate subject's public key.
454*/
455
456/*!
457 \fn QList<QSslCertificateExtension> QSslCertificate::extensions() const
458
459 Returns a list containing the X509 extensions of this certificate.
460 \since 5.0
461 */
462
463/*!
464 \fn QByteArray QSslCertificate::toPem() const
465
466 Returns this certificate converted to a PEM (Base64) encoded
467 representation.
468*/
469
470/*!
471 \fn QByteArray QSslCertificate::toDer() const
472
473 Returns this certificate converted to a DER (binary) encoded
474 representation.
475*/
476
477/*!
478 \fn QString QSslCertificate::toText() const
479
480 Returns this certificate converted to a human-readable text
481 representation.
482
483 \since 5.0
484*/
485
486#if QT_DEPRECATED_SINCE(5,15)
487/*!
488 \obsolete
489
490 Searches all files in the \a path for certificates encoded in the
491 specified \a format and returns them in a list. \a path must be a file
492 or a pattern matching one or more files, as specified by \a syntax.
493
494 Example:
495
496 \snippet code/src_network_ssl_qsslcertificate.cpp 0
497
498 \sa fromData()
499*/
500QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
501 QSsl::EncodingFormat format,
502 QRegExp::PatternSyntax syntax)
503{
504 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
505
506 // make sure to use the same path separators on Windows and Unix like systems.
507 QString sourcePath = QDir::fromNativeSeparators(pathName: path);
508
509 // Find the path without the filename
510 QString pathPrefix = sourcePath.left(n: sourcePath.lastIndexOf(c: QLatin1Char('/')));
511
512 // Check if the path contains any special chars
513 int pos = -1;
514 if (syntax == QRegExp::Wildcard)
515 pos = pathPrefix.indexOf(QRegExp(QLatin1String("[*?[]")));
516 else if (syntax != QRegExp::FixedString)
517 pos = sourcePath.indexOf(QRegExp(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
518 if (pos != -1) {
519 // there was a special char in the path so cut of the part containing that char.
520 pathPrefix = pathPrefix.left(n: pos);
521 const int lastIndexOfSlash = pathPrefix.lastIndexOf(c: QLatin1Char('/'));
522 if (lastIndexOfSlash != -1)
523 pathPrefix = pathPrefix.left(n: lastIndexOfSlash);
524 else
525 pathPrefix.clear();
526 } else {
527 // Check if the path is a file.
528 if (QFileInfo(sourcePath).isFile()) {
529 QFile file(sourcePath);
530 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
531 if (format == QSsl::Pem)
532 openMode |= QIODevice::Text;
533 if (file.open(flags: openMode))
534 return QSslCertificate::fromData(data: file.readAll(), format);
535 return QList<QSslCertificate>();
536 }
537 }
538
539 // Special case - if the prefix ends up being nothing, use "." instead.
540 int startIndex = 0;
541 if (pathPrefix.isEmpty()) {
542 pathPrefix = QLatin1String(".");
543 startIndex = 2;
544 }
545
546 // The path can be a file or directory.
547 QList<QSslCertificate> certs;
548 QRegExp pattern(sourcePath, Qt::CaseSensitive, syntax);
549 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
550 while (it.hasNext()) {
551 QString filePath = startIndex == 0 ? it.next() : it.next().mid(position: startIndex);
552 if (!pattern.exactMatch(str: filePath))
553 continue;
554
555 QFile file(filePath);
556 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
557 if (format == QSsl::Pem)
558 openMode |= QIODevice::Text;
559 if (file.open(flags: openMode))
560 certs += QSslCertificate::fromData(data: file.readAll(), format);
561 }
562 return certs;
563}
564#endif // QT_DEPRECATED_SINCE(5,15)
565
566/*!
567 \since 5.15
568
569 Searches all files in the \a path for certificates encoded in the
570 specified \a format and returns them in a list. \a path must be a file
571 or a pattern matching one or more files, as specified by \a syntax.
572
573 Example:
574
575 \snippet code/src_network_ssl_qsslcertificate.cpp 1
576
577 \sa fromData()
578*/
579QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
580 QSsl::EncodingFormat format,
581 PatternSyntax syntax)
582{
583 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
584
585 // make sure to use the same path separators on Windows and Unix like systems.
586 QString sourcePath = QDir::fromNativeSeparators(pathName: path);
587
588 // Find the path without the filename
589 QString pathPrefix = sourcePath.left(n: sourcePath.lastIndexOf(c: QLatin1Char('/')));
590
591 // Check if the path contains any special chars
592 int pos = -1;
593
594#if QT_CONFIG(regularexpression)
595 if (syntax == PatternSyntax::Wildcard)
596 pos = pathPrefix.indexOf(re: QRegularExpression(QLatin1String("[*?[]")));
597 else if (syntax == PatternSyntax::RegularExpression)
598 pos = sourcePath.indexOf(re: QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
599#else
600 if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp)
601 qWarning("Regular expression support is disabled in this build. Only fixed string can be searched");
602 return QList<QSslCertificate>();
603#endif
604
605 if (pos != -1) {
606 // there was a special char in the path so cut of the part containing that char.
607 pathPrefix = pathPrefix.left(n: pos);
608 const int lastIndexOfSlash = pathPrefix.lastIndexOf(c: QLatin1Char('/'));
609 if (lastIndexOfSlash != -1)
610 pathPrefix = pathPrefix.left(n: lastIndexOfSlash);
611 else
612 pathPrefix.clear();
613 } else {
614 // Check if the path is a file.
615 if (QFileInfo(sourcePath).isFile()) {
616 QFile file(sourcePath);
617 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
618 if (format == QSsl::Pem)
619 openMode |= QIODevice::Text;
620 if (file.open(flags: openMode))
621 return QSslCertificate::fromData(data: file.readAll(), format);
622 return QList<QSslCertificate>();
623 }
624 }
625
626 // Special case - if the prefix ends up being nothing, use "." instead.
627 int startIndex = 0;
628 if (pathPrefix.isEmpty()) {
629 pathPrefix = QLatin1String(".");
630 startIndex = 2;
631 }
632
633 // The path can be a file or directory.
634 QList<QSslCertificate> certs;
635
636#if QT_CONFIG(regularexpression)
637 if (syntax == PatternSyntax::Wildcard)
638 sourcePath = QRegularExpression::wildcardToRegularExpression(str: sourcePath);
639
640 QRegularExpression pattern(QRegularExpression::anchoredPattern(expression: sourcePath));
641#endif
642
643 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
644 while (it.hasNext()) {
645 QString filePath = startIndex == 0 ? it.next() : it.next().mid(position: startIndex);
646
647#if QT_CONFIG(regularexpression)
648 if (!pattern.match(subject: filePath).hasMatch())
649 continue;
650#else
651 if (sourcePath != filePath)
652 continue;
653#endif
654
655 QFile file(filePath);
656 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
657 if (format == QSsl::Pem)
658 openMode |= QIODevice::Text;
659 if (file.open(flags: openMode))
660 certs += QSslCertificate::fromData(data: file.readAll(), format);
661 }
662 return certs;
663}
664
665/*!
666 Searches for and parses all certificates in \a device that are
667 encoded in the specified \a format and returns them in a list of
668 certificates.
669
670 \sa fromData()
671*/
672QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
673{
674 if (!device) {
675 qCWarning(lcSsl, "QSslCertificate::fromDevice: cannot read from a null device");
676 return QList<QSslCertificate>();
677 }
678 return fromData(data: device->readAll(), format);
679}
680
681/*!
682 Searches for and parses all certificates in \a data that are
683 encoded in the specified \a format and returns them in a list of
684 certificates.
685
686 \sa fromDevice()
687*/
688QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
689{
690 return (format == QSsl::Pem)
691 ? QSslCertificatePrivate::certificatesFromPem(pem: data)
692 : QSslCertificatePrivate::certificatesFromDer(der: data);
693}
694
695#ifndef QT_NO_SSL
696
697/*!
698 Verifies a certificate chain. The chain to be verified is passed in the
699 \a certificateChain parameter. The first certificate in the list should
700 be the leaf certificate of the chain to be verified. If \a hostName is
701 specified then the certificate is also checked to see if it is valid for
702 the specified host name.
703
704 Note that the root (CA) certificate should not be included in the list to be verified,
705 this will be looked up automatically using the CA list specified in the
706 default QSslConfiguration, and, in addition, if possible, CA certificates loaded on
707 demand on Unix and Windows.
708
709 \since 5.0
710 */
711#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
712QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
713#else
714QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
715#endif
716{
717 return QSslSocketBackendPrivate::verify(certificateChain, hostName);
718}
719
720/*!
721 \since 5.4
722
723 Imports a PKCS#12 (pfx) file from the specified \a device. A PKCS#12
724 file is a bundle that can contain a number of certificates and keys.
725 This method reads a single \a key, its \a certificate and any
726 associated \a caCertificates from the bundle. If a \a passPhrase is
727 specified then this will be used to decrypt the bundle. Returns
728 \c true if the PKCS#12 file was successfully loaded.
729
730 \note The \a device must be open and ready to be read from.
731 */
732bool QSslCertificate::importPkcs12(QIODevice *device,
733 QSslKey *key, QSslCertificate *certificate,
734 QList<QSslCertificate> *caCertificates,
735 const QByteArray &passPhrase)
736{
737 return QSslSocketBackendPrivate::importPkcs12(device, key, cert: certificate, caCertificates, passPhrase);
738}
739
740#endif
741
742// These certificates are known to be fraudulent and were created during the comodo
743// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
744static const char *const certificate_blacklist[] = {
745 "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo
746 "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo
747 "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo
748 "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", "login.yahoo.com", // Comodo
749 "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", "login.yahoo.com", // Comodo
750 "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", "login.skype.com", // Comodo
751 "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", "addons.mozilla.org", // Comodo
752 "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", "login.live.com", // Comodo
753 "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", "global trustee", // Comodo
754
755 "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", "*.google.com", // leaf certificate issued by DigiNotar
756 "0c:76:da:9c:91:0c:4e:2c:9e:fe:15:d0:58:93:3c:4c", "DigiNotar Root CA", // DigiNotar root
757 "f1:4a:13:f4:87:2b:56:dc:39:df:84:ca:7a:a1:06:49", "DigiNotar Services CA", // DigiNotar intermediate signed by DigiNotar Root
758 "36:16:71:55:43:42:1b:9d:e6:cb:a3:64:41:df:24:38", "DigiNotar Services 1024 CA", // DigiNotar intermediate signed by DigiNotar Root
759 "0a:82:bd:1e:14:4e:88:14:d7:5b:1a:55:27:be:bf:3e", "DigiNotar Root CA G2", // other DigiNotar Root CA
760 "a4:b6:ce:e3:2e:d3:35:46:26:3c:b3:55:3a:a8:92:21", "CertiID Enterprise Certificate Authority", // DigiNotar intermediate signed by "DigiNotar Root CA G2"
761 "5b:d5:60:9c:64:17:68:cf:21:0e:35:fd:fb:05:ad:41", "DigiNotar Qualified CA", // DigiNotar intermediate signed by DigiNotar Root
762
763 "46:9c:2c:b0", "DigiNotar Services 1024 CA", // DigiNotar intermediate cross-signed by Entrust
764 "07:27:10:0d", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
765 "07:27:0f:f9", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
766 "07:27:10:03", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
767 "01:31:69:b0", "DigiNotar PKIoverheid CA Overheid en Bedrijven", // DigiNotar intermediate cross-signed by the Dutch government
768 "01:31:34:bf", "DigiNotar PKIoverheid CA Organisatie - G2", // DigiNotar intermediate cross-signed by the Dutch government
769 "d6:d0:29:77:f1:49:fd:1a:83:f2:b9:ea:94:8c:5c:b4", "DigiNotar Extended Validation CA", // DigiNotar intermediate signed by DigiNotar EV Root
770 "1e:7d:7a:53:3d:45:30:41:96:40:0f:71:48:1f:45:04", "DigiNotar Public CA 2025", // DigiNotar intermediate
771// "(has not been seen in the wild so far)", "DigiNotar Public CA - G2", // DigiNotar intermediate
772// "(has not been seen in the wild so far)", "Koninklijke Notariele Beroepsorganisatie CA", // compromised during DigiNotar breach
773// "(has not been seen in the wild so far)", "Stichting TTP Infos CA," // compromised during DigiNotar breach
774 "46:9c:2c:af", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
775 "46:9c:3c:c9", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
776
777 "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust
778 "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust
779 "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate
780 "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/
781
782 "08:27", "*.EGO.GOV.TR", // Turktrust mis-issued intermediate certificate
783 "08:64", "e-islem.kktcmerkezbankasi.org", // Turktrust mis-issued intermediate certificate
784
785 "03:1d:a7", "AC DG Tr\xC3\xA9sor SSL", // intermediate certificate linking back to ANSSI French National Security Agency
786 "27:83", "NIC Certifying Authority", // intermediate certificate from NIC India (2007)
787 "27:92", "NIC CA 2011", // intermediate certificate from NIC India (2011)
788 "27:b1", "NIC CA 2014", // intermediate certificate from NIC India (2014)
789 nullptr
790};
791
792bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
793{
794 for (int a = 0; certificate_blacklist[a] != nullptr; a++) {
795 QString blacklistedCommonName = QString::fromUtf8(str: certificate_blacklist[(a+1)]);
796 if (certificate.serialNumber() == certificate_blacklist[a++] &&
797 (certificate.subjectInfo(info: QSslCertificate::CommonName).contains(str: blacklistedCommonName) ||
798 certificate.issuerInfo(info: QSslCertificate::CommonName).contains(str: blacklistedCommonName)))
799 return true;
800 }
801 return false;
802}
803
804QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info)
805{
806 QByteArray str;
807 switch (info) {
808 case QSslCertificate::Organization: str = QByteArray("O"); break;
809 case QSslCertificate::CommonName: str = QByteArray("CN"); break;
810 case QSslCertificate::LocalityName: str = QByteArray("L"); break;
811 case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
812 case QSslCertificate::CountryName: str = QByteArray("C"); break;
813 case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
814 case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
815 case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
816 case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
817 }
818 return str;
819}
820
821/*!
822 \since 5.12
823
824 Returns a name that describes the issuer. It returns the QSslCertificate::CommonName
825 if available, otherwise falls back to the first QSslCertificate::Organization or the
826 first QSslCertificate::OrganizationalUnitName.
827
828 \sa issuerInfo()
829*/
830QString QSslCertificate::issuerDisplayName() const
831{
832 QStringList names;
833 names = issuerInfo(info: QSslCertificate::CommonName);
834 if (!names.isEmpty())
835 return names.first();
836 names = issuerInfo(info: QSslCertificate::Organization);
837 if (!names.isEmpty())
838 return names.first();
839 names = issuerInfo(info: QSslCertificate::OrganizationalUnitName);
840 if (!names.isEmpty())
841 return names.first();
842
843 return QString();
844}
845
846/*!
847 \since 5.12
848
849 Returns a name that describes the subject. It returns the QSslCertificate::CommonName
850 if available, otherwise falls back to the first QSslCertificate::Organization or the
851 first QSslCertificate::OrganizationalUnitName.
852
853 \sa subjectInfo()
854*/
855QString QSslCertificate::subjectDisplayName() const
856{
857 QStringList names;
858 names = subjectInfo(info: QSslCertificate::CommonName);
859 if (!names.isEmpty())
860 return names.first();
861 names = subjectInfo(info: QSslCertificate::Organization);
862 if (!names.isEmpty())
863 return names.first();
864 names = subjectInfo(info: QSslCertificate::OrganizationalUnitName);
865 if (!names.isEmpty())
866 return names.first();
867
868 return QString();
869}
870
871/*!
872 \fn uint qHash(const QSslCertificate &key, uint seed)
873
874 Returns the hash value for the \a key, using \a seed to seed the calculation.
875 \since 5.4
876 \relates QHash
877*/
878
879#ifndef QT_NO_DEBUG_STREAM
880QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
881{
882 QDebugStateSaver saver(debug);
883 debug.resetFormat().nospace();
884 debug << "QSslCertificate("
885 << certificate.version()
886 << ", " << certificate.serialNumber()
887 << ", " << certificate.digest().toBase64()
888 << ", " << certificate.issuerDisplayName()
889 << ", " << certificate.subjectDisplayName()
890 << ", " << certificate.subjectAlternativeNames()
891#if QT_CONFIG(datestring)
892 << ", " << certificate.effectiveDate()
893 << ", " << certificate.expiryDate()
894#endif
895 << ')';
896 return debug;
897}
898QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
899{
900 switch (info) {
901 case QSslCertificate::Organization: debug << "Organization"; break;
902 case QSslCertificate::CommonName: debug << "CommonName"; break;
903 case QSslCertificate::CountryName: debug << "CountryName"; break;
904 case QSslCertificate::LocalityName: debug << "LocalityName"; break;
905 case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
906 case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
907 case QSslCertificate::DistinguishedNameQualifier: debug << "DistinguishedNameQualifier"; break;
908 case QSslCertificate::SerialNumber: debug << "SerialNumber"; break;
909 case QSslCertificate::EmailAddress: debug << "EmailAddress"; break;
910 }
911 return debug;
912}
913#endif
914
915QT_END_NAMESPACE
916

source code of qtbase/src/network/ssl/qsslcertificate.cpp