1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 \class QSslCertificate
45 \brief The QSslCertificate class provides a convenient API for an X509 certificate.
53 QSslCertificate stores an X509 certificate, and is commonly used
54 to verify the identity and store information about the local host,
55 a remotely connected peer, or a trusted third party Certificate
58 There are many ways to construct a QSslCertificate. The most
59 common way is to call QSslSocket::peerCertificate(), which returns
60 a QSslCertificate object, or QSslSocket::peerCertificateChain(),
61 which returns a list of them. You can also load certificates from
62 a DER (binary) or PEM (Base64) encoded bundle, typically stored as
63 one or more local files, or in a Qt Resource.
65 You can call isNull() to check if your certificate is null. By default,
66 QSslCertificate constructs a null certificate. A null certificate is
67 invalid, but an invalid certificate is not necessarily null. If you want
68 to reset all contents in a certificate, call clear().
70 After loading a certificate, you can find information about the
71 certificate, its subject, and its issuer, by calling one of the
72 many accessor functions, including version(), serialNumber(),
73 issuerInfo() and subjectInfo(). You can call effectiveDate() and
74 expiryDate() to check when the certificate starts being
75 effective and when it expires.
76 The publicKey() function returns the certificate
77 subject's public key as a QSslKey. You can call issuerInfo() or
78 subjectInfo() to get detailed information about the certificate
79 issuer and its subject.
81 Internally, QSslCertificate is stored as an X509 structure. You
82 can access this handle by calling handle(), but the results are
83 likely to not be portable.
85 \sa QSslSocket, QSslKey, QSslCipher, QSslError
89 \enum QSslCertificate::SubjectInfo
91 Describes keys that you can pass to QSslCertificate::issuerInfo() or
92 QSslCertificate::subjectInfo() to get information about the certificate
95 \value Organization "O" The name of the organization.
97 \value CommonName "CN" The common name; most often this is used to store
100 \value LocalityName "L" The locality.
102 \value OrganizationalUnitName "OU" The organizational unit name.
104 \value CountryName "C" The country.
106 \value StateOrProvinceName "ST" The state or province.
108 \value DistinguishedNameQualifier The distinguished name qualifier
110 \value SerialNumber The certificate's serial number
112 \value EmailAddress The email address associated with the certificate
115 #include "qsslsocket_openssl_symbols_p.h"
116 #include "qsslcertificate.h"
117 #include "qsslcertificate_p.h"
119 #include "qsslkey_p.h"
120 #include "qsslcertificateextension.h"
121 #include "qsslcertificateextension_p.h"
123 #include <QtCore/qatomic.h>
124 #include <QtCore/qdatetime.h>
125 #include <QtCore/qdebug.h>
126 #include <QtCore/qdir.h>
127 #include <QtCore/qdiriterator.h>
128 #include <QtCore/qfile.h>
129 #include <QtCore/qfileinfo.h>
130 #include <QtCore/qmap.h>
131 #include <QtCore/qmutex.h>
132 #include <QtCore/private/qmutexpool_p.h>
133 #include <QtCore/qstring.h>
134 #include <QtCore/qstringlist.h>
135 #include <QtCore/qvarlengtharray.h>
139 // forward declaration
140 static QMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
143 Constructs a QSslCertificate by reading \a format encoded data
144 from \a device and using the first certificate found. You can
145 later call isNull() to see if \a device contained a certificate,
146 and if this certificate was loaded successfully.
148 QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
149 : d(new QSslCertificatePrivate)
151 QSslSocketPrivate::ensureInitialized();
153 d->init(device->readAll(), format);
157 Constructs a QSslCertificate by parsing the \a format encoded
158 \a data and using the first available certificate found. You can
159 later call isNull() to see if \a data contained a certificate,
160 and if this certificate was loaded successfully.
162 QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
163 : d(new QSslCertificatePrivate)
165 QSslSocketPrivate::ensureInitialized();
166 d->init(data, format);
170 Constructs an identical copy of \a other.
172 QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
177 Destroys the QSslCertificate.
179 QSslCertificate::~QSslCertificate()
184 Copies the contents of \a other into this certificate, making the two
185 certificates identical.
187 QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
194 Returns true if this certificate is the same as \a other; otherwise
197 bool QSslCertificate::operator==(const QSslCertificate &other) const
201 if (d->null && other.d->null)
203 if (d->x509 && other.d->x509)
204 return q_X509_cmp(d->x509, other.d->x509) == 0;
209 \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
211 Returns true if this certificate is not the same as \a other; otherwise
216 Returns true if this is a null certificate (i.e., a certificate
217 with no contents); otherwise returns false.
219 By default, QSslCertificate constructs a null certificate.
223 bool QSslCertificate::isNull() const
228 #if QT_DEPRECATED_SINCE(5,0)
230 \fn bool QSslCertificate::isValid() const
233 To verify a certificate, use verify().
234 To check if a certificate is blacklisted, use isBlacklisted().
235 To check if a certificate has expired or is not yet valid, compare
236 expiryDate() and effectiveDate() with QDateTime::currentDateTime()
238 This function checks that the current
239 data-time is within the date-time range during which the
240 certificate is considered valid, and checks that the
241 certificate is not in a blacklist of fraudulent certificates.
243 \sa isNull(), verify(), isBlacklisted(), expiryDate(), effectiveDate()
248 Returns true if this certificate is blacklisted; otherwise
253 bool QSslCertificate::isBlacklisted() const
255 return QSslCertificatePrivate::isBlacklisted(*this);
259 Clears the contents of this certificate, making it a null
264 void QSslCertificate::clear()
268 d = new QSslCertificatePrivate;
272 Returns the certificate's version string.
274 QByteArray QSslCertificate::version() const
276 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
277 if (d->versionString.isEmpty() && d->x509)
279 QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1);
281 return d->versionString;
285 Returns the certificate's serial number string in hexadecimal format.
287 QByteArray QSslCertificate::serialNumber() const
289 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
290 if (d->serialNumberString.isEmpty() && d->x509) {
291 ASN1_INTEGER *serialNumber = d->x509->cert_info->serialNumber;
292 QByteArray hexString;
293 hexString.reserve(serialNumber->length * 3);
294 for (int a = 0; a < serialNumber->length; ++a) {
295 hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
299 d->serialNumberString = hexString;
301 return d->serialNumberString;
305 Returns a cryptographic digest of this certificate. By default,
306 an MD5 digest will be generated, but you can also specify a
309 QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
311 return QCryptographicHash::hash(toDer(), algorithm);
314 static QByteArray _q_SubjectInfoToString(QSslCertificate::SubjectInfo info)
318 case QSslCertificate::Organization: str = QByteArray("O"); break;
319 case QSslCertificate::CommonName: str = QByteArray("CN"); break;
320 case QSslCertificate::LocalityName: str = QByteArray("L"); break;
321 case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
322 case QSslCertificate::CountryName: str = QByteArray("C"); break;
323 case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
324 case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
325 case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
326 case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
332 \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
334 Returns the issuer information for the \a subject from the
335 certificate, or an empty string if there is no information for
336 \a subject in the certificate.
340 QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
342 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
344 if (d->issuerInfo.isEmpty() && d->x509)
346 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
348 return d->issuerInfo.values(_q_SubjectInfoToString(info));
352 Returns the issuer information for \a attribute from the certificate,
353 or an empty string if there is no information for \a attribute in the
358 QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
360 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
362 if (d->issuerInfo.isEmpty() && d->x509)
364 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
366 return d->issuerInfo.values(attribute);
371 \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
373 Returns the information for the \a subject, or an empty string if
374 there is no information for \a subject in the certificate.
378 QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
380 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
382 if (d->subjectInfo.isEmpty() && d->x509)
384 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
386 return d->subjectInfo.values(_q_SubjectInfoToString(info));
390 Returns the subject information for \a attribute, or an empty string if
391 there is no information for \a attribute in the certificate.
395 QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
397 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
399 if (d->subjectInfo.isEmpty() && d->x509)
401 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
403 return d->subjectInfo.values(attribute);
408 Returns a list of the attributes that have values in the subject
409 information of this certificate. The information associated
410 with a given attribute can be accessed using the subjectInfo()
411 method. Note that this list may include the OIDs for any
412 elements that are not known by the SSL backend.
416 QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
418 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
420 if (d->subjectInfo.isEmpty() && d->x509)
422 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
424 return d->subjectInfo.uniqueKeys();
429 Returns a list of the attributes that have values in the issuer
430 information of this certificate. The information associated
431 with a given attribute can be accessed using the issuerInfo()
432 method. Note that this list may include the OIDs for any
433 elements that are not known by the SSL backend.
437 QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
439 QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
441 if (d->issuerInfo.isEmpty() && d->x509)
443 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
445 return d->issuerInfo.uniqueKeys();
448 #if QT_DEPRECATED_SINCE(5,0)
450 \fn QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
453 Use QSslCertificate::subjectAlternativeNames();
458 Returns the list of alternative subject names for this
459 certificate. The alternative names typically contain host
460 names, optionally with wildcards, that are valid for this
463 These names are tested against the connected peer's host name, if
464 either the subject information for \l CommonName doesn't define a
465 valid host name, or the subject info name doesn't match the peer's
470 QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
472 QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
477 STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME)*)q_X509_get_ext_d2i(d->x509, NID_subject_alt_name, 0, 0);
480 for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
481 const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
482 if (genName->type != GEN_DNS && genName->type != GEN_EMAIL)
485 int len = q_ASN1_STRING_length(genName->d.ia5);
486 if (len < 0 || len >= 8192) {
491 const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
492 const QString altName = QString::fromLatin1(altNameStr, len);
493 if (genName->type == GEN_DNS)
494 result.insert(QSsl::DnsEntry, altName);
495 else if (genName->type == GEN_EMAIL)
496 result.insert(QSsl::EmailEntry, altName);
498 q_sk_pop_free((STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_sk_free));
505 Returns the date-time that the certificate becomes valid, or an
506 empty QDateTime if this is a null certificate.
510 QDateTime QSslCertificate::effectiveDate() const
512 return d->notValidBefore;
516 Returns the date-time that the certificate expires, or an empty
517 QDateTime if this is a null certificate.
521 QDateTime QSslCertificate::expiryDate() const
523 return d->notValidAfter;
527 Returns a pointer to the native certificate handle, if there is
528 one, or a null pointer otherwise.
530 You can use this handle, together with the native API, to access
531 extended information about the certificate.
533 \warning Use of this function has a high probability of being
534 non-portable, and its return value may vary from platform to
535 platform or change from minor release to minor release.
537 Qt::HANDLE QSslCertificate::handle() const
539 return Qt::HANDLE(d->x509);
543 Returns the certificate subject's public key.
545 QSslKey QSslCertificate::publicKey() const
552 key.d->type = QSsl::PublicKey;
553 X509_PUBKEY *xkey = d->x509->cert_info->key;
554 EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
557 if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
558 key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
559 key.d->algorithm = QSsl::Rsa;
560 key.d->isNull = false;
561 } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
562 key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
563 key.d->algorithm = QSsl::Dsa;
564 key.d->isNull = false;
565 } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
571 q_EVP_PKEY_free(pkey);
576 * Convert unknown extensions to a QVariant.
578 static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
580 // Get the extension specific method object if available
581 // we cast away the const-ness here because some versions of openssl
582 // don't use const for the parameters in the functions pointers stored
584 X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
586 ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
587 QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_data(value)),
588 q_ASN1_STRING_length(value));
592 //const unsigned char *data = ext->value->data;
593 void *ext_internal = q_X509V3_EXT_d2i(ext);
595 // If this extension can be converted
596 if (meth->i2v && ext_internal) {
597 STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, 0);
603 for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) {
604 CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
605 if (nval->name && nval->value) {
607 map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
608 } else if (nval->name) {
609 list << QString::fromUtf8(nval->name);
610 } else if (nval->value) {
611 list << QString::fromUtf8(nval->value);
619 } else if (meth->i2s && ext_internal) {
620 //qDebug() << meth->i2s(meth, ext_internal);
621 QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
623 } else if (meth->i2r && ext_internal) {
626 BIO *bio = q_BIO_new(q_BIO_s_mem());
630 meth->i2r(meth, ext_internal, bio, 0);
633 long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
634 result = QByteArray(bio_buffer, bio_size);
644 * Convert extensions to a variant. The naming of the keys of the map are
645 * taken from RFC 5280, however we decided the capitalisation in the RFC
646 * was too silly for the real world.
648 static QVariant x509ExtensionToValue(X509_EXTENSION *ext)
650 ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
651 int nid = q_OBJ_obj2nid(obj);
654 case NID_basic_constraints:
656 BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
659 result[QLatin1String("ca")] = basic->ca ? true : false;
661 result[QLatin1String("pathLenConstraint")] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
663 q_BASIC_CONSTRAINTS_free(basic);
667 case NID_info_access:
669 AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
672 for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) {
673 ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
675 GENERAL_NAME *name = ad->location;
676 if (name->type == GEN_URI) {
677 int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
678 if (len < 0 || len >= 8192) {
683 const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(name->d.uniformResourceIdentifier));
684 const QString uri = QString::fromUtf8(uriStr, len);
686 result[QString::fromUtf8(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
688 qWarning() << "Strange location type" << name->type;
692 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
693 q_sk_pop_free((_STACK*)info, reinterpret_cast<void(*)(void*)>(q_sk_free));
695 q_sk_pop_free((STACK*)info, reinterpret_cast<void(*)(void*)>(q_sk_free));
700 case NID_subject_key_identifier:
702 void *ext_internal = q_X509V3_EXT_d2i(ext);
704 // we cast away the const-ness here because some versions of openssl
705 // don't use const for the parameters in the functions pointers stored
707 X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
709 return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
712 case NID_authority_key_identifier:
714 AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
719 if (auth_key->keyid) {
720 QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
721 auth_key->keyid->length);
722 result[QLatin1String("keyid")] = keyid.toHex();
726 // TODO: GENERAL_NAMES
729 if (auth_key->serial)
730 result[QLatin1String("serial")] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
732 q_AUTHORITY_KEYID_free(auth_key);
741 QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext)
743 QSslCertificateExtension result;
745 ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
746 QByteArray oid = QSslCertificatePrivate::asn1ObjectId(obj);
747 QByteArray name = QSslCertificatePrivate::asn1ObjectName(obj);
749 result.d->oid = QString::fromUtf8(oid);
750 result.d->name = QString::fromUtf8(name);
752 bool critical = q_X509_EXTENSION_get_critical(ext);
753 result.d->critical = critical;
755 // Lets see if we have custom support for this one
756 QVariant extensionValue = x509ExtensionToValue(ext);
757 if (extensionValue.isValid()) {
758 result.d->value = extensionValue;
759 result.d->supported = true;
764 extensionValue = x509UnknownExtensionToValue(ext);
765 if (extensionValue.isValid()) {
766 result.d->value = extensionValue;
767 result.d->supported = false;
775 Returns a list containing the X509 extensions of this certificate.
778 QList<QSslCertificateExtension> QSslCertificate::extensions() const
780 QList<QSslCertificateExtension> result;
785 int count = q_X509_get_ext_count(d->x509);
787 for (int i=0; i < count; i++) {
788 X509_EXTENSION *ext = q_X509_get_ext(d->x509, i);
789 result << QSslCertificatePrivate::convertExtension(ext);
796 Returns this certificate converted to a PEM (Base64) encoded
799 QByteArray QSslCertificate::toPem() const
803 return d->QByteArray_from_X509(d->x509, QSsl::Pem);
807 Returns this certificate converted to a DER (binary) encoded
810 QByteArray QSslCertificate::toDer() const
814 return d->QByteArray_from_X509(d->x509, QSsl::Der);
818 Returns this certificate converted to a human-readable text
823 QByteArray QSslCertificate::toText() const
827 return d->text_from_X509(d->x509);
831 Searches all files in the \a path for certificates encoded in the
832 specified \a format and returns them in a list. \e must be a file or a
833 pattern matching one or more files, as specified by \a syntax.
837 \snippet code/src_network_ssl_qsslcertificate.cpp 0
841 QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
842 QSsl::EncodingFormat format,
843 QRegExp::PatternSyntax syntax)
845 // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
847 if (syntax == QRegExp::Wildcard)
848 pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\*\\?\\[\\]]")));
849 else if (syntax != QRegExp::FixedString)
850 pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
851 QString pathPrefix = path.left(pos); // == path if pos < 0
853 pathPrefix = pathPrefix.left(pathPrefix.lastIndexOf(QLatin1Char('/')));
855 // Special case - if the prefix ends up being nothing, use "." instead and
856 // chop off the first two characters from the glob'ed paths.
858 if (pathPrefix.trimmed().isEmpty()) {
859 if(path.startsWith(QLatin1Char('/'))) {
860 pathPrefix = path.left(path.indexOf(QRegExp(QLatin1String("[\\*\\?\\[]"))));
861 pathPrefix = path.left(path.lastIndexOf(QLatin1Char('/')));
864 pathPrefix = QLatin1String(".");
868 // The path is a file.
869 if (pos == -1 && QFileInfo(pathPrefix).isFile()) {
870 QFile file(pathPrefix);
871 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
872 return QSslCertificate::fromData(file.readAll(),format);
873 return QList<QSslCertificate>();
876 // The path can be a file or directory.
877 QList<QSslCertificate> certs;
878 QRegExp pattern(path, Qt::CaseSensitive, syntax);
879 QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
880 while (it.hasNext()) {
881 QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
882 if (!pattern.exactMatch(filePath))
885 QFile file(filePath);
886 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
887 certs += QSslCertificate::fromData(file.readAll(),format);
893 Searches for and parses all certificates in \a device that are
894 encoded in the specified \a format and returns them in a list of
899 QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
902 qWarning("QSslCertificate::fromDevice: cannot read from a null device");
903 return QList<QSslCertificate>();
905 return fromData(device->readAll(), format);
909 Searches for and parses all certificates in \a data that are
910 encoded in the specified \a format and returns them in a list of
915 QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
917 return (format == QSsl::Pem)
918 ? QSslCertificatePrivate::certificatesFromPem(data)
919 : QSslCertificatePrivate::certificatesFromDer(data);
923 Verifies a certificate chain. The chain to be verified is passed in the
924 \a certificateChain parameter. The first certificate in the list should
925 be the leaf certificate of the chain to be verified. If \a hostName is
926 specified then the certificate is also checked to see if it is valid for
927 the specified host name.
929 Note that the root (CA) certificate should not be included in the list to be verified,
930 this will be looked up automatically either using the CA list specified by
931 QSslSocket::defaultCaCertificates() or, if possible, it will be loaded on demand
936 QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
938 return QSslSocketBackendPrivate::verify(certificateChain, hostName);
941 void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
943 if (!data.isEmpty()) {
944 QList<QSslCertificate> certs = (format == QSsl::Pem)
945 ? certificatesFromPem(data, 1)
946 : certificatesFromDer(data, 1);
947 if (!certs.isEmpty()) {
948 *this = *certs.first().d;
950 x509 = q_X509_dup(x509);
955 #define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
956 #define ENDCERTSTRING "-----END CERTIFICATE-----"
958 // ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
959 QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
962 qWarning("QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
966 // Use i2d_X509 to convert the X509 to an array.
967 int length = q_i2d_X509(x509, 0);
969 array.resize(length);
970 char *data = array.data();
971 char **dataP = &data;
972 unsigned char **dataPu = (unsigned char **)dataP;
973 if (q_i2d_X509(x509, dataPu) < 0)
976 if (format == QSsl::Der)
979 // Convert to Base64 - wrap at 64 characters.
980 array = array.toBase64();
982 for (int i = 0; i <= array.size() - 64; i += 64) {
983 tmp += QByteArray::fromRawData(array.data() + i, 64);
986 if (int remainder = array.size() % 64) {
987 tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
991 return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
994 QByteArray QSslCertificatePrivate::text_from_X509(X509 *x509)
997 qWarning("QSslSocketBackendPrivate::text_from_X509: null X509");
1002 BIO *bio = q_BIO_new(q_BIO_s_mem());
1006 q_X509_print(bio, x509);
1008 QVarLengthArray<char, 16384> data;
1009 int count = q_BIO_read(bio, data.data(), 16384);
1011 result = QByteArray( data.data(), count );
1019 QByteArray QSslCertificatePrivate::asn1ObjectId(ASN1_OBJECT *object)
1021 char buf[80]; // The openssl docs a buffer length of 80 should be more than enough
1022 q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
1024 return QByteArray(buf);
1028 QByteArray QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object)
1030 int nid = q_OBJ_obj2nid(object);
1031 if (nid != NID_undef)
1032 return QByteArray(q_OBJ_nid2sn(nid));
1034 return asn1ObjectId(object);
1037 static QMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
1039 QMap<QByteArray, QString> info;
1040 for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
1041 X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
1043 QByteArray name = QSslCertificatePrivate::asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
1044 unsigned char *data = 0;
1045 int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
1046 info.insertMulti(name, QString::fromUtf8((char*)data, size));
1047 q_CRYPTO_free(data);
1053 QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
1055 QSslCertificate certificate;
1056 if (!x509 || !QSslSocket::supportsSsl())
1059 ASN1_TIME *nbef = q_X509_get_notBefore(x509);
1060 ASN1_TIME *naft = q_X509_get_notAfter(x509);
1061 certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
1062 certificate.d->notValidAfter = q_getTimeFromASN1(naft);
1063 certificate.d->null = false;
1064 certificate.d->x509 = q_X509_dup(x509);
1069 static bool matchLineFeed(const QByteArray &pem, int *offset)
1073 // ignore extra whitespace at the end of the line
1074 while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
1081 if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
1088 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
1090 QList<QSslCertificate> certificates;
1091 QSslSocketPrivate::ensureInitialized();
1094 while (count == -1 || certificates.size() < count) {
1095 int startPos = pem.indexOf(BEGINCERTSTRING, offset);
1098 startPos += sizeof(BEGINCERTSTRING) - 1;
1099 if (!matchLineFeed(pem, &startPos))
1102 int endPos = pem.indexOf(ENDCERTSTRING, startPos);
1106 offset = endPos + sizeof(ENDCERTSTRING) - 1;
1107 if (offset < pem.size() && !matchLineFeed(pem, &offset))
1110 QByteArray decoded = QByteArray::fromBase64(
1111 QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
1112 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
1113 const unsigned char *data = (const unsigned char *)decoded.data();
1115 unsigned char *data = (unsigned char *)decoded.data();
1118 if (X509 *x509 = q_d2i_X509(0, &data, decoded.size())) {
1119 certificates << QSslCertificate_from_X509(x509);
1124 return certificates;
1127 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
1129 QList<QSslCertificate> certificates;
1130 QSslSocketPrivate::ensureInitialized();
1133 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
1134 const unsigned char *data = (const unsigned char *)der.data();
1136 unsigned char *data = (unsigned char *)der.data();
1138 int size = der.size();
1140 while (count == -1 || certificates.size() < count) {
1141 if (X509 *x509 = q_d2i_X509(0, &data, size)) {
1142 certificates << QSslCertificate_from_X509(x509);
1147 size -= ((char *)data - der.data());
1150 return certificates;
1153 // These certificates are known to be fraudulent and were created during the comodo
1154 // compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
1155 static const char *certificate_blacklist[] = {
1156 "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo
1157 "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo
1158 "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo
1159 "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", "login.yahoo.com", // Comodo
1160 "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", "login.yahoo.com", // Comodo
1161 "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", "login.skype.com", // Comodo
1162 "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", "addons.mozilla.org", // Comodo
1163 "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", "login.live.com", // Comodo
1164 "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", "global trustee", // Comodo
1166 "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", "*.google.com", // leaf certificate issued by DigiNotar
1167 "0c:76:da:9c:91:0c:4e:2c:9e:fe:15:d0:58:93:3c:4c", "DigiNotar Root CA", // DigiNotar root
1168 "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
1169 "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
1170 "0a:82:bd:1e:14:4e:88:14:d7:5b:1a:55:27:be:bf:3e", "DigiNotar Root CA G2", // other DigiNotar Root CA
1171 "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"
1172 "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
1174 "46:9c:2c:b0", "DigiNotar Services 1024 CA", // DigiNotar intermediate cross-signed by Entrust
1175 "07:27:10:0d", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
1176 "07:27:0f:f9", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
1177 "07:27:10:03", "DigiNotar Cyber CA", // DigiNotar intermediate cross-signed by CyberTrust
1178 "01:31:69:b0", "DigiNotar PKIoverheid CA Overheid en Bedrijven", // DigiNotar intermediate cross-signed by the Dutch government
1179 "01:31:34:bf", "DigiNotar PKIoverheid CA Organisatie - G2", // DigiNotar intermediate cross-signed by the Dutch government
1180 "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
1181 "1e:7d:7a:53:3d:45:30:41:96:40:0f:71:48:1f:45:04", "DigiNotar Public CA 2025", // DigiNotar intermediate
1182 // "(has not been seen in the wild so far)", "DigiNotar Public CA - G2", // DigiNotar intermediate
1183 // "(has not been seen in the wild so far)", "Koninklijke Notariele Beroepsorganisatie CA", // compromised during DigiNotar breach
1184 // "(has not been seen in the wild so far)", "Stichting TTP Infos CA," // compromised during DigiNotar breach
1185 "46:9c:2c:af", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
1186 "46:9c:3c:c9", "DigiNotar Root CA", // DigiNotar intermediate cross-signed by Entrust
1188 "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust
1189 "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust
1190 "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate
1191 "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/
1195 bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
1197 for (int a = 0; certificate_blacklist[a] != 0; a++) {
1198 QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);
1199 if (certificate.serialNumber() == certificate_blacklist[a++] &&
1200 (certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
1201 certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
1207 #ifndef QT_NO_DEBUG_STREAM
1208 QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
1210 debug << "QSslCertificate("
1211 << certificate.version()
1212 << ',' << certificate.serialNumber()
1213 << ',' << certificate.digest().toBase64()
1214 << ',' << certificate.issuerInfo(QSslCertificate::Organization)
1215 << ',' << certificate.subjectInfo(QSslCertificate::Organization)
1216 << ',' << certificate.subjectAlternativeNames()
1217 #ifndef QT_NO_DATESTRING
1218 << ',' << certificate.effectiveDate()
1219 << ',' << certificate.expiryDate()
1224 QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
1227 case QSslCertificate::Organization: debug << "Organization"; break;
1228 case QSslCertificate::CommonName: debug << "CommonName"; break;
1229 case QSslCertificate::CountryName: debug << "CountryName"; break;
1230 case QSslCertificate::LocalityName: debug << "LocalityName"; break;
1231 case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
1232 case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
1233 case QSslCertificate::DistinguishedNameQualifier: debug << "DistinguishedNameQualifier"; break;
1234 case QSslCertificate::SerialNumber: debug << "SerialNumber"; break;
1235 case QSslCertificate::EmailAddress: debug << "EmailAddress"; break;