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