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#ifdef QT_SECURETRANSPORT
138#include "qsslsocket_mac_p.h"
139#endif
140#if QT_CONFIG(schannel)
141#include "qsslsocket_schannel_p.h"
142#endif
143#if QT_CONFIG(regularexpression)
144#include "qregularexpression.h"
145#endif
146#include "qssl_p.h"
147#include "qsslcertificate.h"
148#include "qsslcertificate_p.h"
149#ifndef QT_NO_SSL
150#include "qsslkey_p.h"
151#endif
152
153#include <QtCore/qdir.h>
154#include <QtCore/qdiriterator.h>
155#include <QtCore/qfile.h>
156
157QT_BEGIN_NAMESPACE
158
159/*!
160 Constructs a QSslCertificate by reading \a format encoded data
161 from \a device and using the first certificate found. You can
162 later call isNull() to see if \a device contained a certificate,
163 and if this certificate was loaded successfully.
164*/
165QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
166 : d(new QSslCertificatePrivate)
167{
168#ifndef QT_NO_OPENSSL
169 QSslSocketPrivate::ensureInitialized();
170 if (device && QSslSocket::supportsSsl())
171#else
172 if (device)
173#endif
174 d->init(device->readAll(), format);
175}
176
177/*!
178 Constructs a QSslCertificate by parsing the \a format encoded
179 \a data and using the first available certificate found. You can
180 later call isNull() to see if \a data contained a certificate,
181 and if this certificate was loaded successfully.
182*/
183QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
184 : d(new QSslCertificatePrivate)
185{
186#ifndef QT_NO_OPENSSL
187 QSslSocketPrivate::ensureInitialized();
188 if (QSslSocket::supportsSsl())
189#endif
190 d->init(data, format);
191}
192
193/*!
194 Constructs an identical copy of \a other.
195*/
196QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
197{
198}
199
200/*!
201 Destroys the QSslCertificate.
202*/
203QSslCertificate::~QSslCertificate()
204{
205}
206
207/*!
208 Copies the contents of \a other into this certificate, making the two
209 certificates identical.
210*/
211QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
212{
213 d = other.d;
214 return *this;
215}
216
217/*!
218 \fn void QSslCertificate::swap(QSslCertificate &other)
219 \since 5.0
220
221 Swaps this certificate instance with \a other. This function is
222 very fast and never fails.
223*/
224
225/*!
226 \fn bool QSslCertificate::operator==(const QSslCertificate &other) const
227
228 Returns \c true if this certificate is the same as \a other; otherwise
229 returns \c false.
230*/
231
232/*!
233 \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
234
235 Returns \c true if this certificate is not the same as \a other; otherwise
236 returns \c false.
237*/
238
239/*!
240 \fn bool QSslCertificate::isNull() const
241
242 Returns \c true if this is a null certificate (i.e., a certificate
243 with no contents); otherwise returns \c false.
244
245 By default, QSslCertificate constructs a null certificate.
246
247 \sa clear()
248*/
249
250/*!
251 Returns \c true if this certificate is blacklisted; otherwise
252 returns \c false.
253
254 \sa isNull()
255*/
256bool QSslCertificate::isBlacklisted() const
257{
258 return QSslCertificatePrivate::isBlacklisted(*this);
259}
260
261/*!
262 \fn bool QSslCertificate::isSelfSigned() const
263 \since 5.4
264
265 Returns \c true if this certificate is self signed; otherwise
266 returns \c false.
267
268 A certificate is considered self-signed its issuer and subject
269 are identical.
270*/
271
272/*!
273 Clears the contents of this certificate, making it a null
274 certificate.
275
276 \sa isNull()
277*/
278void QSslCertificate::clear()
279{
280 if (isNull())
281 return;
282 d = new QSslCertificatePrivate;
283}
284
285/*!
286 \fn QByteArray QSslCertificate::version() const
287 Returns the certificate's version string.
288*/
289
290/*!
291 \fn QByteArray QSslCertificate::serialNumber() const
292
293 Returns the certificate's serial number string in hexadecimal format.
294*/
295
296/*!
297 Returns a cryptographic digest of this certificate. By default,
298 an MD5 digest will be generated, but you can also specify a
299 custom \a algorithm.
300*/
301QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
302{
303 return QCryptographicHash::hash(toDer(), algorithm);
304}
305
306/*!
307 \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
308
309 Returns the issuer information for the \a subject from the
310 certificate, or an empty list if there is no information for
311 \a subject in the certificate. There can be more than one entry
312 of each type.
313
314 \sa subjectInfo()
315*/
316
317/*!
318 \fn QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
319
320 Returns the issuer information for \a attribute from the certificate,
321 or an empty list if there is no information for \a attribute in the
322 certificate. There can be more than one entry for an attribute.
323
324 \sa subjectInfo()
325*/
326
327/*!
328 \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
329
330 Returns the information for the \a subject, or an empty list if
331 there is no information for \a subject in the certificate. There
332 can be more than one entry of each type.
333
334 \sa issuerInfo()
335*/
336
337/*!
338 \fn QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
339
340 Returns the subject information for \a attribute, or an empty list if
341 there is no information for \a attribute in the certificate. There
342 can be more than one entry for an attribute.
343
344 \sa issuerInfo()
345*/
346
347/*!
348 \fn QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
349
350 \since 5.0
351 Returns a list of the attributes that have values in the subject
352 information of this certificate. The information associated
353 with a given attribute can be accessed using the subjectInfo()
354 method. Note that this list may include the OIDs for any
355 elements that are not known by the SSL backend.
356
357 \sa subjectInfo()
358*/
359
360/*!
361 \fn QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
362
363 \since 5.0
364 Returns a list of the attributes that have values in the issuer
365 information of this certificate. The information associated
366 with a given attribute can be accessed using the issuerInfo()
367 method. Note that this list may include the OIDs for any
368 elements that are not known by the SSL backend.
369
370 \sa subjectInfo()
371*/
372
373/*!
374 \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
375
376 Returns the list of alternative subject names for this
377 certificate. The alternative names typically contain host
378 names, optionally with wildcards, that are valid for this
379 certificate.
380
381 These names are tested against the connected peer's host name, if
382 either the subject information for \l CommonName doesn't define a
383 valid host name, or the subject info name doesn't match the peer's
384 host name.
385
386 \sa subjectInfo()
387*/
388
389/*!
390 \fn QDateTime QSslCertificate::effectiveDate() const
391
392 Returns the date-time that the certificate becomes valid, or an
393 empty QDateTime if this is a null certificate.
394
395 \sa expiryDate()
396*/
397
398/*!
399 \fn QDateTime QSslCertificate::expiryDate() const
400
401 Returns the date-time that the certificate expires, or an empty
402 QDateTime if this is a null certificate.
403
404 \sa effectiveDate()
405*/
406
407/*!
408 \fn Qt::HANDLE QSslCertificate::handle() const
409 Returns a pointer to the native certificate handle, if there is
410 one, else \nullptr.
411
412 You can use this handle, together with the native API, to access
413 extended information about the certificate.
414
415 \warning Use of this function has a high probability of being
416 non-portable, and its return value may vary from platform to
417 platform or change from minor release to minor release.
418*/
419
420/*!
421 \fn QSslKey QSslCertificate::publicKey() const
422 Returns the certificate subject's public key.
423*/
424
425/*!
426 \fn QList<QSslCertificateExtension> QSslCertificate::extensions() const
427
428 Returns a list containing the X509 extensions of this certificate.
429 \since 5.0
430 */
431
432/*!
433 \fn QByteArray QSslCertificate::toPem() const
434
435 Returns this certificate converted to a PEM (Base64) encoded
436 representation.
437*/
438
439/*!
440 \fn QByteArray QSslCertificate::toDer() const
441
442 Returns this certificate converted to a DER (binary) encoded
443 representation.
444*/
445
446/*!
447 \fn QString QSslCertificate::toText() const
448
449 Returns this certificate converted to a human-readable text
450 representation.
451
452 \since 5.0
453*/
454
455/*!
456 \since 5.15
457
458 Searches all files in the \a path for certificates encoded in the
459 specified \a format and returns them in a list. \a path must be a file
460 or a pattern matching one or more files, as specified by \a syntax.
461
462 Example:
463
464 \snippet code/src_network_ssl_qsslcertificate.cpp 1
465
466 \sa fromData()
467*/
468QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
469 QSsl::EncodingFormat format,
470 PatternSyntax syntax)
471{
472 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
473
474 // make sure to use the same path separators on Windows and Unix like systems.
475 QString sourcePath = QDir::fromNativeSeparators(path);
476
477 // Find the path without the filename
478 QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(QLatin1Char('/')));
479
480 // Check if the path contains any special chars
481 int pos = -1;
482
483#if QT_CONFIG(regularexpression)
484 if (syntax == PatternSyntax::Wildcard)
485 pos = pathPrefix.indexOf(QRegularExpression(QLatin1String("[*?[]")));
486 else if (syntax == PatternSyntax::RegularExpression)
487 pos = sourcePath.indexOf(QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
488#else
489 if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp)
490 qWarning("Regular expression support is disabled in this build. Only fixed string can be searched");
491 return QList<QSslCertificate>();
492#endif
493
494 if (pos != -1) {
495 // there was a special char in the path so cut of the part containing that char.
496 pathPrefix = pathPrefix.left(pos);
497 const int lastIndexOfSlash = pathPrefix.lastIndexOf(QLatin1Char('/'));
498 if (lastIndexOfSlash != -1)
499 pathPrefix = pathPrefix.left(lastIndexOfSlash);
500 else
501 pathPrefix.clear();
502 } else {
503 // Check if the path is a file.
504 if (QFileInfo(sourcePath).isFile()) {
505 QFile file(sourcePath);
506 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
507 if (format == QSsl::Pem)
508 openMode |= QIODevice::Text;
509 if (file.open(openMode))
510 return QSslCertificate::fromData(file.readAll(), format);
511 return QList<QSslCertificate>();
512 }
513 }
514
515 // Special case - if the prefix ends up being nothing, use "." instead.
516 int startIndex = 0;
517 if (pathPrefix.isEmpty()) {
518 pathPrefix = QLatin1String(".");
519 startIndex = 2;
520 }
521
522 // The path can be a file or directory.
523 QList<QSslCertificate> certs;
524
525#if QT_CONFIG(regularexpression)
526 if (syntax == PatternSyntax::Wildcard)
527 sourcePath = QRegularExpression::wildcardToRegularExpression(sourcePath, QRegularExpression::UnanchoredWildcardConversion);
528
529 QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath));
530#endif
531
532 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
533 while (it.hasNext()) {
534 QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
535
536#if QT_CONFIG(regularexpression)
537 if (!pattern.match(filePath).hasMatch())
538 continue;
539#else
540 if (sourcePath != filePath)
541 continue;
542#endif
543
544 QFile file(filePath);
545 QIODevice::OpenMode openMode = QIODevice::ReadOnly;
546 if (format == QSsl::Pem)
547 openMode |= QIODevice::Text;
548 if (file.open(openMode))
549 certs += QSslCertificate::fromData(file.readAll(), format);
550 }
551 return certs;
552}
553
554/*!
555 Searches for and parses all certificates in \a device that are
556 encoded in the specified \a format and returns them in a list of
557 certificates.
558
559 \sa fromData()
560*/
561QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
562{
563 if (!device) {
564 qCWarning(lcSsl, "QSslCertificate::fromDevice: cannot read from a null device");
565 return QList<QSslCertificate>();
566 }
567 return fromData(device->readAll(), format);
568}
569
570/*!
571 Searches for and parses all certificates in \a data that are
572 encoded in the specified \a format and returns them in a list of
573 certificates.
574
575 \sa fromDevice()
576*/
577QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
578{
579 return (format == QSsl::Pem)
580 ? QSslCertificatePrivate::certificatesFromPem(data)
581 : QSslCertificatePrivate::certificatesFromDer(data);
582}
583
584#ifndef QT_NO_SSL
585
586/*!
587 Verifies a certificate chain. The chain to be verified is passed in the
588 \a certificateChain parameter. The first certificate in the list should
589 be the leaf certificate of the chain to be verified. If \a hostName is
590 specified then the certificate is also checked to see if it is valid for
591 the specified host name.
592
593 Note that the root (CA) certificate should not be included in the list to be verified,
594 this will be looked up automatically either using the CA list specified by
595 QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand
596 on Unix.
597
598 \since 5.0
599 */
600#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
601QList<QSslError> QSslCertificate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
602#else
603QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
604#endif
605{
606 return QSslSocketBackendPrivate::verify(certificateChain, hostName);
607}
608
609/*!
610 \since 5.4
611
612 Imports a PKCS#12 (pfx) file from the specified \a device. A PKCS#12
613 file is a bundle that can contain a number of certificates and keys.
614 This method reads a single \a key, its \a certificate and any
615 associated \a caCertificates from the bundle. If a \a passPhrase is
616 specified then this will be used to decrypt the bundle. Returns
617 \c true if the PKCS#12 file was successfully loaded.
618
619 \note The \a device must be open and ready to be read from.
620 */
621bool QSslCertificate::importPkcs12(QIODevice *device,
622 QSslKey *key, QSslCertificate *certificate,
623 QList<QSslCertificate> *caCertificates,
624 const QByteArray &passPhrase)
625{
626 return QSslSocketBackendPrivate::importPkcs12(device, key, certificate, caCertificates, passPhrase);
627}
628
629#endif
630
631// These certificates are known to be fraudulent and were created during the comodo
632// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
633static const char *const certificate_blacklist[] = {
634 "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo
635 "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo
636 "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo
637 "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", "login.yahoo.com", // Comodo
638 "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", "login.yahoo.com", // Comodo
639 "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", "login.skype.com", // Comodo
640 "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", "addons.mozilla.org", // Comodo
641 "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", "login.live.com", // Comodo
642 "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", "global trustee", // Comodo
643
644 "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", "*.google.com", // leaf certificate issued by DigiNotar
645 "0c:76:da:9c:91:0c:4e:2c:9e:fe:15:d0:58:93:3c:4c", "DigiNotar Root CA", // DigiNotar root
646 "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
647 "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
648 "0a:82:bd:1e:14:4e:88:14:d7:5b:1a:55:27:be:bf:3e", "DigiNotar Root CA G2", // other DigiNotar Root CA
649 "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"
650 "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
651
652 "46:9c:2c:b0", "DigiNotar Services 1024 CA", // DigiNotar intermediate cross-signed by Entrust
653 "07:27:10:0d", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
654 "07:27:0f:f9", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
655 "07:27:10:03", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
656 "01:31:69:b0", "DigiNotar PKIoverheid CA Overheid en Bedrijven", // DigiNotar intermediate cross-signed by the Dutch government
657 "01:31:34:bf", "DigiNotar PKIoverheid CA Organisatie - G2", // DigiNotar intermediate cross-signed by the Dutch government
658 "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
659 "1e:7d:7a:53:3d:45:30:41:96:40:0f:71:48:1f:45:04", "DigiNotar Public CA 2025", // DigiNotar intermediate
660// "(has not been seen in the wild so far)", "DigiNotar Public CA - G2", // DigiNotar intermediate
661// "(has not been seen in the wild so far)", "Koninklijke Notariele Beroepsorganisatie CA", // compromised during DigiNotar breach
662// "(has not been seen in the wild so far)", "Stichting TTP Infos CA," // compromised during DigiNotar breach
663 "46:9c:2c:af", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
664 "46:9c:3c:c9", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
665
666 "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust
667 "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust
668 "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate
669 "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/
670
671 "08:27", "*.EGO.GOV.TR", // Turktrust mis-issued intermediate certificate
672 "08:64", "e-islem.kktcmerkezbankasi.org", // Turktrust mis-issued intermediate certificate
673
674 "03:1d:a7", "AC DG Tr\xC3\xA9sor SSL", // intermediate certificate linking back to ANSSI French National Security Agency
675 "27:83", "NIC Certifying Authority", // intermediate certificate from NIC India (2007)
676 "27:92", "NIC CA 2011", // intermediate certificate from NIC India (2011)
677 "27:b1", "NIC CA 2014", // intermediate certificate from NIC India (2014)
678 nullptr
679};
680
681bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
682{
683 for (int a = 0; certificate_blacklist[a] != nullptr; a++) {
684 QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);
685 if (certificate.serialNumber() == certificate_blacklist[a++] &&
686 (certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
687 certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
688 return true;
689 }
690 return false;
691}
692
693QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info)
694{
695 QByteArray str;
696 switch (info) {
697 case QSslCertificate::Organization: str = QByteArray("O"); break;
698 case QSslCertificate::CommonName: str = QByteArray("CN"); break;
699 case QSslCertificate::LocalityName: str = QByteArray("L"); break;
700 case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
701 case QSslCertificate::CountryName: str = QByteArray("C"); break;
702 case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
703 case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
704 case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
705 case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
706 }
707 return str;
708}
709
710/*!
711 \since 5.12
712
713 Returns a name that describes the issuer. It returns the QSslCertificate::CommonName
714 if available, otherwise falls back to the first QSslCertificate::Organization or the
715 first QSslCertificate::OrganizationalUnitName.
716
717 \sa issuerInfo()
718*/
719QString QSslCertificate::issuerDisplayName() const
720{
721 QStringList names;
722 names = issuerInfo(QSslCertificate::CommonName);
723 if (!names.isEmpty())
724 return names.first();
725 names = issuerInfo(QSslCertificate::Organization);
726 if (!names.isEmpty())
727 return names.first();
728 names = issuerInfo(QSslCertificate::OrganizationalUnitName);
729 if (!names.isEmpty())
730 return names.first();
731
732 return QString();
733}
734
735/*!
736 \since 5.12
737
738 Returns a name that describes the subject. It returns the QSslCertificate::CommonName
739 if available, otherwise falls back to the first QSslCertificate::Organization or the
740 first QSslCertificate::OrganizationalUnitName.
741
742 \sa subjectInfo()
743*/
744QString QSslCertificate::subjectDisplayName() const
745{
746 QStringList names;
747 names = subjectInfo(QSslCertificate::CommonName);
748 if (!names.isEmpty())
749 return names.first();
750 names = subjectInfo(QSslCertificate::Organization);
751 if (!names.isEmpty())
752 return names.first();
753 names = subjectInfo(QSslCertificate::OrganizationalUnitName);
754 if (!names.isEmpty())
755 return names.first();
756
757 return QString();
758}
759
760/*!
761 \fn size_t qHash(const QSslCertificate &key, size_t seed)
762
763 Returns the hash value for the \a key, using \a seed to seed the calculation.
764 \since 5.4
765 \relates QHash
766*/
767
768#ifndef QT_NO_DEBUG_STREAM
769QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
770{
771 QDebugStateSaver saver(debug);
772 debug.resetFormat().nospace();
773 debug << "QSslCertificate("
774 << certificate.version()
775 << ", " << certificate.serialNumber()
776 << ", " << certificate.digest().toBase64()
777 << ", " << certificate.issuerDisplayName()
778 << ", " << certificate.subjectDisplayName()
779 << ", " << certificate.subjectAlternativeNames()
780#if QT_CONFIG(datestring)
781 << ", " << certificate.effectiveDate()
782 << ", " << certificate.expiryDate()
783#endif
784 << ')';
785 return debug;
786}
787QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
788{
789 switch (info) {
790 case QSslCertificate::Organization: debug << "Organization"; break;
791 case QSslCertificate::CommonName: debug << "CommonName"; break;
792 case QSslCertificate::CountryName: debug << "CountryName"; break;
793 case QSslCertificate::LocalityName: debug << "LocalityName"; break;
794 case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
795 case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
796 case QSslCertificate::DistinguishedNameQualifier: debug << "DistinguishedNameQualifier"; break;
797 case QSslCertificate::SerialNumber: debug << "SerialNumber"; break;
798 case QSslCertificate::EmailAddress: debug << "EmailAddress"; break;
799 }
800 return debug;
801}
802#endif
803
804QT_END_NAMESPACE
805