76b7d41e46a86ed5902514008bc22347f8982461
[profile/ivi/qtbase.git] / src / network / ssl / qsslcertificate.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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_mapFromX509Name(X509_NAME *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 checks that the current
223     data-time is within the date-time range during which the
224     certificate is considered valid, and checks that the
225     certificate is not in a blacklist of fraudulent certificates.
226
227     \sa isNull()
228 */
229 bool QSslCertificate::isValid() const
230 {
231     const QDateTime currentTime = QDateTime::currentDateTime();
232     return currentTime >= d->notValidBefore &&
233             currentTime <= d->notValidAfter &&
234             ! QSslCertificatePrivate::isBlacklisted(*this);
235 }
236
237 /*!
238     Clears the contents of this certificate, making it a null
239     certificate.
240
241     \sa isNull()
242 */
243 void QSslCertificate::clear()
244 {
245     if (isNull())
246         return;
247     d = new QSslCertificatePrivate;
248 }
249
250 /*!
251     Returns the certificate's version string.
252 */
253 QByteArray QSslCertificate::version() const
254 {
255     if (d->versionString.isEmpty() && d->x509)
256         d->versionString =
257             QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1);
258
259     return d->versionString;
260 }
261
262 /*!
263     Returns the certificate's serial number string in decimal format.
264     In case the serial number cannot be converted to decimal format
265     (i.e. if it is bigger than 4294967295, which means it does not fit into 4 bytes),
266     its hexadecimal version is returned.
267 */
268 QByteArray QSslCertificate::serialNumber() const
269 {
270     if (d->serialNumberString.isEmpty() && d->x509) {
271         ASN1_INTEGER *serialNumber = d->x509->cert_info->serialNumber;
272         // if we cannot convert to a long, just output the hexadecimal number
273         if (serialNumber->length > 4) {
274             QByteArray hexString;
275             hexString.reserve(serialNumber->length * 3);
276             for (int a = 0; a < serialNumber->length; ++a) {
277                 hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
278                 hexString += ':';
279             }
280             hexString.chop(1);
281             d->serialNumberString = hexString;
282         } else {
283             d->serialNumberString = QByteArray::number(qlonglong(q_ASN1_INTEGER_get(serialNumber)));
284         }
285     }
286     return d->serialNumberString;
287 }
288
289 /*!
290     Returns a cryptographic digest of this certificate. By default,
291     an MD5 digest will be generated, but you can also specify a
292     custom \a algorithm.
293 */
294 QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
295 {
296     return QCryptographicHash::hash(toDer(), algorithm);
297 }
298
299 static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info)
300 {
301     QString str;
302     switch (info) {
303     case QSslCertificate::Organization: str = QLatin1String("O"); break;
304     case QSslCertificate::CommonName: str = QLatin1String("CN"); break;
305     case QSslCertificate::LocalityName: str = QLatin1String("L"); break;
306     case QSslCertificate::OrganizationalUnitName: str = QLatin1String("OU"); break;
307     case QSslCertificate::CountryName: str = QLatin1String("C"); break;
308     case QSslCertificate::StateOrProvinceName: str = QLatin1String("ST"); break;
309     }
310     return str;
311 }
312
313 /*!
314   \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
315   
316   Returns the issuer information for the \a subject from the
317   certificate, or an empty string if there is no information for
318   \a subject in the certificate.
319
320   \sa subjectInfo()
321 */
322 QString QSslCertificate::issuerInfo(SubjectInfo info) const
323 {
324     // lazy init
325     if (d->issuerInfo.isEmpty() && d->x509)
326         d->issuerInfo =
327                 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
328
329     return d->issuerInfo.value(_q_SubjectInfoToString(info));
330 }
331
332 /*!
333   Returns the issuer information for \a tag from the certificate,
334   or an empty string if there is no information for \a tag in the
335   certificate.
336
337   \sa subjectInfo()
338 */
339 QString QSslCertificate::issuerInfo(const QByteArray &tag) const
340 {
341     // lazy init
342     if (d->issuerInfo.isEmpty() && d->x509)
343         d->issuerInfo =
344                 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
345
346     return d->issuerInfo.value(QString::fromLatin1(tag));
347 }
348
349 /*!
350
351   \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
352
353   Returns the information for the \a subject, or an empty string if
354   there is no information for \a subject in the certificate.
355
356     \sa issuerInfo()
357 */
358 QString QSslCertificate::subjectInfo(SubjectInfo info) const
359 {
360     // lazy init
361     if (d->subjectInfo.isEmpty() && d->x509)
362         d->subjectInfo =
363                 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
364
365     return d->subjectInfo.value(_q_SubjectInfoToString(info));
366 }
367
368 /*!
369     Returns the subject information for \a tag, or an empty string if
370     there is no information for \a tag in the certificate.
371
372     \sa issuerInfo()
373 */
374 QString QSslCertificate::subjectInfo(const QByteArray &tag) const
375 {
376     // lazy init
377     if (d->subjectInfo.isEmpty() && d->x509)
378         d->subjectInfo =
379                 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
380
381     return d->subjectInfo.value(QString::fromLatin1(tag));
382 }
383
384 /*!
385   Returns the list of alternative subject names for this
386   certificate. The alternate subject names typically contain host
387   names, optionally with wildcards, that are valid for this
388   certificate.
389   
390   These names are tested against the connected peer's host name, if
391   either the subject information for \l CommonName doesn't define a
392   valid host name, or the subject info name doesn't match the peer's
393   host name.
394   
395   \sa subjectInfo()
396 */
397 QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
398 {
399     QMultiMap<QSsl::AlternateNameEntryType, QString> result;
400
401     if (!d->x509)
402         return result;
403
404     STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME)*)q_X509_get_ext_d2i(d->x509, NID_subject_alt_name, 0, 0);
405
406     if (altNames) {
407         for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
408             const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
409             if (genName->type != GEN_DNS && genName->type != GEN_EMAIL)
410                 continue;
411
412             int len = q_ASN1_STRING_length(genName->d.ia5);
413             if (len < 0 || len >= 8192) {
414                 // broken name
415                 continue;
416             }
417
418             const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
419             const QString altName = QString::fromLatin1(altNameStr, len);
420             if (genName->type == GEN_DNS)
421                 result.insert(QSsl::DnsEntry, altName);
422             else if (genName->type == GEN_EMAIL)
423                 result.insert(QSsl::EmailEntry, altName);
424         }
425         q_sk_pop_free((STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_sk_free));
426     }
427
428     return result;
429 }
430
431 /*!
432   Returns the date-time that the certificate becomes valid, or an
433   empty QDateTime if this is a null certificate.
434
435   \sa expiryDate()
436 */
437 QDateTime QSslCertificate::effectiveDate() const
438 {
439     return d->notValidBefore;
440 }
441
442 /*!
443   Returns the date-time that the certificate expires, or an empty
444   QDateTime if this is a null certificate.
445
446     \sa effectiveDate()
447 */
448 QDateTime QSslCertificate::expiryDate() const
449 {
450     return d->notValidAfter;
451 }
452
453 /*!
454     Returns a pointer to the native certificate handle, if there is
455     one, or a null pointer otherwise.
456
457     You can use this handle, together with the native API, to access
458     extended information about the certificate.
459
460     \warning Use of this function has a high probability of being
461     non-portable, and its return value may vary from platform to
462     platform or change from minor release to minor release.
463 */
464 Qt::HANDLE QSslCertificate::handle() const
465 {
466     return Qt::HANDLE(d->x509);
467 }
468
469 /*!
470     Returns the certificate subject's public key.
471 */
472 QSslKey QSslCertificate::publicKey() const
473 {
474     if (!d->x509)
475         return QSslKey();
476
477     QSslKey key;
478
479     key.d->type = QSsl::PublicKey;
480     X509_PUBKEY *xkey = d->x509->cert_info->key;
481     EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
482     Q_ASSERT(pkey);
483
484     if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
485         key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
486         key.d->algorithm = QSsl::Rsa;
487         key.d->isNull = false;
488     } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
489         key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
490         key.d->algorithm = QSsl::Dsa;
491         key.d->isNull = false;
492     } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
493         // DH unsupported
494     } else {
495         // error?
496     }
497
498     q_EVP_PKEY_free(pkey);
499     return key;
500 }
501
502 /*!
503     Returns this certificate converted to a PEM (Base64) encoded
504     representation.
505 */
506 QByteArray QSslCertificate::toPem() const
507 {
508     if (!d->x509)
509         return QByteArray();
510     return d->QByteArray_from_X509(d->x509, QSsl::Pem);
511 }
512
513 /*!
514     Returns this certificate converted to a DER (binary) encoded
515     representation.
516 */
517 QByteArray QSslCertificate::toDer() const
518 {
519     if (!d->x509)
520         return QByteArray();
521     return d->QByteArray_from_X509(d->x509, QSsl::Der);
522 }
523
524 /*!
525     Searches all files in the \a path for certificates encoded in the
526     specified \a format and returns them in a list. \e must be a file or a
527     pattern matching one or more files, as specified by \a syntax.
528
529     Example:
530     
531     \snippet doc/src/snippets/code/src_network_ssl_qsslcertificate.cpp 0
532
533     \sa fromData()
534 */
535 QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
536                                                  QSsl::EncodingFormat format,
537                                                  QRegExp::PatternSyntax syntax)
538 {
539     // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
540     int pos = -1;
541     if (syntax == QRegExp::Wildcard)
542         pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\*\\?\\[\\]]")));
543     else if (syntax != QRegExp::FixedString)
544         pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
545     QString pathPrefix = path.left(pos); // == path if pos < 0
546     if (pos != -1)
547         pathPrefix = pathPrefix.left(pathPrefix.lastIndexOf(QLatin1Char('/')));
548
549     // Special case - if the prefix ends up being nothing, use "." instead and
550     // chop off the first two characters from the glob'ed paths.
551     int startIndex = 0;
552     if (pathPrefix.trimmed().isEmpty()) {
553         if(path.startsWith(QLatin1Char('/'))) {
554             pathPrefix = path.left(path.indexOf(QRegExp(QLatin1String("[\\*\\?\\[]"))));
555             pathPrefix = path.left(path.lastIndexOf(QLatin1Char('/')));
556         } else {
557             startIndex = 2;
558             pathPrefix = QLatin1String(".");
559         }
560     }
561
562     // The path is a file.
563     if (pos == -1 && QFileInfo(pathPrefix).isFile()) {
564         QFile file(pathPrefix);
565         if (file.open(QIODevice::ReadOnly | QIODevice::Text))
566             return QSslCertificate::fromData(file.readAll(),format);
567         return QList<QSslCertificate>();
568     }
569
570     // The path can be a file or directory.
571     QList<QSslCertificate> certs;
572     QRegExp pattern(path, Qt::CaseSensitive, syntax);
573     QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
574     while (it.hasNext()) {
575         QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
576         if (!pattern.exactMatch(filePath))
577             continue;
578
579         QFile file(filePath);
580         if (file.open(QIODevice::ReadOnly | QIODevice::Text))
581             certs += QSslCertificate::fromData(file.readAll(),format);
582     }
583     return certs;
584 }
585
586 /*!
587     Searches for and parses all certificates in \a device that are
588     encoded in the specified \a format and returns them in a list of
589     certificates.
590
591     \sa fromData()
592 */
593 QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
594 {
595     if (!device) {
596         qWarning("QSslCertificate::fromDevice: cannot read from a null device");
597         return QList<QSslCertificate>();
598     }
599     return fromData(device->readAll(), format);
600 }
601
602 /*!
603     Searches for and parses all certificates in \a data that are
604     encoded in the specified \a format and returns them in a list of
605     certificates.
606
607     \sa fromDevice()
608 */
609 QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
610 {
611     return (format == QSsl::Pem)
612         ? QSslCertificatePrivate::certificatesFromPem(data)
613         : QSslCertificatePrivate::certificatesFromDer(data);
614 }
615
616 void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
617 {
618     if (!data.isEmpty()) {
619         QList<QSslCertificate> certs = (format == QSsl::Pem)
620             ? certificatesFromPem(data, 1)
621             : certificatesFromDer(data, 1);
622         if (!certs.isEmpty()) {
623             *this = *certs.first().d;
624             if (x509)
625                 x509 = q_X509_dup(x509);
626         }
627     }
628 }
629
630 #define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
631 #define ENDCERTSTRING "-----END CERTIFICATE-----"
632
633 // ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
634 QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
635 {
636     if (!x509) {
637         qWarning("QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
638         return QByteArray();
639     }
640
641     // Use i2d_X509 to convert the X509 to an array.
642     int length = q_i2d_X509(x509, 0);
643     QByteArray array;
644     array.resize(length);
645     char *data = array.data();
646     char **dataP = &data;
647     unsigned char **dataPu = (unsigned char **)dataP;
648     if (q_i2d_X509(x509, dataPu) < 0)
649         return QByteArray();
650
651     if (format == QSsl::Der)
652         return array;
653
654     // Convert to Base64 - wrap at 64 characters.
655     array = array.toBase64();
656     QByteArray tmp;
657     for (int i = 0; i <= array.size() - 64; i += 64) {
658         tmp += QByteArray::fromRawData(array.data() + i, 64);
659         tmp += '\n';
660     }
661     if (int remainder = array.size() % 64) {
662         tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
663         tmp += '\n';
664     }
665
666     return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
667 }
668
669 static QMap<QString, QString> _q_mapFromX509Name(X509_NAME *name)
670 {
671     QMap<QString, QString> info;
672     for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
673         X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
674         const char *obj = q_OBJ_nid2sn(q_OBJ_obj2nid(q_X509_NAME_ENTRY_get_object(e)));
675         unsigned char *data = 0;
676         int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
677         info[QString::fromUtf8(obj)] = QString::fromUtf8((char*)data, size);
678         q_CRYPTO_free(data);
679     }
680     return info;
681 }
682
683 QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
684 {
685     QSslCertificate certificate;
686     if (!x509 || !QSslSocket::supportsSsl())
687         return certificate;
688
689     ASN1_TIME *nbef = q_X509_get_notBefore(x509);
690     ASN1_TIME *naft = q_X509_get_notAfter(x509);
691     certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
692     certificate.d->notValidAfter = q_getTimeFromASN1(naft);
693     certificate.d->null = false;
694     certificate.d->x509 = q_X509_dup(x509);
695
696     return certificate;
697 }
698
699 static bool matchLineFeed(const QByteArray &pem, int *offset)
700 {
701     char ch = 0;
702
703     // ignore extra whitespace at the end of the line
704     while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
705         ++*offset;
706
707     if (ch == '\n') {
708         *offset += 1;
709         return true;
710     }
711     if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
712         *offset += 2;
713         return true;
714     }
715     return false;
716 }
717
718 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
719 {
720     QList<QSslCertificate> certificates;
721     QSslSocketPrivate::ensureInitialized();
722
723     int offset = 0;
724     while (count == -1 || certificates.size() < count) {
725         int startPos = pem.indexOf(BEGINCERTSTRING, offset);
726         if (startPos == -1)
727             break;
728         startPos += sizeof(BEGINCERTSTRING) - 1;
729         if (!matchLineFeed(pem, &startPos))
730             break;
731
732         int endPos = pem.indexOf(ENDCERTSTRING, startPos);
733         if (endPos == -1)
734             break;
735
736         offset = endPos + sizeof(ENDCERTSTRING) - 1;
737         if (offset < pem.size() && !matchLineFeed(pem, &offset))
738             break;
739
740         QByteArray decoded = QByteArray::fromBase64(
741             QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
742 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
743         const unsigned char *data = (const unsigned char *)decoded.data();
744 #else
745         unsigned char *data = (unsigned char *)decoded.data();
746 #endif
747
748         if (X509 *x509 = q_d2i_X509(0, &data, decoded.size())) {
749             certificates << QSslCertificate_from_X509(x509);
750             q_X509_free(x509);
751         }
752     }
753
754     return certificates;
755 }
756
757 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
758 {
759     QList<QSslCertificate> certificates;
760     QSslSocketPrivate::ensureInitialized();
761
762
763 #if OPENSSL_VERSION_NUMBER >= 0x00908000L
764         const unsigned char *data = (const unsigned char *)der.data();
765 #else
766         unsigned char *data = (unsigned char *)der.data();
767 #endif
768     int size = der.size();
769
770     while (count == -1 || certificates.size() < count) {
771         if (X509 *x509 = q_d2i_X509(0, &data, size)) {
772             certificates << QSslCertificate_from_X509(x509);
773             q_X509_free(x509);
774         } else {
775             break;
776         }
777         size -= ((char *)data - der.data());
778     }
779
780     return certificates;
781 }
782
783 // These certificates are known to be fraudulent and were created during the comodo
784 // compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html
785 static const char *certificate_blacklist[] = {
786     "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e",
787     "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06",
788     "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3",
789     "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29",
790     "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71",
791     "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47",
792     "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43",
793     "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0",
794     "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0",
795     0
796 };
797
798 bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
799 {
800     for (int a = 0; certificate_blacklist[a] != 0; a++) {
801         if (certificate.serialNumber() == certificate_blacklist[a])
802             return true;
803     }
804     return false;
805 }
806
807 #ifndef QT_NO_DEBUG_STREAM
808 QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
809 {
810     debug << "QSslCertificate("
811           << certificate.version()
812           << ',' << certificate.serialNumber()
813           << ',' << certificate.digest().toBase64()
814           << ',' << certificate.issuerInfo(QSslCertificate::Organization)
815           << ',' << certificate.subjectInfo(QSslCertificate::Organization)
816           << ',' << certificate.alternateSubjectNames()
817 #ifndef QT_NO_TEXTSTREAM
818           << ',' << certificate.effectiveDate()
819           << ',' << certificate.expiryDate()
820 #endif
821           << ')';
822     return debug;
823 }
824 QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
825 {
826     switch (info) {
827     case QSslCertificate::Organization: debug << "Organization"; break;
828     case QSslCertificate::CommonName: debug << "CommonName"; break;
829     case QSslCertificate::CountryName: debug << "CountryName"; break;
830     case QSslCertificate::LocalityName: debug << "LocalityName"; break;
831     case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
832     case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
833     }
834     return debug;
835 }
836 #endif
837
838 QT_END_NAMESPACE