1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Copyright (C) 2016 Richard J. Moore <rich@kde.org>
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qssl_p.h"
42 #include "qsslsocket_openssl_symbols_p.h"
43 #include "qsslcertificate_p.h"
44 #include "qsslkey_p.h"
45 #include "qsslcertificateextension_p.h"
46 
47 #include <QtCore/qendian.h>
48 #include <QtCore/qmutex.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 Q_CONSTEXPR int MutexPoolSize = 17;
53 static QBasicMutex mutexPool[MutexPoolSize];
54 namespace QMutexPool {
globalInstanceGet(const void * addr)55     static QBasicMutex *globalInstanceGet(const void *addr)
56     {
57         return mutexPool + (quintptr(addr) % MutexPoolSize);
58     }
59 }
60 
61 // forward declaration
62 static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name);
63 
operator ==(const QSslCertificate & other) const64 bool QSslCertificate::operator==(const QSslCertificate &other) const
65 {
66     if (d == other.d)
67         return true;
68 
69     if (d->null && other.d->null)
70         return true;
71 
72     if (d->x509 && other.d->x509) {
73         const int ret = q_X509_cmp(d->x509, other.d->x509);
74         if (ret >= -1 && ret <= 1)
75             return ret == 0;
76         QSslSocketBackendPrivate::logAndClearErrorQueue();
77     }
78 
79     return false;
80 }
81 
qHash(const QSslCertificate & key,uint seed)82 uint qHash(const QSslCertificate &key, uint seed) noexcept
83 {
84     if (X509 * const x509 = key.d->x509) {
85         const EVP_MD *sha1 = q_EVP_sha1();
86         unsigned int len = 0;
87         unsigned char md[EVP_MAX_MD_SIZE];
88         q_X509_digest(x509, sha1, md, &len);
89         return qHashBits(md, len, seed);
90     }
91 
92     return seed;
93 }
94 
isNull() const95 bool QSslCertificate::isNull() const
96 {
97     return d->null;
98 }
99 
isSelfSigned() const100 bool QSslCertificate::isSelfSigned() const
101 {
102     if (!d->x509)
103         return false;
104 
105     return (q_X509_check_issued(d->x509, d->x509) == X509_V_OK);
106 }
107 
version() const108 QByteArray QSslCertificate::version() const
109 {
110 #if QT_CONFIG(thread)
111     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
112 #endif
113     if (d->versionString.isEmpty() && d->x509)
114         d->versionString = QByteArray::number(qlonglong(q_X509_get_version(d->x509)) + 1);
115 
116     return d->versionString;
117 }
118 
serialNumber() const119 QByteArray QSslCertificate::serialNumber() const
120 {
121 #if QT_CONFIG(thread)
122     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
123 #endif
124     if (d->serialNumberString.isEmpty() && d->x509) {
125         ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(d->x509);
126         QByteArray hexString;
127         hexString.reserve(serialNumber->length * 3);
128         for (int a = 0; a < serialNumber->length; ++a) {
129             hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
130             hexString += ':';
131         }
132         hexString.chop(1);
133         d->serialNumberString = hexString;
134     }
135     return d->serialNumberString;
136 }
137 
issuerInfo(SubjectInfo info) const138 QStringList QSslCertificate::issuerInfo(SubjectInfo info) const
139 {
140 #if QT_CONFIG(thread)
141     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
142 #endif
143     // lazy init
144     if (d->issuerInfo.isEmpty() && d->x509)
145         d->issuerInfo =
146                 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
147 
148     return d->issuerInfo.values(d->subjectInfoToString(info));
149 }
150 
issuerInfo(const QByteArray & attribute) const151 QStringList QSslCertificate::issuerInfo(const QByteArray &attribute) const
152 {
153 #if QT_CONFIG(thread)
154     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
155 #endif
156     // lazy init
157     if (d->issuerInfo.isEmpty() && d->x509)
158         d->issuerInfo =
159                 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
160 
161     return d->issuerInfo.values(attribute);
162 }
163 
subjectInfo(SubjectInfo info) const164 QStringList QSslCertificate::subjectInfo(SubjectInfo info) const
165 {
166 #if QT_CONFIG(thread)
167     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
168 #endif
169     // lazy init
170     if (d->subjectInfo.isEmpty() && d->x509)
171         d->subjectInfo =
172                 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
173 
174     return d->subjectInfo.values(d->subjectInfoToString(info));
175 }
176 
subjectInfo(const QByteArray & attribute) const177 QStringList QSslCertificate::subjectInfo(const QByteArray &attribute) const
178 {
179 #if QT_CONFIG(thread)
180     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
181 #endif
182     // lazy init
183     if (d->subjectInfo.isEmpty() && d->x509)
184         d->subjectInfo =
185                 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
186 
187     return d->subjectInfo.values(attribute);
188 }
189 
subjectInfoAttributes() const190 QList<QByteArray> QSslCertificate::subjectInfoAttributes() const
191 {
192 #if QT_CONFIG(thread)
193     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
194 #endif
195     // lazy init
196     if (d->subjectInfo.isEmpty() && d->x509)
197         d->subjectInfo =
198                 _q_mapFromX509Name(q_X509_get_subject_name(d->x509));
199 
200     return d->subjectInfo.uniqueKeys();
201 }
202 
issuerInfoAttributes() const203 QList<QByteArray> QSslCertificate::issuerInfoAttributes() const
204 {
205 #if QT_CONFIG(thread)
206     QMutexLocker lock(QMutexPool::globalInstanceGet(d.data()));
207 #endif
208     // lazy init
209     if (d->issuerInfo.isEmpty() && d->x509)
210         d->issuerInfo =
211                 _q_mapFromX509Name(q_X509_get_issuer_name(d->x509));
212 
213     return d->issuerInfo.uniqueKeys();
214 }
215 
subjectAlternativeNames() const216 QMultiMap<QSsl::AlternativeNameEntryType, QString> QSslCertificate::subjectAlternativeNames() const
217 {
218     QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
219 
220     if (!d->x509)
221         return result;
222 
223     STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME) *)q_X509_get_ext_d2i(
224         d->x509, NID_subject_alt_name, nullptr, nullptr);
225 
226     auto altName = [](ASN1_IA5STRING *ia5, int len) {
227         const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(ia5));
228         return QString::fromLatin1(altNameStr, len);
229     };
230     if (altNames) {
231         for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
232             const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
233             if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
234                 continue;
235 
236             int len = q_ASN1_STRING_length(genName->d.ia5);
237             if (len < 0 || len >= 8192) {
238                 // broken name
239                 continue;
240             }
241 
242             switch (genName->type) {
243             case GEN_DNS:
244                 result.insert(QSsl::DnsEntry, altName(genName->d.ia5, len));
245                 break;
246             case GEN_EMAIL:
247                 result.insert(QSsl::EmailEntry, altName(genName->d.ia5, len));
248                 break;
249             case GEN_IPADD: {
250                 QHostAddress ipAddress;
251                 switch (len) {
252                 case 4: // IPv4
253                     ipAddress = QHostAddress(qFromBigEndian(*reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
254                     break;
255                 case 16: // IPv6
256                     ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
257                     break;
258                 default: // Unknown IP address format
259                     break;
260                 }
261                 if (!ipAddress.isNull())
262                     result.insert(QSsl::IpAddressEntry, ipAddress.toString());
263                 break;
264             }
265             default:
266                 break;
267             }
268         }
269 
270         q_OPENSSL_sk_pop_free((OPENSSL_STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
271     }
272 
273     return result;
274 }
275 
effectiveDate() const276 QDateTime QSslCertificate::effectiveDate() const
277 {
278     return d->notValidBefore;
279 }
280 
expiryDate() const281 QDateTime QSslCertificate::expiryDate() const
282 {
283     return d->notValidAfter;
284 }
285 
handle() const286 Qt::HANDLE QSslCertificate::handle() const
287 {
288     return Qt::HANDLE(d->x509);
289 }
290 
publicKey() const291 QSslKey QSslCertificate::publicKey() const
292 {
293     if (!d->x509)
294         return QSslKey();
295 
296     QSslKey key;
297 
298     key.d->type = QSsl::PublicKey;
299 
300     EVP_PKEY *pkey = q_X509_get_pubkey(d->x509);
301     Q_ASSERT(pkey);
302     const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
303 
304     if (keyType == EVP_PKEY_RSA) {
305         key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
306         key.d->algorithm = QSsl::Rsa;
307         key.d->isNull = false;
308     } else if (keyType == EVP_PKEY_DSA) {
309         key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
310         key.d->algorithm = QSsl::Dsa;
311         key.d->isNull = false;
312 #ifndef OPENSSL_NO_EC
313     } else if (keyType == EVP_PKEY_EC) {
314         key.d->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
315         key.d->algorithm = QSsl::Ec;
316         key.d->isNull = false;
317 #endif
318     } else if (keyType == EVP_PKEY_DH) {
319         // DH unsupported
320     } else {
321         // error?
322     }
323 
324     q_EVP_PKEY_free(pkey);
325     return key;
326 }
327 
328 /*
329  * Convert unknown extensions to a QVariant.
330  */
x509UnknownExtensionToValue(X509_EXTENSION * ext)331 static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
332 {
333     // Get the extension specific method object if available
334     // we cast away the const-ness here because some versions of openssl
335     // don't use const for the parameters in the functions pointers stored
336     // in the object.
337     Q_ASSERT(ext);
338 
339     X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
340     if (!meth) {
341         ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext);
342         Q_ASSERT(value);
343         QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(value)),
344                            q_ASN1_STRING_length(value));
345         return result;
346     }
347 
348     //const unsigned char *data = ext->value->data;
349     void *ext_internal = q_X509V3_EXT_d2i(ext);
350 
351     // If this extension can be converted
352     if (meth->i2v && ext_internal) {
353         STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
354 
355         QVariantMap map;
356         QVariantList list;
357         bool isMap = false;
358 
359         for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) {
360             CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
361             if (nval->name && nval->value) {
362                 isMap = true;
363                 map[QString::fromUtf8(nval->name)] = QString::fromUtf8(nval->value);
364             } else if (nval->name) {
365                 list << QString::fromUtf8(nval->name);
366             } else if (nval->value) {
367                 list << QString::fromUtf8(nval->value);
368             }
369         }
370 
371         if (isMap)
372             return map;
373         else
374             return list;
375     } else if (meth->i2s && ext_internal) {
376         QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal)));
377         return result;
378     } else if (meth->i2r && ext_internal) {
379         QByteArray result;
380 
381         BIO *bio = q_BIO_new(q_BIO_s_mem());
382         if (!bio)
383             return result;
384 
385         meth->i2r(meth, ext_internal, bio, 0);
386 
387         char *bio_buffer;
388         long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
389         result = QByteArray(bio_buffer, bio_size);
390 
391         q_BIO_free(bio);
392         return result;
393     }
394 
395     return QVariant();
396 }
397 
398 /*
399  * Convert extensions to a variant. The naming of the keys of the map are
400  * taken from RFC 5280, however we decided the capitalisation in the RFC
401  * was too silly for the real world.
402  */
x509ExtensionToValue(X509_EXTENSION * ext)403 static QVariant x509ExtensionToValue(X509_EXTENSION *ext)
404 {
405     ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
406     int nid = q_OBJ_obj2nid(obj);
407 
408     switch (nid) {
409     case NID_basic_constraints:
410         {
411             BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext));
412             if (!basic)
413                 return QVariant();
414 
415             QVariantMap result;
416             result[QLatin1String("ca")] = basic->ca ? true : false;
417             if (basic->pathlen)
418                 result[QLatin1String("pathLenConstraint")] = (qlonglong)q_ASN1_INTEGER_get(basic->pathlen);
419 
420             q_BASIC_CONSTRAINTS_free(basic);
421             return result;
422         }
423         break;
424     case NID_info_access:
425         {
426             AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext));
427             if (!info)
428                 return QVariant();
429 
430             QVariantMap result;
431             for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) {
432                 ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
433 
434                 GENERAL_NAME *name = ad->location;
435                 if (name->type == GEN_URI) {
436                     int len = q_ASN1_STRING_length(name->d.uniformResourceIdentifier);
437                     if (len < 0 || len >= 8192) {
438                         // broken name
439                         continue;
440                     }
441 
442                     const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(name->d.uniformResourceIdentifier));
443                     const QString uri = QString::fromUtf8(uriStr, len);
444 
445                     result[QString::fromUtf8(QSslCertificatePrivate::asn1ObjectName(ad->method))] = uri;
446                 } else {
447                     qCWarning(lcSsl) << "Strange location type" << name->type;
448                 }
449             }
450 
451             q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free));
452             return result;
453         }
454         break;
455     case NID_subject_key_identifier:
456         {
457             void *ext_internal = q_X509V3_EXT_d2i(ext);
458             if (!ext_internal)
459                 return QVariant();
460             // we cast away the const-ness here because some versions of openssl
461             // don't use const for the parameters in the functions pointers stored
462             // in the object.
463             X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext));
464 
465             return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal)));
466         }
467         break;
468     case NID_authority_key_identifier:
469         {
470             AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext));
471             if (!auth_key)
472                 return QVariant();
473 
474             QVariantMap result;
475 
476             // keyid
477             if (auth_key->keyid) {
478                 QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
479                                  auth_key->keyid->length);
480                 result[QLatin1String("keyid")] = keyid.toHex();
481             }
482 
483             // issuer
484             // TODO: GENERAL_NAMES
485 
486             // serial
487             if (auth_key->serial)
488                 result[QLatin1String("serial")] = (qlonglong)q_ASN1_INTEGER_get(auth_key->serial);
489 
490             q_AUTHORITY_KEYID_free(auth_key);
491             return result;
492         }
493         break;
494     }
495 
496     return QVariant();
497 }
498 
convertExtension(X509_EXTENSION * ext)499 QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext)
500 {
501     Q_ASSERT(ext);
502 
503     QSslCertificateExtension result;
504 
505     ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext);
506     if (!obj) {
507         qCWarning(lcSsl, "Invalid (nullptr) ASN1_OBJECT");
508         return result;
509     }
510 
511     QByteArray oid = QSslCertificatePrivate::asn1ObjectId(obj);
512     QByteArray name = QSslCertificatePrivate::asn1ObjectName(obj);
513 
514     result.d->oid = QString::fromUtf8(oid);
515     result.d->name = QString::fromUtf8(name);
516 
517     bool critical = q_X509_EXTENSION_get_critical(ext);
518     result.d->critical = critical;
519 
520     // Lets see if we have custom support for this one
521     QVariant extensionValue = x509ExtensionToValue(ext);
522     if (extensionValue.isValid()) {
523         result.d->value = extensionValue;
524         result.d->supported = true;
525 
526         return result;
527     }
528 
529     extensionValue = x509UnknownExtensionToValue(ext);
530     if (extensionValue.isValid()) {
531         result.d->value = extensionValue;
532         result.d->supported = false;
533         return result;
534     }
535 
536     return result;
537 }
538 
extensions() const539 QList<QSslCertificateExtension> QSslCertificate::extensions() const
540 {
541     QList<QSslCertificateExtension> result;
542 
543     if (!d->x509)
544         return result;
545 
546     int count = q_X509_get_ext_count(d->x509);
547     if (count <= 0)
548         return result;
549 
550     result.reserve(count);
551 
552     for (int i = 0; i < count; i++) {
553         X509_EXTENSION *ext = q_X509_get_ext(d->x509, i);
554         if (!ext) {
555             qCWarning(lcSsl) << "Invalid (nullptr) extension at index" << i;
556             continue;
557         }
558         result << QSslCertificatePrivate::convertExtension(ext);
559     }
560 
561     // Converting an extension may result in an error(s), clean them up.
562     Q_UNUSED(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
563 
564     return result;
565 }
566 
toPem() const567 QByteArray QSslCertificate::toPem() const
568 {
569     if (!d->x509)
570         return QByteArray();
571     return d->QByteArray_from_X509(d->x509, QSsl::Pem);
572 }
573 
toDer() const574 QByteArray QSslCertificate::toDer() const
575 {
576     if (!d->x509)
577         return QByteArray();
578     return d->QByteArray_from_X509(d->x509, QSsl::Der);
579 }
580 
toText() const581 QString QSslCertificate::toText() const
582 {
583     if (!d->x509)
584         return QString();
585     return d->text_from_X509(d->x509);
586 }
587 
588 #define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
589 #define ENDCERTSTRING "-----END CERTIFICATE-----"
590 
init(const QByteArray & data,QSsl::EncodingFormat format)591 void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
592 {
593     if (!data.isEmpty()) {
594         const QList<QSslCertificate> certs = (format == QSsl::Pem)
595             ? certificatesFromPem(data, 1)
596             : certificatesFromDer(data, 1);
597         if (!certs.isEmpty()) {
598             *this = *certs.first().d;
599             if (x509)
600                 x509 = q_X509_dup(x509);
601         }
602     }
603 }
604 
605 // ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
QByteArray_from_X509(X509 * x509,QSsl::EncodingFormat format)606 QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
607 {
608     if (!x509) {
609         qCWarning(lcSsl, "QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
610         return QByteArray();
611     }
612 
613     // Use i2d_X509 to convert the X509 to an array.
614     int length = q_i2d_X509(x509, nullptr);
615     QByteArray array;
616     array.resize(length);
617     char *data = array.data();
618     char **dataP = &data;
619     unsigned char **dataPu = (unsigned char **)dataP;
620     if (q_i2d_X509(x509, dataPu) < 0)
621         return QByteArray();
622 
623     if (format == QSsl::Der)
624         return array;
625 
626     // Convert to Base64 - wrap at 64 characters.
627     array = array.toBase64();
628     QByteArray tmp;
629     for (int i = 0; i <= array.size() - 64; i += 64) {
630         tmp += QByteArray::fromRawData(array.data() + i, 64);
631         tmp += '\n';
632     }
633     if (int remainder = array.size() % 64) {
634         tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
635         tmp += '\n';
636     }
637 
638     return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
639 }
640 
text_from_X509(X509 * x509)641 QString QSslCertificatePrivate::text_from_X509(X509 *x509)
642 {
643     if (!x509) {
644         qCWarning(lcSsl, "QSslSocketBackendPrivate::text_from_X509: null X509");
645         return QString();
646     }
647 
648     QByteArray result;
649     BIO *bio = q_BIO_new(q_BIO_s_mem());
650     if (!bio)
651         return QString();
652 
653     q_X509_print(bio, x509);
654 
655     QVarLengthArray<char, 16384> data;
656     int count = q_BIO_read(bio, data.data(), 16384);
657     if ( count > 0 ) {
658         result = QByteArray( data.data(), count );
659     }
660 
661     q_BIO_free(bio);
662 
663     return QString::fromLatin1(result);
664 }
665 
asn1ObjectId(ASN1_OBJECT * object)666 QByteArray QSslCertificatePrivate::asn1ObjectId(ASN1_OBJECT *object)
667 {
668     char buf[80]; // The openssl docs a buffer length of 80 should be more than enough
669     q_OBJ_obj2txt(buf, sizeof(buf), object, 1); // the 1 says always use the oid not the long name
670 
671     return QByteArray(buf);
672 }
673 
674 
asn1ObjectName(ASN1_OBJECT * object)675 QByteArray QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object)
676 {
677     int nid = q_OBJ_obj2nid(object);
678     if (nid != NID_undef)
679         return QByteArray(q_OBJ_nid2sn(nid));
680 
681     return asn1ObjectId(object);
682 }
683 
_q_mapFromX509Name(X509_NAME * name)684 static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name)
685 {
686     QMultiMap<QByteArray, QString> info;
687     for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) {
688         X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i);
689 
690         QByteArray name = QSslCertificatePrivate::asn1ObjectName(q_X509_NAME_ENTRY_get_object(e));
691         unsigned char *data = nullptr;
692         int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e));
693         info.insert(name, QString::fromUtf8((char*)data, size));
694 #if QT_CONFIG(opensslv11)
695         q_CRYPTO_free(data, nullptr, 0);
696 #else
697         q_CRYPTO_free(data);
698 #endif
699     }
700 
701     return info;
702 }
703 
QSslCertificate_from_X509(X509 * x509)704 QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
705 {
706     QSslCertificate certificate;
707     if (!x509 || !QSslSocket::supportsSsl())
708         return certificate;
709 
710     ASN1_TIME *nbef = q_X509_getm_notBefore(x509);
711     ASN1_TIME *naft = q_X509_getm_notAfter(x509);
712 
713     certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
714     certificate.d->notValidAfter = q_getTimeFromASN1(naft);
715     certificate.d->null = false;
716     certificate.d->x509 = q_X509_dup(x509);
717 
718     return certificate;
719 }
720 
matchLineFeed(const QByteArray & pem,int * offset)721 static bool matchLineFeed(const QByteArray &pem, int *offset)
722 {
723     char ch = 0;
724 
725     // ignore extra whitespace at the end of the line
726     while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
727         ++*offset;
728 
729     if (ch == '\n') {
730         *offset += 1;
731         return true;
732     }
733     if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
734         *offset += 2;
735         return true;
736     }
737     return false;
738 }
739 
certificatesFromPem(const QByteArray & pem,int count)740 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
741 {
742     QList<QSslCertificate> certificates;
743     QSslSocketPrivate::ensureInitialized();
744 
745     int offset = 0;
746     while (count == -1 || certificates.size() < count) {
747         int startPos = pem.indexOf(BEGINCERTSTRING, offset);
748         if (startPos == -1)
749             break;
750         startPos += sizeof(BEGINCERTSTRING) - 1;
751         if (!matchLineFeed(pem, &startPos))
752             break;
753 
754         int endPos = pem.indexOf(ENDCERTSTRING, startPos);
755         if (endPos == -1)
756             break;
757 
758         offset = endPos + sizeof(ENDCERTSTRING) - 1;
759         if (offset < pem.size() && !matchLineFeed(pem, &offset))
760             break;
761 
762         QByteArray decoded = QByteArray::fromBase64(
763             QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
764         const unsigned char *data = (const unsigned char *)decoded.data();
765 
766         if (X509 *x509 = q_d2i_X509(nullptr, &data, decoded.size())) {
767             certificates << QSslCertificate_from_X509(x509);
768             q_X509_free(x509);
769         }
770     }
771 
772     return certificates;
773 }
774 
certificatesFromDer(const QByteArray & der,int count)775 QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
776 {
777     QList<QSslCertificate> certificates;
778     QSslSocketPrivate::ensureInitialized();
779 
780     const unsigned char *data = (const unsigned char *)der.data();
781     int size = der.size();
782 
783     while (size > 0 && (count == -1 || certificates.size() < count)) {
784         if (X509 *x509 = q_d2i_X509(nullptr, &data, size)) {
785             certificates << QSslCertificate_from_X509(x509);
786             q_X509_free(x509);
787         } else {
788             break;
789         }
790         size -= ((const char *)data - der.data());
791     }
792 
793     return certificates;
794 }
795 
796 QT_END_NAMESPACE
797