src/network/ssl/qsslcertificate.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtNetwork module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 /*!
       
    44     \class QSslCertificate
       
    45     \brief The QSslCertificate class provides a convenient API for an X509 certificate.
       
    46     \since 4.3
       
    47 
       
    48     \reentrant
       
    49     \ingroup network
       
    50     \ingroup ssl
       
    51     \inmodule QtNetwork
       
    52 
       
    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
       
    56     Authority.
       
    57 
       
    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.
       
    64 
       
    65     You can call isNull() to check if your certificate is null. By
       
    66     default, QSslCertificate constructs a null certificate. To check
       
    67     if the certificate is valid, call isValid(). A null certificate is
       
    68     invalid, but an invalid certificate is not necessarily null. If
       
    69     you want to reset all contents in a certificate, call clear().
       
    70 
       
    71     After loading a certificate, you can find information about the
       
    72     certificate, its subject, and its issuer, by calling one of the
       
    73     many accessor functions, including version(), serialNumber(),
       
    74     issuerInfo() and subjectInfo(). You can call effectiveDate() and
       
    75     expiryDate() to check when the certificate starts being
       
    76     effective and when it expires.
       
    77     The publicKey() function returns the certificate
       
    78     subject's public key as a QSslKey. You can call issuerInfo() or
       
    79     subjectInfo() to get detailed information about the certificate
       
    80     issuer and its subject.
       
    81 
       
    82     Internally, QSslCertificate is stored as an X509 structure. You
       
    83     can access this handle by calling handle(), but the results are
       
    84     likely to not be portable.
       
    85 
       
    86     \sa QSslSocket, QSslKey, QSslCipher, QSslError
       
    87 */
       
    88 
       
    89 /*!
       
    90     \enum QSslCertificate::SubjectInfo
       
    91 
       
    92     Describes keys that you can pass to QSslCertificate::issuerInfo() or
       
    93     QSslCertificate::subjectInfo() to get information about the certificate
       
    94     issuer or subject.
       
    95 
       
    96     \value Organization "O" The name of the organization.
       
    97 
       
    98     \value CommonName "CN" The common name; most often this is used to store
       
    99     the host name.
       
   100 
       
   101     \value LocalityName "L" The locality.
       
   102 
       
   103     \value OrganizationalUnitName "OU" The organizational unit name.
       
   104 
       
   105     \value CountryName "C" The country.
       
   106 
       
   107     \value StateOrProvinceName "ST" The state or province.
       
   108 */
       
   109 
       
   110 #include "qsslsocket_openssl_symbols_p.h"
       
   111 #include "qsslcertificate.h"
       
   112 #include "qsslcertificate_p.h"
       
   113 #include "qsslkey.h"
       
   114 #include "qsslkey_p.h"
       
   115 
       
   116 #include <QtCore/qatomic.h>
       
   117 #include <QtCore/qdatetime.h>
       
   118 #include <QtCore/qdebug.h>
       
   119 #include <QtCore/qdir.h>
       
   120 #include <QtCore/qdiriterator.h>
       
   121 #include <QtCore/qfile.h>
       
   122 #include <QtCore/qfileinfo.h>
       
   123 #include <QtCore/qmap.h>
       
   124 #include <QtCore/qstring.h>
       
   125 #include <QtCore/qstringlist.h>
       
   126 
       
   127 QT_BEGIN_NAMESPACE
       
   128 
       
   129 // forward declaration
       
   130 static QMap<QString, QString> _q_mapFromOnelineName(char *name);
       
   131 
       
   132 /*!
       
   133     Constructs a QSslCertificate by reading \a format encoded data
       
   134     from \a device and using the first certificate found. You can
       
   135     later call isNull() to see if \a device contained a certificate,
       
   136     and if this certificate was loaded successfully.
       
   137 */
       
   138 QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
       
   139     : d(new QSslCertificatePrivate)
       
   140 {
       
   141     QSslSocketPrivate::ensureInitialized();
       
   142     if (device)
       
   143         d->init(device->readAll(), format);
       
   144 }
       
   145 
       
   146 /*!
       
   147     Constructs a QSslCertificate by parsing the \a format encoded
       
   148     \a data and using the first available certificate found. You can
       
   149     later call isNull() to see if \a data contained a certificate,
       
   150     and if this certificate was loaded successfully.
       
   151 */
       
   152 QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
       
   153     : d(new QSslCertificatePrivate)
       
   154 {
       
   155     QSslSocketPrivate::ensureInitialized();
       
   156     d->init(data, format);
       
   157 }
       
   158 
       
   159 /*!
       
   160     Constructs an identical copy of \a other.
       
   161 */
       
   162 QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
       
   163 {
       
   164 }
       
   165 
       
   166 /*!
       
   167     Destroys the QSslCertificate.
       
   168 */
       
   169 QSslCertificate::~QSslCertificate()
       
   170 {
       
   171 }
       
   172 
       
   173 /*!
       
   174     Copies the contents of \a other into this certificate, making the two
       
   175     certificates identical.
       
   176 */
       
   177 QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
       
   178 {
       
   179     d = other.d;
       
   180     return *this;
       
   181 }
       
   182 
       
   183 /*!
       
   184     Returns true if this certificate is the same as \a other; otherwise
       
   185     returns false.
       
   186 */
       
   187 bool QSslCertificate::operator==(const QSslCertificate &other) const
       
   188 {
       
   189     if (d == other.d)
       
   190         return true;
       
   191     if (d->null && other.d->null)
       
   192         return true;
       
   193     if (d->x509 && other.d->x509)
       
   194         return q_X509_cmp(d->x509, other.d->x509) == 0;
       
   195     return false;
       
   196 }
       
   197 
       
   198 /*!
       
   199     \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
       
   200 
       
   201     Returns true if this certificate is not the same as \a other; otherwise
       
   202     returns false.
       
   203 */
       
   204 
       
   205 /*!
       
   206     Returns true if this is a null certificate (i.e., a certificate
       
   207     with no contents); otherwise returns false.
       
   208 
       
   209     By default, QSslCertificate constructs a null certificate.
       
   210 
       
   211     \sa isValid(), clear()
       
   212 */
       
   213 bool QSslCertificate::isNull() const
       
   214 {
       
   215     return d->null;
       
   216 }
       
   217 
       
   218 /*!
       
   219     Returns true if this certificate is valid; otherwise returns
       
   220     false.
       
   221 
       
   222     Note: Currently, this function only checks that the current
       
   223     data-time is within the date-time range during which the
       
   224     certificate is considered valid. No other checks are
       
   225     currently performed.
       
   226 
       
   227     \sa isNull()
       
   228 */
       
   229 bool QSslCertificate::isValid() const
       
   230 {
       
   231     const QDateTime currentTime = QDateTime::currentDateTime();
       
   232     return currentTime >= d->notValidBefore && currentTime <= d->notValidAfter;
       
   233 }
       
   234 
       
   235 /*!
       
   236     Clears the contents of this certificate, making it a null
       
   237     certificate.
       
   238 
       
   239     \sa isNull()
       
   240 */
       
   241 void QSslCertificate::clear()
       
   242 {
       
   243     if (isNull())
       
   244         return;
       
   245     d = new QSslCertificatePrivate;
       
   246 }
       
   247 
       
   248 /*!
       
   249     Returns the certificate's version string.
       
   250 */
       
   251 QByteArray QSslCertificate::version() const
       
   252 {
       
   253     if (d->versionString.isEmpty() && d->x509)
       
   254         d->versionString =
       
   255             QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1);
       
   256 
       
   257     return d->versionString;
       
   258 }
       
   259 
       
   260 /*!
       
   261     Returns the certificate's serial number string in decimal format.
       
   262 */
       
   263 QByteArray QSslCertificate::serialNumber() const
       
   264 {
       
   265     if (d->serialNumberString.isEmpty() && d->x509)
       
   266         d->serialNumberString =
       
   267             QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->serialNumber)));
       
   268 
       
   269     return d->serialNumberString;
       
   270 }
       
   271 
       
   272 /*!
       
   273     Returns a cryptographic digest of this certificate. By default,
       
   274     an MD5 digest will be generated, but you can also specify a
       
   275     custom \a algorithm.
       
   276 */
       
   277 QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
       
   278 {
       
   279     return QCryptographicHash::hash(toDer(), algorithm);
       
   280 }
       
   281 
       
   282 static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info)
       
   283 {
       
   284     QString str;
       
   285     switch (info) {
       
   286     case QSslCertificate::Organization: str = QLatin1String("O"); break;
       
   287     case QSslCertificate::CommonName: str = QLatin1String("CN"); break;
       
   288     case QSslCertificate::LocalityName: str = QLatin1String("L"); break;
       
   289     case QSslCertificate::OrganizationalUnitName: str = QLatin1String("OU"); break;
       
   290     case QSslCertificate::CountryName: str = QLatin1String("C"); break;
       
   291     case QSslCertificate::StateOrProvinceName: str = QLatin1String("ST"); break;
       
   292     }
       
   293     return str;
       
   294 }
       
   295 
       
   296 /*!
       
   297   \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
       
   298   
       
   299   Returns the issuer information for the \a subject from the
       
   300   certificate, or an empty string if there is no information for
       
   301   \a subject in the certificate.
       
   302 
       
   303   \sa subjectInfo()
       
   304 */
       
   305 QString QSslCertificate::issuerInfo(SubjectInfo info) const
       
   306 {
       
   307     if (d->issuerInfo.isEmpty() && d->x509)
       
   308         d->issuerInfo =
       
   309                 _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_issuer_name(d->x509), 0, 0));
       
   310 
       
   311     return d->issuerInfo.value(_q_SubjectInfoToString(info));
       
   312 }
       
   313 
       
   314 /*!
       
   315   Returns the issuer information for \a tag from the certificate,
       
   316   or an empty string if there is no information for \a tag in the
       
   317   certificate.
       
   318 
       
   319   \sa subjectInfo()
       
   320 */
       
   321 QString QSslCertificate::issuerInfo(const QByteArray &tag) const
       
   322 {
       
   323     // ### Use a QByteArray for the keys in the map
       
   324     return d->issuerInfo.value(QString::fromLatin1(tag));
       
   325 }
       
   326 
       
   327 /*!
       
   328 
       
   329   \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
       
   330 
       
   331   Returns the information for the \a subject, or an empty string if
       
   332   there is no information for \a subject in the certificate.
       
   333 
       
   334     \sa issuerInfo()
       
   335 */
       
   336 QString QSslCertificate::subjectInfo(SubjectInfo info) const
       
   337 {
       
   338     if (d->subjectInfo.isEmpty() && d->x509)
       
   339         d->subjectInfo =
       
   340                 _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_subject_name(d->x509), 0, 0));
       
   341 
       
   342     return d->subjectInfo.value(_q_SubjectInfoToString(info));
       
   343 }
       
   344 
       
   345 /*!
       
   346     Returns the subject information for \a tag, or an empty string if
       
   347     there is no information for \a tag in the certificate.
       
   348 
       
   349     \sa issuerInfo()
       
   350 */
       
   351 QString QSslCertificate::subjectInfo(const QByteArray &tag) const
       
   352 {
       
   353     // ### Use a QByteArray for the keys in the map
       
   354     return d->subjectInfo.value(QString::fromLatin1(tag));
       
   355 }
       
   356 
       
   357 /*!
       
   358   Returns the list of alternative subject names for this
       
   359   certificate. The alternate subject names typically contain host
       
   360   names, optionally with wildcards, that are valid for this
       
   361   certificate.
       
   362   
       
   363   These names are tested against the connected peer's host name, if
       
   364   either the subject information for \l CommonName doesn't define a
       
   365   valid host name, or the subject info name doesn't match the peer's
       
   366   host name.
       
   367   
       
   368   \sa subjectInfo()
       
   369 */
       
   370 QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
       
   371 {
       
   372     QMultiMap<QSsl::AlternateNameEntryType, QString> result;
       
   373 
       
   374     if (!d->x509)
       
   375         return result;
       
   376 
       
   377     STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME)*)q_X509_get_ext_d2i(d->x509, NID_subject_alt_name, 0, 0);
       
   378 
       
   379     if (altNames) {
       
   380         for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
       
   381             const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
       
   382             if (genName->type != GEN_DNS && genName->type != GEN_EMAIL)
       
   383                 continue;
       
   384 
       
   385             int len = q_ASN1_STRING_length(genName->d.ia5);
       
   386             if (len < 0 || len >= 8192) {
       
   387                 // broken name
       
   388                 continue;
       
   389             }
       
   390 
       
   391             const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
       
   392             const QString altName = QString::fromLatin1(altNameStr, len);
       
   393             if (genName->type == GEN_DNS)
       
   394                 result.insert(QSsl::DnsEntry, altName);
       
   395             else if (genName->type == GEN_EMAIL)
       
   396                 result.insert(QSsl::EmailEntry, altName);
       
   397         }
       
   398         q_sk_pop_free((STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_sk_free));
       
   399     }
       
   400 
       
   401     return result;
       
   402 }
       
   403 
       
   404 /*!
       
   405   Returns the date-time that the certificate becomes valid, or an
       
   406   empty QDateTime if this is a null certificate.
       
   407 
       
   408   \sa expiryDate()
       
   409 */
       
   410 QDateTime QSslCertificate::effectiveDate() const
       
   411 {
       
   412     return d->notValidBefore;
       
   413 }
       
   414 
       
   415 /*!
       
   416   Returns the date-time that the certificate expires, or an empty
       
   417   QDateTime if this is a null certificate.
       
   418 
       
   419     \sa effectiveDate()
       
   420 */
       
   421 QDateTime QSslCertificate::expiryDate() const
       
   422 {
       
   423     return d->notValidAfter;
       
   424 }
       
   425 
       
   426 /*!
       
   427     Returns a pointer to the native certificate handle, if there is
       
   428     one, or a null pointer otherwise.
       
   429 
       
   430     You can use this handle, together with the native API, to access
       
   431     extended information about the certificate.
       
   432 
       
   433     \warning Use of this function has a high probability of being
       
   434     non-portable, and its return value may vary from platform to
       
   435     platform or change from minor release to minor release.
       
   436 */
       
   437 Qt::HANDLE QSslCertificate::handle() const
       
   438 {
       
   439     return Qt::HANDLE(d->x509);
       
   440 }
       
   441 
       
   442 /*!
       
   443     Returns the certificate subject's public key.
       
   444 */
       
   445 QSslKey QSslCertificate::publicKey() const
       
   446 {
       
   447     if (!d->x509)
       
   448         return QSslKey();
       
   449 
       
   450     QSslKey key;
       
   451 
       
   452     key.d->type = QSsl::PublicKey;
       
   453     X509_PUBKEY *xkey = d->x509->cert_info->key;
       
   454     EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
       
   455     Q_ASSERT(pkey);
       
   456 
       
   457     if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
       
   458         key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
       
   459         key.d->algorithm = QSsl::Rsa;
       
   460         key.d->isNull = false;
       
   461     } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
       
   462         key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
       
   463         key.d->algorithm = QSsl::Dsa;
       
   464         key.d->isNull = false;
       
   465     } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
       
   466         // DH unsupported
       
   467     } else {
       
   468         // error?
       
   469     }
       
   470 
       
   471     q_EVP_PKEY_free(pkey);
       
   472     return key;
       
   473 }
       
   474 
       
   475 /*!
       
   476     Returns this certificate converted to a PEM (Base64) encoded
       
   477     representation.
       
   478 */
       
   479 QByteArray QSslCertificate::toPem() const
       
   480 {
       
   481     if (!d->x509)
       
   482         return QByteArray();
       
   483     return d->QByteArray_from_X509(d->x509, QSsl::Pem);
       
   484 }
       
   485 
       
   486 /*!
       
   487     Returns this certificate converted to a DER (binary) encoded
       
   488     representation.
       
   489 */
       
   490 QByteArray QSslCertificate::toDer() const
       
   491 {
       
   492     if (!d->x509)
       
   493         return QByteArray();
       
   494     return d->QByteArray_from_X509(d->x509, QSsl::Der);
       
   495 }
       
   496 
       
   497 /*!
       
   498     Searches all files in the \a path for certificates encoded in the
       
   499     specified \a format and returns them in a list. \e must be a file or a
       
   500     pattern matching one or more files, as specified by \a syntax.
       
   501 
       
   502     Example:
       
   503     
       
   504     \snippet doc/src/snippets/code/src_network_ssl_qsslcertificate.cpp 0
       
   505 
       
   506     \sa fromData()
       
   507 */
       
   508 QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
       
   509                                                  QSsl::EncodingFormat format,
       
   510                                                  QRegExp::PatternSyntax syntax)
       
   511 {
       
   512     // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
       
   513     int pos = -1;
       
   514     if (syntax == QRegExp::Wildcard)
       
   515         pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\*\\?\\[\\]]")));
       
   516     else if (syntax != QRegExp::FixedString)
       
   517         pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
       
   518     QString pathPrefix = path.left(pos); // == path if pos < 0
       
   519     if (pos != -1)
       
   520         pathPrefix = pathPrefix.left(pathPrefix.lastIndexOf(QLatin1Char('/')));
       
   521 
       
   522     // Special case - if the prefix ends up being nothing, use "." instead and
       
   523     // chop off the first two characters from the glob'ed paths.
       
   524     int startIndex = 0;
       
   525     if (pathPrefix.trimmed().isEmpty()) {
       
   526         startIndex = 2;
       
   527         pathPrefix = QLatin1String(".");
       
   528     }
       
   529 
       
   530     // The path is a file.
       
   531     if (pos == -1 && QFileInfo(pathPrefix).isFile()) {
       
   532         QFile file(pathPrefix);
       
   533         if (file.open(QIODevice::ReadOnly | QIODevice::Text))
       
   534             return QSslCertificate::fromData(file.readAll(),format);
       
   535         return QList<QSslCertificate>();
       
   536     }
       
   537 
       
   538     // The path can be a file or directory.
       
   539     QList<QSslCertificate> certs;
       
   540     QRegExp pattern(path, Qt::CaseSensitive, syntax);
       
   541     QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
       
   542     while (it.hasNext()) {
       
   543         QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
       
   544         if (!pattern.exactMatch(filePath))
       
   545             continue;
       
   546 
       
   547         QFile file(filePath);
       
   548         if (file.open(QIODevice::ReadOnly | QIODevice::Text))
       
   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 */
       
   561 QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
       
   562 {
       
   563     if (!device) {
       
   564         qWarning("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 */
       
   577 QList<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 void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
       
   585 {
       
   586     if (!data.isEmpty()) {
       
   587         QList<QSslCertificate> certs = (format == QSsl::Pem)
       
   588             ? certificatesFromPem(data, 1)
       
   589             : certificatesFromDer(data, 1);
       
   590         if (!certs.isEmpty()) {
       
   591             *this = *certs.first().d;
       
   592             if (x509)
       
   593                 x509 = q_X509_dup(x509);
       
   594         }
       
   595     }
       
   596 }
       
   597 
       
   598 #define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
       
   599 #define ENDCERTSTRING "-----END CERTIFICATE-----"
       
   600 
       
   601 // ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
       
   602 QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
       
   603 {
       
   604     if (!x509) {
       
   605         qWarning("QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
       
   606         return QByteArray();
       
   607     }
       
   608 
       
   609     // Use i2d_X509 to convert the X509 to an array.
       
   610     int length = q_i2d_X509(x509, 0);
       
   611     QByteArray array;
       
   612     array.resize(length);
       
   613     char *data = array.data();
       
   614     char **dataP = &data;
       
   615     unsigned char **dataPu = (unsigned char **)dataP;
       
   616     if (q_i2d_X509(x509, dataPu) < 0)
       
   617         return QByteArray();
       
   618 
       
   619     if (format == QSsl::Der)
       
   620         return array;
       
   621 
       
   622     // Convert to Base64 - wrap at 64 characters.
       
   623     array = array.toBase64();
       
   624     QByteArray tmp;
       
   625     for (int i = 0; i <= array.size() - 64; i += 64) {
       
   626         tmp += QByteArray::fromRawData(array.data() + i, 64);
       
   627         tmp += "\n";
       
   628     }
       
   629     if (int remainder = array.size() % 64) {
       
   630         tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
       
   631         tmp += "\n";
       
   632     }
       
   633 
       
   634     return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
       
   635 }
       
   636 
       
   637 static QMap<QString, QString> _q_mapFromOnelineName(char *name)
       
   638 {
       
   639     QMap<QString, QString> info;
       
   640     QString infoStr = QString::fromLocal8Bit(name);
       
   641     q_CRYPTO_free(name);
       
   642 
       
   643     // ### The right-hand encoding seems to allow hex (Regulierungsbeh\xC8orde)
       
   644     //entry.replace(QLatin1String("\\x"), QLatin1String("%"));
       
   645     //entry = QUrl::fromPercentEncoding(entry.toLatin1());
       
   646     // ### See RFC-4630 for more details!
       
   647 
       
   648     QRegExp rx(QLatin1String("/([A-Za-z]+)=(.+)"));
       
   649 
       
   650     int pos = 0;
       
   651     while ((pos = rx.indexIn(infoStr, pos)) != -1) {
       
   652         const QString name = rx.cap(1);
       
   653 
       
   654         QString value = rx.cap(2);
       
   655         const int valuePos = rx.pos(2);
       
   656 
       
   657         const int next = rx.indexIn(value);
       
   658         if (next == -1) {
       
   659             info.insert(name, value);
       
   660             break;
       
   661         }
       
   662 
       
   663         value = value.left(next);
       
   664         info.insert(name, value);
       
   665         pos = valuePos + value.length();
       
   666     }
       
   667 
       
   668     return info;
       
   669 }
       
   670 
       
   671 QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
       
   672 {
       
   673     QSslCertificate certificate;
       
   674     if (!x509 || !QSslSocket::supportsSsl())
       
   675         return certificate;
       
   676 
       
   677     ASN1_TIME *nbef = q_X509_get_notBefore(x509);
       
   678     ASN1_TIME *naft = q_X509_get_notAfter(x509);
       
   679     certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
       
   680     certificate.d->notValidAfter = q_getTimeFromASN1(naft);
       
   681     certificate.d->null = false;
       
   682     certificate.d->x509 = q_X509_dup(x509);
       
   683 
       
   684     return certificate;
       
   685 }
       
   686 
       
   687 static bool matchLineFeed(const QByteArray &pem, int *offset)
       
   688 {
       
   689     char ch = pem.at(*offset);
       
   690 
       
   691     // ignore extra whitespace at the end of the line
       
   692     while (ch == ' ' && *offset < pem.size())
       
   693         ch = pem.at(++*offset);
       
   694 
       
   695     if (ch == '\n') {
       
   696         *offset += 1;
       
   697         return true;
       
   698     }
       
   699     if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
       
   700         *offset += 2;
       
   701         return true;
       
   702     }
       
   703     return false;
       
   704 }
       
   705 
       
   706 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
       
   707 {
       
   708     QList<QSslCertificate> certificates;
       
   709     QSslSocketPrivate::ensureInitialized();
       
   710 
       
   711     int offset = 0;
       
   712     while (count == -1 || certificates.size() < count) {
       
   713         int startPos = pem.indexOf(BEGINCERTSTRING, offset);
       
   714         if (startPos == -1)
       
   715             break;
       
   716         startPos += sizeof(BEGINCERTSTRING) - 1;
       
   717         if (!matchLineFeed(pem, &startPos))
       
   718             break;
       
   719 
       
   720         int endPos = pem.indexOf(ENDCERTSTRING, startPos);
       
   721         if (endPos == -1)
       
   722             break;
       
   723 
       
   724         offset = endPos + sizeof(ENDCERTSTRING) - 1;
       
   725         if (!matchLineFeed(pem, &offset))
       
   726             break;
       
   727 
       
   728         QByteArray decoded = QByteArray::fromBase64(
       
   729             QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
       
   730 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
       
   731         const unsigned char *data = (const unsigned char *)decoded.data();
       
   732 #else
       
   733         unsigned char *data = (unsigned char *)decoded.data();
       
   734 #endif
       
   735 
       
   736         if (X509 *x509 = q_d2i_X509(0, &data, decoded.size())) {
       
   737             certificates << QSslCertificate_from_X509(x509);
       
   738             q_X509_free(x509);
       
   739         }
       
   740     }
       
   741 
       
   742     return certificates;
       
   743 }
       
   744 
       
   745 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
       
   746 {
       
   747     QList<QSslCertificate> certificates;
       
   748     QSslSocketPrivate::ensureInitialized();
       
   749 
       
   750 
       
   751 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
       
   752         const unsigned char *data = (const unsigned char *)der.data();
       
   753 #else
       
   754         unsigned char *data = (unsigned char *)der.data();
       
   755 #endif
       
   756     int size = der.size();
       
   757 
       
   758     while (count == -1 || certificates.size() < count) {
       
   759         if (X509 *x509 = q_d2i_X509(0, &data, size)) {
       
   760             certificates << QSslCertificate_from_X509(x509);
       
   761             q_X509_free(x509);
       
   762         } else {
       
   763             break;
       
   764         }
       
   765         size -= ((char *)data - der.data());
       
   766     }
       
   767 
       
   768     return certificates;
       
   769 }
       
   770 
       
   771 #ifndef QT_NO_DEBUG_STREAM
       
   772 QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
       
   773 {
       
   774     debug << "QSslCertificate("
       
   775           << certificate.version()
       
   776           << ',' << certificate.serialNumber()
       
   777           << ',' << certificate.digest().toBase64()
       
   778           << ',' << certificate.issuerInfo(QSslCertificate::Organization)
       
   779           << ',' << certificate.subjectInfo(QSslCertificate::Organization)
       
   780           << ',' << certificate.alternateSubjectNames()
       
   781 #ifndef QT_NO_TEXTSTREAM
       
   782           << ',' << certificate.effectiveDate()
       
   783           << ',' << certificate.expiryDate()
       
   784 #endif
       
   785           << ')';
       
   786     return debug;
       
   787 }
       
   788 QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
       
   789 {
       
   790     switch (info) {
       
   791     case QSslCertificate::Organization: debug << "Organization"; break;
       
   792     case QSslCertificate::CommonName: debug << "CommonName"; break;
       
   793     case QSslCertificate::CountryName: debug << "CountryName"; break;
       
   794     case QSslCertificate::LocalityName: debug << "LocalityName"; break;
       
   795     case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
       
   796     case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
       
   797     }
       
   798     return debug;
       
   799 }
       
   800 #endif
       
   801 
       
   802 QT_END_NAMESPACE