1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsslsocket_openssl_symbols_p.h"
5#include "qtlsbackend_openssl_p.h"
6#include "qtlskey_openssl_p.h"
7#include "qx509_openssl_p.h"
8#include "qtls_openssl_p.h"
9
10#include <QtNetwork/private/qsslcertificate_p.h>
11
12#include <QtNetwork/qsslsocket.h>
13#include <QtNetwork/qhostaddress.h>
14
15#include <QtCore/qendian.h>
16#include <QtCore/qdatetime.h>
17#include <QtCore/qhash.h>
18#include <QtCore/qiodevice.h>
19#include <QtCore/qscopeguard.h>
20#include <QtCore/qtimezone.h>
21#include <QtCore/qvarlengtharray.h>
22
23QT_BEGIN_NAMESPACE
24
25using namespace Qt::StringLiterals;
26
27namespace QTlsPrivate {
28
29namespace {
30
31QByteArray asn1ObjectId(ASN1_OBJECT *object)
32{
33 if (!object)
34 return {};
35
36 char buf[80] = {}; // The openssl docs a buffer length of 80 should be more than enough
37 q_OBJ_obj2txt(buf, buf_len: sizeof(buf), obj: object, no_name: 1); // the 1 says always use the oid not the long name
38
39 return QByteArray(buf);
40}
41
42QByteArray asn1ObjectName(ASN1_OBJECT *object)
43{
44 if (!object)
45 return {};
46
47 const int nid = q_OBJ_obj2nid(a: object);
48 if (nid != NID_undef)
49 return QByteArray(q_OBJ_nid2sn(a: nid));
50
51 return asn1ObjectId(object);
52}
53
54QMultiMap<QByteArray, QString> mapFromX509Name(X509_NAME *name)
55{
56 if (!name)
57 return {};
58
59 QMultiMap<QByteArray, QString> info;
60 for (int i = 0; i < q_X509_NAME_entry_count(a: name); ++i) {
61 X509_NAME_ENTRY *e = q_X509_NAME_get_entry(a: name, b: i);
62
63 QByteArray name = asn1ObjectName(object: q_X509_NAME_ENTRY_get_object(a: e));
64 unsigned char *data = nullptr;
65 int size = q_ASN1_STRING_to_UTF8(a: &data, b: q_X509_NAME_ENTRY_get_data(a: e));
66 info.insert(key: name, value: QString::fromUtf8(utf8: (char*)data, size));
67 q_CRYPTO_free(str: data, file: nullptr, line: 0);
68 }
69
70 return info;
71}
72
73QDateTime dateTimeFromASN1(const ASN1_TIME *aTime)
74{
75 QDateTime result;
76 tm lTime;
77
78 if (q_ASN1_TIME_to_tm(s: aTime, tm: &lTime)) {
79 QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
80 QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
81 result = QDateTime(resDate, resTime, QTimeZone::UTC);
82 }
83
84 return result;
85}
86
87
88#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
89#define ENDCERTSTRING "-----END CERTIFICATE-----"
90
91QByteArray x509ToQByteArray(X509 *x509, QSsl::EncodingFormat format)
92{
93 Q_ASSERT(x509);
94
95 // Use i2d_X509 to convert the X509 to an array.
96 const int length = q_i2d_X509(a: x509, b: nullptr);
97 if (length <= 0) {
98 QTlsBackendOpenSSL::logAndClearErrorQueue();
99 return {};
100 }
101
102 QByteArray array;
103 array.resize(size: length);
104
105 char *data = array.data();
106 char **dataP = &data;
107 unsigned char **dataPu = (unsigned char **)dataP;
108 if (q_i2d_X509(a: x509, b: dataPu) < 0)
109 return QByteArray();
110
111 if (format == QSsl::Der)
112 return array;
113
114 // Convert to Base64 - wrap at 64 characters.
115 array = array.toBase64();
116 QByteArray tmp;
117 for (int i = 0; i <= array.size() - 64; i += 64) {
118 tmp += QByteArray::fromRawData(data: array.data() + i, size: 64);
119 tmp += '\n';
120 }
121 if (int remainder = array.size() % 64) {
122 tmp += QByteArray::fromRawData(data: array.data() + array.size() - remainder, size: remainder);
123 tmp += '\n';
124 }
125
126 return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
127}
128
129QString x509ToText(X509 *x509)
130{
131 Q_ASSERT(x509);
132
133 QByteArray result;
134 BIO *bio = q_BIO_new(a: q_BIO_s_mem());
135 if (!bio)
136 return QString();
137 const auto bioRaii = qScopeGuard(f: [bio]{q_BIO_free(a: bio);});
138
139 q_X509_print(a: bio, b: x509);
140
141 QVarLengthArray<char, 16384> data;
142 int count = q_BIO_read(a: bio, b: data.data(), c: 16384);
143 if ( count > 0 )
144 result = QByteArray( data.data(), count );
145
146 return QString::fromLatin1(ba: result);
147}
148
149QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext)
150{
151 // Get the extension specific method object if available
152 // we cast away the const-ness here because some versions of openssl
153 // don't use const for the parameters in the functions pointers stored
154 // in the object.
155 Q_ASSERT(ext);
156
157 X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(a: ext));
158 if (!meth) {
159 ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(a: ext);
160 Q_ASSERT(value);
161 QByteArray result( reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(x: value)),
162 q_ASN1_STRING_length(a: value));
163 return result;
164 }
165
166 void *ext_internal = q_X509V3_EXT_d2i(a: ext);
167 if (!ext_internal)
168 return {};
169
170 const auto extCleaner = qScopeGuard(f: [meth, ext_internal]{
171 Q_ASSERT(ext_internal && meth);
172
173 if (meth->it)
174 q_ASN1_item_free(val: static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it));
175 else if (meth->ext_free)
176 meth->ext_free(ext_internal);
177 else
178 qCWarning(lcTlsBackend, "No method to free an unknown extension, a potential memory leak?");
179 });
180
181 // If this extension can be converted
182 if (meth->i2v) {
183 STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr);
184 const auto stackCleaner = qScopeGuard(f: [val]{
185 if (val)
186 q_OPENSSL_sk_pop_free(a: (OPENSSL_STACK *)val, b: (void(*)(void*))q_X509V3_conf_free);
187 });
188
189 QVariantMap map;
190 QVariantList list;
191 bool isMap = false;
192
193 for (int j = 0; j < q_SKM_sk_num(val); j++) {
194 CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j);
195 if (nval->name && nval->value) {
196 isMap = true;
197 map[QString::fromUtf8(utf8: nval->name)] = QString::fromUtf8(utf8: nval->value);
198 } else if (nval->name) {
199 list << QString::fromUtf8(utf8: nval->name);
200 } else if (nval->value) {
201 list << QString::fromUtf8(utf8: nval->value);
202 }
203 }
204
205 if (isMap)
206 return map;
207 else
208 return list;
209 } else if (meth->i2s) {
210 const char *hexString = meth->i2s(meth, ext_internal);
211 QVariant result(hexString ? QString::fromUtf8(utf8: hexString) : QString{});
212 q_OPENSSL_free((void *)hexString);
213 return result;
214 } else if (meth->i2r) {
215 QByteArray result;
216
217 BIO *bio = q_BIO_new(a: q_BIO_s_mem());
218 if (!bio)
219 return result;
220
221 meth->i2r(meth, ext_internal, bio, 0);
222
223 char *bio_buffer;
224 long bio_size = q_BIO_get_mem_data(bio, &bio_buffer);
225 result = QByteArray(bio_buffer, bio_size);
226
227 q_BIO_free(a: bio);
228 return result;
229 }
230
231 return QVariant();
232}
233
234/*
235 * Convert extensions to a variant. The naming of the keys of the map are
236 * taken from RFC 5280, however we decided the capitalisation in the RFC
237 * was too silly for the real world.
238 */
239QVariant x509ExtensionToValue(X509_EXTENSION *ext)
240{
241 ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(a: ext);
242 int nid = q_OBJ_obj2nid(a: obj);
243
244 // We cast away the const-ness here because some versions of openssl
245 // don't use const for the parameters in the functions pointers stored
246 // in the object.
247 X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(a: ext));
248
249 void *ext_internal = nullptr; // The value, returned by X509V3_EXT_d2i.
250 const auto extCleaner = qScopeGuard(f: [meth, &ext_internal]() {
251 if (!meth || !ext_internal)
252 return;
253
254 if (meth->it)
255 q_ASN1_item_free(val: static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it));
256 else if (meth->ext_free)
257 meth->ext_free(ext_internal);
258 else
259 qWarning(catFunc: lcTlsBackend, msg: "Cannot free an extension, a potential memory leak?");
260 });
261
262 const char * hexString = nullptr; // The value returned by meth->i2s.
263 const auto hexStringCleaner = qScopeGuard(f: [&hexString](){
264 if (hexString)
265 q_OPENSSL_free((void*)hexString);
266 });
267
268 switch (nid) {
269 case NID_basic_constraints:
270 {
271 BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(a: ext));
272 if (!basic)
273 return {};
274 QVariantMap result;
275 result["ca"_L1] = basic->ca ? true : false;
276 if (basic->pathlen)
277 result["pathLenConstraint"_L1] = (qlonglong)q_ASN1_INTEGER_get(a: basic->pathlen);
278
279 q_BASIC_CONSTRAINTS_free(a: basic);
280 return result;
281 }
282 break;
283 case NID_info_access:
284 {
285 AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(a: ext));
286 if (!info)
287 return {};
288 QVariantMap result;
289 for (int i=0; i < q_SKM_sk_num(info); i++) {
290 ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i);
291
292 GENERAL_NAME *name = ad->location;
293 if (name->type == GEN_URI) {
294 int len = q_ASN1_STRING_length(a: name->d.uniformResourceIdentifier);
295 if (len < 0 || len >= 8192) {
296 // broken name
297 continue;
298 }
299
300 const char *uriStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(x: name->d.uniformResourceIdentifier));
301 const QString uri = QString::fromUtf8(utf8: uriStr, size: len);
302
303 result[QString::fromUtf8(ba: asn1ObjectName(object: ad->method))] = uri;
304 } else {
305 qCWarning(lcTlsBackend) << "Strange location type" << name->type;
306 }
307 }
308
309 q_AUTHORITY_INFO_ACCESS_free(a: info);
310 return result;
311 }
312 break;
313 case NID_subject_key_identifier:
314 {
315 ext_internal = q_X509V3_EXT_d2i(a: ext);
316 if (!ext_internal)
317 return {};
318
319 hexString = meth->i2s(meth, ext_internal);
320 return QVariant(QString::fromUtf8(utf8: hexString));
321 }
322 break;
323 case NID_authority_key_identifier:
324 {
325 AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(a: ext));
326 if (!auth_key)
327 return {};
328 QVariantMap result;
329
330 // keyid
331 if (auth_key->keyid) {
332 QByteArray keyid(reinterpret_cast<const char *>(auth_key->keyid->data),
333 auth_key->keyid->length);
334 result["keyid"_L1] = keyid.toHex();
335 }
336
337 // issuer
338 // TODO: GENERAL_NAMES
339
340 // serial
341 if (auth_key->serial)
342 result["serial"_L1] = (qlonglong)q_ASN1_INTEGER_get(a: auth_key->serial);
343
344 q_AUTHORITY_KEYID_free(a: auth_key);
345 return result;
346 }
347 break;
348 }
349
350 return {};
351}
352
353} // Unnamed namespace
354
355extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx)
356{
357 if (!ok) {
358 // Store the error and at which depth the error was detected.
359 using ErrorListPtr = QList<QSslErrorEntry> *;
360 ErrorListPtr errors = nullptr;
361
362 // Error list is attached to either 'SSL' or 'X509_STORE'.
363 if (X509_STORE *store = q_X509_STORE_CTX_get0_store(ctx)) // We try store first:
364 errors = ErrorListPtr(q_X509_STORE_get_ex_data(r: store, idx: 0));
365
366 if (!errors) {
367 // Not found on store? Try SSL and its external data then. According to the OpenSSL's
368 // documentation:
369 //
370 // "Whenever a X509_STORE_CTX object is created for the verification of the
371 // peer's certificate during a handshake, a pointer to the SSL object is
372 // stored into the X509_STORE_CTX object to identify the connection affected.
373 // To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
374 // used with the correct index."
375
376 // TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
377 // This is a temporary solution for now to ease the transition.
378 const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
379 + TlsCryptographOpenSSL::errorOffsetInExData;
380 if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, idx: q_SSL_get_ex_data_X509_STORE_CTX_idx())))
381 errors = ErrorListPtr(q_SSL_get_ex_data(ssl, idx: offset));
382 }
383
384 if (!errors) {
385 qCWarning(lcTlsBackend, "Neither X509_STORE, nor SSL contains error list, verification failed");
386 return 0;
387 }
388
389 errors->append(t: X509CertificateOpenSSL::errorEntryFromStoreContext(ctx));
390 }
391 // Always return OK to allow verification to continue. We handle the
392 // errors gracefully after collecting all errors, after verification has
393 // completed.
394 return 1;
395}
396
397X509CertificateOpenSSL::X509CertificateOpenSSL() = default;
398
399X509CertificateOpenSSL::~X509CertificateOpenSSL()
400{
401 if (x509)
402 q_X509_free(a: x509);
403}
404
405bool X509CertificateOpenSSL::isEqual(const X509Certificate &rhs) const
406{
407 //TLSTODO: to make it safe I'll check the backend type later.
408 const auto &other = static_cast<const X509CertificateOpenSSL &>(rhs);
409 if (x509 && other.x509) {
410 const int ret = q_X509_cmp(a: x509, b: other.x509);
411 if (ret >= -1 && ret <= 1)
412 return ret == 0;
413 QTlsBackendOpenSSL::logAndClearErrorQueue();
414 }
415
416 return false;
417}
418
419bool X509CertificateOpenSSL::isSelfSigned() const
420{
421 if (!x509)
422 return false;
423
424 return q_X509_check_issued(a: x509, b: x509) == X509_V_OK;
425}
426
427QMultiMap<QSsl::AlternativeNameEntryType, QString>
428X509CertificateOpenSSL::subjectAlternativeNames() const
429{
430 QMultiMap<QSsl::AlternativeNameEntryType, QString> result;
431
432 if (!x509)
433 return result;
434
435 auto *altNames = static_cast<STACK_OF(GENERAL_NAME) *>(q_X509_get_ext_d2i(a: x509, NID_subject_alt_name,
436 c: nullptr, d: nullptr));
437 if (!altNames)
438 return result;
439
440 auto altName = [](ASN1_IA5STRING *ia5, int len) {
441 const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_get0_data(x: ia5));
442 return QString::fromLatin1(str: altNameStr, size: len);
443 };
444
445 for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
446 const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
447 if (genName->type != GEN_DNS && genName->type != GEN_EMAIL && genName->type != GEN_IPADD)
448 continue;
449
450 const int len = q_ASN1_STRING_length(a: genName->d.ia5);
451 if (len < 0 || len >= 8192) {
452 // broken name
453 continue;
454 }
455
456 switch (genName->type) {
457 case GEN_DNS:
458 result.insert(key: QSsl::DnsEntry, value: altName(genName->d.ia5, len));
459 break;
460 case GEN_EMAIL:
461 result.insert(key: QSsl::EmailEntry, value: altName(genName->d.ia5, len));
462 break;
463 case GEN_IPADD: {
464 QHostAddress ipAddress;
465 switch (len) {
466 case 4: // IPv4
467 ipAddress = QHostAddress(qFromBigEndian(source: *reinterpret_cast<quint32 *>(genName->d.iPAddress->data)));
468 break;
469 case 16: // IPv6
470 ipAddress = QHostAddress(reinterpret_cast<quint8 *>(genName->d.iPAddress->data));
471 break;
472 default: // Unknown IP address format
473 break;
474 }
475 if (!ipAddress.isNull())
476 result.insert(key: QSsl::IpAddressEntry, value: ipAddress.toString());
477 break;
478 }
479 default:
480 break;
481 }
482 }
483
484 q_OPENSSL_sk_pop_free(a: (OPENSSL_STACK*)altNames, b: reinterpret_cast<void(*)(void*)>(q_GENERAL_NAME_free));
485
486 return result;
487}
488
489TlsKey *X509CertificateOpenSSL::publicKey() const
490{
491 if (!x509)
492 return {};
493
494 return TlsKeyOpenSSL::publicKeyFromX509(x: x509);
495}
496
497QByteArray X509CertificateOpenSSL::toPem() const
498{
499 if (!x509)
500 return {};
501
502 return x509ToQByteArray(x509, format: QSsl::Pem);
503}
504
505QByteArray X509CertificateOpenSSL::toDer() const
506{
507 if (!x509)
508 return {};
509
510 return x509ToQByteArray(x509, format: QSsl::Der);
511
512}
513QString X509CertificateOpenSSL::toText() const
514{
515 if (!x509)
516 return {};
517
518 return x509ToText(x509);
519}
520
521Qt::HANDLE X509CertificateOpenSSL::handle() const
522{
523 return Qt::HANDLE(x509);
524}
525
526size_t X509CertificateOpenSSL::hash(size_t seed) const noexcept
527{
528 if (x509) {
529 const EVP_MD *sha1 = q_EVP_sha1();
530 unsigned int len = 0;
531 unsigned char md[EVP_MAX_MD_SIZE];
532 q_X509_digest(x509, type: sha1, md, len: &len);
533 return qHashBits(p: md, size: len, seed);
534 }
535
536 return seed;
537}
538
539QSslCertificate X509CertificateOpenSSL::certificateFromX509(X509 *x509)
540{
541 QSslCertificate certificate;
542
543 auto *backend = QTlsBackend::backend<X509CertificateOpenSSL>(o: certificate);
544 if (!backend || !x509)
545 return certificate;
546
547 ASN1_TIME *nbef = q_X509_getm_notBefore(a: x509);
548 if (nbef)
549 backend->notValidBefore = dateTimeFromASN1(aTime: nbef);
550
551 ASN1_TIME *naft = q_X509_getm_notAfter(a: x509);
552 if (naft)
553 backend->notValidAfter = dateTimeFromASN1(aTime: naft);
554
555 backend->null = false;
556 backend->x509 = q_X509_dup(a: x509);
557
558 backend->issuerInfoEntries = mapFromX509Name(name: q_X509_get_issuer_name(a: x509));
559 backend->subjectInfoEntries = mapFromX509Name(name: q_X509_get_subject_name(a: x509));
560 backend->versionString = QByteArray::number(qlonglong(q_X509_get_version(a: x509)) + 1);
561
562 if (ASN1_INTEGER *serialNumber = q_X509_get_serialNumber(a: x509)) {
563 QByteArray hexString;
564 hexString.reserve(asize: serialNumber->length * 3);
565 for (int a = 0; a < serialNumber->length; ++a) {
566 hexString += QByteArray::number(serialNumber->data[a], base: 16).rightJustified(width: 2, fill: '0');
567 hexString += ':';
568 }
569 hexString.chop(n: 1);
570 backend->serialNumberString = hexString;
571 }
572
573 backend->parseExtensions();
574
575 return certificate;
576}
577
578QList<QSslCertificate> X509CertificateOpenSSL::stackOfX509ToQSslCertificates(STACK_OF(X509) *x509)
579{
580 if (!x509)
581 return {};
582
583 QList<QSslCertificate> certificates;
584 for (int i = 0; i < q_sk_X509_num(x509); ++i) {
585 if (X509 *entry = q_sk_X509_value(x509, i))
586 certificates << certificateFromX509(x509: entry);
587 }
588
589 return certificates;
590}
591
592QSslErrorEntry X509CertificateOpenSSL::errorEntryFromStoreContext(X509_STORE_CTX *ctx)
593{
594 Q_ASSERT(ctx);
595
596 return {.code: q_X509_STORE_CTX_get_error(ctx), .depth: q_X509_STORE_CTX_get_error_depth(ctx)};
597}
598
599QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &chain,
600 const QString &hostName)
601{
602 // This was previously QSslSocketPrivate::verify().
603 auto roots = QSslConfiguration::defaultConfiguration().caCertificates();
604#ifndef Q_OS_WIN
605 // On Windows, system CA certificates are already set as default ones.
606 // No need to add them again (and again) and also, if the default configuration
607 // has its own set of CAs, this probably should not be amended by the ones
608 // from the 'ROOT' store, since it's not what an application chose to trust.
609 if (QSslSocketPrivate::rootCertOnDemandLoadingSupported())
610 roots.append(other: QSslSocketPrivate::systemCaCertificates());
611#endif // Q_OS_WIN
612 return verify(caCertificates: roots, certificateChain: chain, hostName);
613}
614
615QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &caCertificates,
616 const QList<QSslCertificate> &certificateChain,
617 const QString &hostName)
618{
619 // This was previously QSslSocketPrivate::verify().
620 if (certificateChain.size() <= 0)
621 return {QSslError(QSslError::UnspecifiedError)};
622
623 QList<QSslError> errors;
624 X509_STORE *certStore = q_X509_STORE_new();
625 if (!certStore) {
626 qCWarning(lcTlsBackend) << "Unable to create certificate store";
627 errors << QSslError(QSslError::UnspecifiedError);
628 return errors;
629 }
630 const std::unique_ptr<X509_STORE, decltype(&q_X509_STORE_free)> storeGuard(certStore, q_X509_STORE_free);
631
632 const QDateTime now = QDateTime::currentDateTimeUtc();
633 for (const QSslCertificate &caCertificate : caCertificates) {
634 // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html:
635 //
636 // If several CA certificates matching the name, key identifier, and
637 // serial number condition are available, only the first one will be
638 // examined. This may lead to unexpected results if the same CA
639 // certificate is available with different expiration dates. If a
640 // ``certificate expired'' verification error occurs, no other
641 // certificate will be searched. Make sure to not have expired
642 // certificates mixed with valid ones.
643 //
644 // See also: QSslContext::sharedFromConfiguration()
645 if (caCertificate.expiryDate() >= now) {
646 q_X509_STORE_add_cert(ctx: certStore, x: reinterpret_cast<X509 *>(caCertificate.handle()));
647 }
648 }
649
650 QList<QSslErrorEntry> lastErrors;
651 if (!q_X509_STORE_set_ex_data(ctx: certStore, idx: 0, data: &lastErrors)) {
652 qCWarning(lcTlsBackend) << "Unable to attach external data (error list) to a store";
653 errors << QSslError(QSslError::UnspecifiedError);
654 return errors;
655 }
656
657 // Register a custom callback to get all verification errors.
658 q_X509_STORE_set_verify_cb(ctx: certStore, verify_cb: qt_X509Callback);
659
660 // Build the chain of intermediate certificates
661 STACK_OF(X509) *intermediates = nullptr;
662 if (certificateChain.size() > 1) {
663 intermediates = (STACK_OF(X509) *) q_OPENSSL_sk_new_null();
664
665 if (!intermediates) {
666 errors << QSslError(QSslError::UnspecifiedError);
667 return errors;
668 }
669
670 bool first = true;
671 for (const QSslCertificate &cert : certificateChain) {
672 if (first) {
673 first = false;
674 continue;
675 }
676
677 q_OPENSSL_sk_push(st: (OPENSSL_STACK *)intermediates, data: reinterpret_cast<X509 *>(cert.handle()));
678 }
679 }
680
681 X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
682 if (!storeContext) {
683 errors << QSslError(QSslError::UnspecifiedError);
684 return errors;
685 }
686 std::unique_ptr<X509_STORE_CTX, decltype(&q_X509_STORE_CTX_free)> ctxGuard(storeContext, q_X509_STORE_CTX_free);
687
688 if (!q_X509_STORE_CTX_init(ctx: storeContext, store: certStore, x509: reinterpret_cast<X509 *>(certificateChain[0].handle()), chain: intermediates)) {
689 errors << QSslError(QSslError::UnspecifiedError);
690 return errors;
691 }
692
693 // Now we can actually perform the verification of the chain we have built.
694 // We ignore the result of this function since we process errors via the
695 // callback.
696 (void) q_X509_verify_cert(ctx: storeContext);
697 ctxGuard.reset();
698 q_OPENSSL_sk_free(a: (OPENSSL_STACK *)intermediates);
699
700 // Now process the errors
701
702 if (certificateChain[0].isBlacklisted())
703 errors << QSslError(QSslError::CertificateBlacklisted, certificateChain[0]);
704
705 // Check the certificate name against the hostname if one was specified
706 if (!hostName.isEmpty() && !TlsCryptograph::isMatchingHostname(cert: certificateChain[0], peerName: hostName)) {
707 // No matches in common names or alternate names.
708 QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
709 errors << error;
710 }
711
712 // Translate errors from the error list into QSslErrors.
713 errors.reserve(asize: errors.size() + lastErrors.size());
714 for (const auto &error : std::as_const(t&: lastErrors))
715 errors << openSSLErrorToQSslError(errorCode: error.code, cert: certificateChain.value(i: error.depth));
716
717 return errors;
718}
719
720QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromPem(const QByteArray &pem, int count)
721{
722 QList<QSslCertificate> certificates;
723
724 int offset = 0;
725 while (count == -1 || certificates.size() < count) {
726 int startPos = pem.indexOf(BEGINCERTSTRING, from: offset);
727 if (startPos == -1)
728 break;
729 startPos += sizeof(BEGINCERTSTRING) - 1;
730 if (!matchLineFeed(pem, offset: &startPos))
731 break;
732
733 int endPos = pem.indexOf(ENDCERTSTRING, from: startPos);
734 if (endPos == -1)
735 break;
736
737 offset = endPos + sizeof(ENDCERTSTRING) - 1;
738 if (offset < pem.size() && !matchLineFeed(pem, offset: &offset))
739 break;
740
741 QByteArray decoded = QByteArray::fromBase64(
742 base64: QByteArray::fromRawData(data: pem.data() + startPos, size: endPos - startPos));
743 const unsigned char *data = (const unsigned char *)decoded.data();
744
745 if (X509 *x509 = q_d2i_X509(a: nullptr, b: &data, c: decoded.size())) {
746 certificates << certificateFromX509(x509);
747 q_X509_free(a: x509);
748 }
749 }
750
751 return certificates;
752}
753
754QList<QSslCertificate> X509CertificateOpenSSL::certificatesFromDer(const QByteArray &der, int count)
755{
756 QList<QSslCertificate> certificates;
757
758 const unsigned char *data = (const unsigned char *)der.data();
759 int size = der.size();
760
761 while (size > 0 && (count == -1 || certificates.size() < count)) {
762 if (X509 *x509 = q_d2i_X509(a: nullptr, b: &data, c: size)) {
763 certificates << certificateFromX509(x509);
764 q_X509_free(a: x509);
765 } else {
766 break;
767 }
768 size -= ((const char *)data - der.data());
769 }
770
771 return certificates;
772}
773
774bool X509CertificateOpenSSL::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
775 QList<QSslCertificate> *caCertificates,
776 const QByteArray &passPhrase)
777{
778 // These are required
779 Q_ASSERT(device);
780 Q_ASSERT(key);
781 Q_ASSERT(cert);
782
783 // Read the file into a BIO
784 QByteArray pkcs12data = device->readAll();
785 if (pkcs12data.size() == 0)
786 return false;
787
788 BIO *bio = q_BIO_new_mem_buf(a: const_cast<char *>(pkcs12data.constData()), b: pkcs12data.size());
789 if (!bio) {
790 qCWarning(lcTlsBackend, "BIO_new_mem_buf returned null");
791 return false;
792 }
793 const auto bioRaii = qScopeGuard(f: [bio]{q_BIO_free(a: bio);});
794
795 // Create the PKCS#12 object
796 PKCS12 *p12 = q_d2i_PKCS12_bio(bio, pkcs12: nullptr);
797 if (!p12) {
798 qCWarning(lcTlsBackend, "Unable to read PKCS#12 structure, %s",
799 q_ERR_error_string(q_ERR_get_error(), nullptr));
800 return false;
801 }
802 const auto p12Raii = qScopeGuard(f: [p12]{q_PKCS12_free(pkcs12: p12);});
803
804 // Extract the data
805 EVP_PKEY *pkey = nullptr;
806 X509 *x509 = nullptr;
807 STACK_OF(X509) *ca = nullptr;
808
809 if (!q_PKCS12_parse(p12, pass: passPhrase.constData(), pkey: &pkey, cert: &x509, ca: &ca)) {
810 qCWarning(lcTlsBackend, "Unable to parse PKCS#12 structure, %s",
811 q_ERR_error_string(q_ERR_get_error(), nullptr));
812 return false;
813 }
814
815 const auto x509Raii = qScopeGuard(f: [x509]{q_X509_free(a: x509);});
816 const auto keyRaii = qScopeGuard(f: [pkey]{q_EVP_PKEY_free(a: pkey);});
817 const auto caRaii = qScopeGuard(f: [ca] {
818 q_OPENSSL_sk_pop_free(a: reinterpret_cast<OPENSSL_STACK *>(ca),
819 b: reinterpret_cast<void (*)(void *)>(q_X509_free));
820 });
821
822 // Convert to Qt types
823 auto *tlsKey = QTlsBackend::backend<TlsKeyOpenSSL>(o: *key);
824 if (!tlsKey || !tlsKey->fromEVP_PKEY(pkey)) {
825 qCWarning(lcTlsBackend, "Unable to convert private key");
826 return false;
827 }
828
829 *cert = certificateFromX509(x509);
830
831 if (caCertificates)
832 *caCertificates = stackOfX509ToQSslCertificates(x509: ca);
833
834 return true;
835}
836
837QSslError X509CertificateOpenSSL::openSSLErrorToQSslError(int errorCode, const QSslCertificate &cert)
838{
839 QSslError error;
840 switch (errorCode) {
841 case X509_V_OK:
842 // X509_V_OK is also reported if the peer had no certificate.
843 break;
844 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
845 error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
846 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
847 error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
848 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
849 error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
850 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
851 error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
852 case X509_V_ERR_CERT_NOT_YET_VALID:
853 error = QSslError(QSslError::CertificateNotYetValid, cert); break;
854 case X509_V_ERR_CERT_HAS_EXPIRED:
855 error = QSslError(QSslError::CertificateExpired, cert); break;
856 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
857 error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
858 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
859 error = QSslError(QSslError::InvalidNotAfterField, cert); break;
860 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
861 error = QSslError(QSslError::SelfSignedCertificate, cert); break;
862 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
863 error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
864 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
865 error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
866 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
867 error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
868 case X509_V_ERR_CERT_REVOKED:
869 error = QSslError(QSslError::CertificateRevoked, cert); break;
870 case X509_V_ERR_INVALID_CA:
871 error = QSslError(QSslError::InvalidCaCertificate, cert); break;
872 case X509_V_ERR_PATH_LENGTH_EXCEEDED:
873 error = QSslError(QSslError::PathLengthExceeded, cert); break;
874 case X509_V_ERR_INVALID_PURPOSE:
875 error = QSslError(QSslError::InvalidPurpose, cert); break;
876 case X509_V_ERR_CERT_UNTRUSTED:
877 error = QSslError(QSslError::CertificateUntrusted, cert); break;
878 case X509_V_ERR_CERT_REJECTED:
879 error = QSslError(QSslError::CertificateRejected, cert); break;
880 default:
881 error = QSslError(QSslError::UnspecifiedError, cert); break;
882 }
883 return error;
884}
885
886void X509CertificateOpenSSL::parseExtensions()
887{
888 extensions.clear();
889
890 if (!x509)
891 return;
892
893 int count = q_X509_get_ext_count(a: x509);
894 if (count <= 0)
895 return;
896
897 extensions.reserve(asize: count);
898
899 for (int i = 0; i < count; i++) {
900 X509_EXTENSION *ext = q_X509_get_ext(a: x509, b: i);
901 if (!ext) {
902 qCWarning(lcTlsBackend) << "Invalid (nullptr) extension at index" << i;
903 continue;
904 }
905
906 extensions << convertExtension(ext);
907 }
908
909 // Converting an extension may result in an error(s), clean them up:
910 QTlsBackendOpenSSL::clearErrorQueue();
911}
912
913X509CertificateBase::X509CertificateExtension X509CertificateOpenSSL::convertExtension(X509_EXTENSION *ext)
914{
915 Q_ASSERT(ext);
916
917 X509CertificateExtension result;
918
919 ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(a: ext);
920 if (!obj)
921 return result;
922
923 result.oid = QString::fromUtf8(ba: asn1ObjectId(object: obj));
924 result.name = QString::fromUtf8(ba: asn1ObjectName(object: obj));
925
926 result.critical = bool(q_X509_EXTENSION_get_critical(a: ext));
927
928 // Lets see if we have custom support for this one
929 QVariant extensionValue = x509ExtensionToValue(ext);
930 if (extensionValue.isValid()) {
931 result.value = extensionValue;
932 result.supported = true;
933 return result;
934 }
935
936 extensionValue = x509UnknownExtensionToValue(ext);
937 if (extensionValue.isValid())
938 result.value = extensionValue;
939
940 result.supported = false;
941
942 return result;
943}
944
945} // namespace QTlsPrivate
946
947QT_END_NAMESPACE
948

source code of qtbase/src/plugins/tls/openssl/qx509_openssl.cpp