diff options
Diffstat (limited to 'src/network/ssl')
33 files changed, 1142 insertions, 563 deletions
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h index 2068254a95..59d1f58482 100644 --- a/src/network/ssl/qasn1element_p.h +++ b/src/network/ssl/qasn1element_p.h @@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE #define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1") #define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1") #define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1") +#define DH_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.3.1") // These are mostly from the RFC for PKCS#5 // PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B diff --git a/src/network/ssl/qdtls.h b/src/network/ssl/qdtls.h index 8505b00d5e..d057eadf19 100644 --- a/src/network/ssl/qdtls.h +++ b/src/network/ssl/qdtls.h @@ -48,7 +48,9 @@ #include <QtCore/qcryptographichash.h> #include <QtCore/qobject.h> +#ifndef Q_CLANG_QDOC QT_REQUIRE_CONFIG(dtls); +#endif QT_BEGIN_NAMESPACE diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 19d99bc489..6b5dbdfeac 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -71,7 +71,8 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); \value Rsa The RSA algorithm. \value Dsa The DSA algorithm. - \value Ec The Elliptic Curve algorithm + \value Ec The Elliptic Curve algorithm. + \value Dh The Diffie-Hellman algorithm. \value Opaque A key that should be treated as a 'black box' by QSslKey. The opaque key facility allows applications to add support for facilities @@ -116,8 +117,8 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); Describes the protocol of the cipher. - \value SslV3 SSLv3. When using the WinRT backend this option will also enable TLSv1.0 - \value SslV2 SSLv2. Note, SSLv2 support was removed in OpenSSL 1.1. + \value SslV3 SSLv3; not supported by QSslSocket. + \value SslV2 SSLv2; not supported by QSslSocket. \value TlsV1_0 TLSv1.0 \value TlsV1_0OrLater TLSv1.0 and later versions. This option is not available when using the WinRT backend due to platform limitations. \value TlsV1 Obsolete, means the same as TlsV1_0 @@ -132,19 +133,9 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); \value TlsV1_3 TLSv1.3. (Since Qt 5.12) \value TlsV1_3OrLater TLSv1.3 and later versions. (Since Qt 5.12) \value UnknownProtocol The cipher's protocol cannot be determined. - \value AnyProtocol The socket understands SSLv2, SSLv3, TLSv1.0 and all - supported later versions of TLS. This value is used by QSslSocket only. - \value TlsV1SslV3 On the client side, this will send - a TLS 1.0 Client Hello, enabling TLSv1_0 and SSLv3 connections. - On the server side, this will enable both SSLv3 and TLSv1_0 connections. - \value SecureProtocols The default option, using protocols known to be secure; - currently behaves similar to TlsV1Ssl3 except denying SSLv3 connections that does - not upgrade to TLS. - - \note most servers understand both SSL and TLS, but it is recommended to use - TLS only for security reasons. However, SSL and TLS are not compatible with - each other: if you get unexpected handshake failures, verify that you chose - the correct setting for your protocol. + \value AnyProtocol Any supported protocol. This value is used by QSslSocket only. + \value TlsV1SslV3 Same as TlsV1_0. + \value SecureProtocols The default option, using protocols known to be secure. */ /*! diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 60362cb410..5c25e4e105 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -62,7 +62,8 @@ namespace QSsl { Opaque, Rsa, Dsa, - Ec + Ec, + Dh, }; enum AlternativeNameEntryType { diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp index fa87cfeaaf..57a4dca08f 100644 --- a/src/network/ssl/qsslcertificate_openssl.cpp +++ b/src/network/ssl/qsslcertificate_openssl.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE // forward declaration -static QMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name); +static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name); bool QSslCertificate::operator==(const QSslCertificate &other) const { @@ -615,16 +615,16 @@ QByteArray QSslCertificatePrivate::asn1ObjectName(ASN1_OBJECT *object) return asn1ObjectId(object); } -static QMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name) +static QMultiMap<QByteArray, QString> _q_mapFromX509Name(X509_NAME *name) { - QMap<QByteArray, QString> info; + QMultiMap<QByteArray, QString> info; for (int i = 0; i < q_X509_NAME_entry_count(name); ++i) { X509_NAME_ENTRY *e = q_X509_NAME_get_entry(name, i); QByteArray name = QSslCertificatePrivate::asn1ObjectName(q_X509_NAME_ENTRY_get_object(e)); unsigned char *data = nullptr; int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e)); - info.insertMulti(name, QString::fromUtf8((char*)data, size)); + info.insert(name, QString::fromUtf8((char*)data, size)); #if QT_CONFIG(opensslv11) q_CRYPTO_free(data, nullptr, 0); #else diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h index dfdceab502..2dbc4145af 100644 --- a/src/network/ssl/qsslcertificate_p.h +++ b/src/network/ssl/qsslcertificate_p.h @@ -102,8 +102,8 @@ public: QByteArray versionString; QByteArray serialNumberString; - QMap<QByteArray, QString> issuerInfo; - QMap<QByteArray, QString> subjectInfo; + QMultiMap<QByteArray, QString> issuerInfo; + QMultiMap<QByteArray, QString> subjectInfo; QDateTime notValidAfter; QDateTime notValidBefore; diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 3f732b4646..4697a5f90f 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -228,7 +228,8 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->nextAllowedProtocols == other.d->nextAllowedProtocols && d->nextNegotiatedProtocol == other.d->nextNegotiatedProtocol && d->nextProtocolNegotiationStatus == other.d->nextProtocolNegotiationStatus && - d->dtlsCookieEnabled == other.d->dtlsCookieEnabled; + d->dtlsCookieEnabled == other.d->dtlsCookieEnabled && + d->ocspStaplingEnabled == other.d->ocspStaplingEnabled; } /*! @@ -272,7 +273,8 @@ bool QSslConfiguration::isNull() const d->preSharedKeyIdentityHint.isNull() && d->nextAllowedProtocols.isEmpty() && d->nextNegotiatedProtocol.isNull() && - d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone); + d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone && + d->ocspStaplingEnabled == false); } /*! @@ -1094,6 +1096,37 @@ void QSslConfiguration::setDefaultDtlsConfiguration(const QSslConfiguration &con #endif // dtls +/*! + \since 5.13 + If \a enabled is true, client QSslSocket will send a certificate status request + to its peer when initiating a handshake. During the handshake QSslSocket will + verify the server's response. This value must be set before the handshake + starts. + + \sa ocspStaplingEnabled() +*/ +void QSslConfiguration::setOcspStaplingEnabled(bool enabled) +{ +#if QT_CONFIG(ocsp) + d->ocspStaplingEnabled = enabled; +#else + if (enabled) + qCWarning(lcSsl, "Enabling OCSP-stapling requires the feature 'ocsp'"); +#endif // ocsp +} + +/*! + \since 5.13 + Returns true if OCSP stapling was enabled by setOCSPStaplingEnabled(), + otherwise false (which is the default value). + + \sa setOcspStaplingEnabled() +*/ +bool QSslConfiguration::ocspStaplingEnabled() const +{ + return d->ocspStaplingEnabled; +} + /*! \internal */ bool QSslConfigurationPrivate::peerSessionWasShared(const QSslConfiguration &configuration) { diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 454ac0cee3..8f53e25a53 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -170,6 +170,9 @@ public: static void setDefaultDtlsConfiguration(const QSslConfiguration &configuration); #endif // dtls + void setOcspStaplingEnabled(bool enable); + bool ocspStaplingEnabled() const; + enum NextProtocolNegotiationStatus { NextProtocolNegotiationNone, NextProtocolNegotiationNegotiated, diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index 6c23165c6a..83126bb9a0 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -143,6 +143,12 @@ public: const bool dtlsCookieEnabled = false; #endif // dtls +#if QT_CONFIG(ocsp) + bool ocspStaplingEnabled = false; +#else + const bool ocspStaplingEnabled = false; +#endif + // in qsslsocket.cpp: static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp index 35cca9f01a..e81e5582f4 100644 --- a/src/network/ssl/qsslcontext_openssl.cpp +++ b/src/network/ssl/qsslcontext_openssl.cpp @@ -243,12 +243,28 @@ QString QSslContext::errorString() const return errorStr; } +#if QT_CONFIG(ocsp) +extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *); // Defined in qsslsocket_openssl.cpp. +#endif // ocsp // static void QSslContext::applyBackendConfig(QSslContext *sslContext) { - if (sslContext->sslConfiguration.backendConfiguration().isEmpty()) + const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration(); + if (conf.isEmpty()) return; +#if QT_CONFIG(ocsp) + auto ocspResponsePos = conf.find("Qt-OCSP-response"); + if (ocspResponsePos != conf.end()) { + // This is our private, undocumented configuration option, existing only for + // the purpose of testing OCSP status responses. We don't even check this + // callback was set. If no - the test must fail. + q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, qt_OCSP_status_server_callback); + if (conf.size() == 1) + return; + } +#endif // ocsp + #if OPENSSL_VERSION_NUMBER >= 0x10002000L if (QSslSocket::sslLibraryVersionNumber() >= 0x10002000L) { QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free); @@ -256,8 +272,10 @@ void QSslContext::applyBackendConfig(QSslContext *sslContext) q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx); q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE); - const auto &backendConfig = sslContext->sslConfiguration.backendConfiguration(); - for (auto i = backendConfig.constBegin(); i != backendConfig.constEnd(); ++i) { + for (auto i = conf.constBegin(); i != conf.constEnd(); ++i) { + if (i.key() == "Qt-OCSP-response") // This never goes to SSL_CONF_cmd(). + continue; + if (!i.value().canConvert(QMetaType::QByteArray)) { sslContext->errorCode = QSslError::UnspecifiedError; sslContext->errorStr = msgErrorSettingBackendConfig( diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp index c96a48dac1..21a5c779f7 100644 --- a/src/network/ssl/qsslcontext_openssl11.cpp +++ b/src/network/ssl/qsslcontext_openssl11.cpp @@ -95,6 +95,10 @@ init_context: // SSL 2 is no longer supported, but chosen deliberately -> error sslContext->ctx = nullptr; unsupportedProtocol = true; + } else if (sslContext->sslConfiguration.protocol() == QSsl::SslV3) { + // SSL 3 is no longer supported, but chosen deliberately -> error + sslContext->ctx = nullptr; + unsupportedProtocol = true; } else { switch (sslContext->sslConfiguration.protocol()) { case QSsl::DtlsV1_0: @@ -151,11 +155,6 @@ init_context: long maxVersion = anyVersion; switch (sslContext->sslConfiguration.protocol()) { - // The single-protocol versions first: - case QSsl::SslV3: - minVersion = SSL3_VERSION; - maxVersion = SSL3_VERSION; - break; case QSsl::TlsV1_0: minVersion = TLS1_VERSION; maxVersion = TLS1_VERSION; @@ -181,9 +180,6 @@ init_context: // Ranges: case QSsl::TlsV1SslV3: case QSsl::AnyProtocol: - minVersion = SSL3_VERSION; - maxVersion = 0; - break; case QSsl::SecureProtocols: case QSsl::TlsV1_0OrLater: minVersion = TLS1_VERSION; @@ -227,8 +223,9 @@ init_context: break; #endif // TLS1_3_VERSION case QSsl::SslV2: - // This protocol is not supported by OpenSSL 1.1 and we handle - // it as an error (see the code above). + case QSsl::SslV3: + // These protocols are not supported, and we handle + // them as an error (see the code above). Q_UNREACHABLE(); break; case QSsl::UnknownProtocol: diff --git a/src/network/ssl/qsslcontext_opensslpre11.cpp b/src/network/ssl/qsslcontext_opensslpre11.cpp index 34537d1da4..956c5c32ec 100644 --- a/src/network/ssl/qsslcontext_opensslpre11.cpp +++ b/src/network/ssl/qsslcontext_opensslpre11.cpp @@ -115,32 +115,19 @@ init_context: break; #endif // dtls case QSsl::SslV2: -#ifndef OPENSSL_NO_SSL2 - sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method()); -#else - // SSL 2 not supported by the system, but chosen deliberately -> error - sslContext->ctx = 0; - unsupportedProtocol = true; -#endif - break; case QSsl::SslV3: -#ifndef OPENSSL_NO_SSL3_METHOD - sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method()); -#else - // SSL 3 not supported by the system, but chosen deliberately -> error + // We don't support SSLv2 / SSLv3. sslContext->ctx = 0; unsupportedProtocol = true; -#endif break; case QSsl::SecureProtocols: // SSLv2 and SSLv3 will be disabled by SSL options // But we need q_SSLv23_server_method() otherwise AnyProtocol will be unable to connect on Win32. - case QSsl::TlsV1SslV3: - // SSLv2 will will be disabled by SSL options case QSsl::AnyProtocol: default: sslContext->ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method()); break; + case QSsl::TlsV1SslV3: case QSsl::TlsV1_0: sslContext->ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method()); break; @@ -212,12 +199,9 @@ init_context: long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions); q_SSL_CTX_set_options(sslContext->ctx, options); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L // Tell OpenSSL to release memory early // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html - if (q_SSLeay() >= 0x10000000L) - q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS); -#endif + q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS); // Initialize ciphers QByteArray cipherString; diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp index 3f79d1a037..74ff6987d2 100644 --- a/src/network/ssl/qsslerror.cpp +++ b/src/network/ssl/qsslerror.cpp @@ -86,6 +86,18 @@ \value UnspecifiedError \value NoSslSupport \value CertificateBlacklisted + \value OcspNoResponseFound + \value OcspMalformedRequest + \value OcspMalformedResponse + \value OcspInternalError + \value OcspTryLater + \value OcspSigRequred + \value OcspUnauthorized + \value OcspResponseCannotBeTrusted + \value OcspResponseCertIdUnknown + \value OcspResponseExpired + \value OcspStatusUnknown + \sa QSslError::errorString() */ @@ -292,6 +304,39 @@ QString QSslError::errorString() const case CertificateBlacklisted: errStr = QSslSocket::tr("The peer certificate is blacklisted"); break; + case OcspNoResponseFound: + errStr = QSslSocket::tr("No OCSP status response found"); + break; + case OcspMalformedRequest: + errStr = QSslSocket::tr("The OCSP status request had invalid syntax"); + break; + case OcspMalformedResponse: + errStr = QSslSocket::tr("OCSP response contains an unexpected number of SingleResponse structures"); + break; + case OcspInternalError: + errStr = QSslSocket::tr("OCSP responder reached an inconsistent internal state"); + break; + case OcspTryLater: + errStr = QSslSocket::tr("OCSP responder was unable to return a status for the requested certificate"); + break; + case OcspSigRequred: + errStr = QSslSocket::tr("The server requires the client to sign the OCSP request in order to construct a response"); + break; + case OcspUnauthorized: + errStr = QSslSocket::tr("The client is not authorized to request OCSP status from this server"); + break; + case OcspResponseCannotBeTrusted: + errStr = QSslSocket::tr("OCSP reponder's identity cannot be verified"); + break; + case OcspResponseCertIdUnknown: + errStr = QSslSocket::tr("The identity of a certificate in an OCSP response cannot be established"); + break; + case OcspResponseExpired: + errStr = QSslSocket::tr("The certificate status response has expired"); + break; + case OcspStatusUnknown: + errStr = QSslSocket::tr("The certificate's status is unknown"); + break; default: errStr = QSslSocket::tr("Unknown error"); break; diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h index d7c959423d..513b8afd7f 100644 --- a/src/network/ssl/qsslerror.h +++ b/src/network/ssl/qsslerror.h @@ -80,6 +80,18 @@ public: HostNameMismatch, NoSslSupport, CertificateBlacklisted, + CertificateStatusUnknown, + OcspNoResponseFound, + OcspMalformedRequest, + OcspMalformedResponse, + OcspInternalError, + OcspTryLater, + OcspSigRequred, + OcspUnauthorized, + OcspResponseCannotBeTrusted, + OcspResponseCertIdUnknown, + OcspResponseExpired, + OcspStatusUnknown, UnspecifiedError = -1 }; diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp index 9a43e67772..99c1a39c73 100644 --- a/src/network/ssl/qsslkey_openssl.cpp +++ b/src/network/ssl/qsslkey_openssl.cpp @@ -69,6 +69,11 @@ void QSslKeyPrivate::clear(bool deep) q_DSA_free(dsa); dsa = nullptr; } + if (algorithm == QSsl::Dh && dh) { + if (deep) + q_DH_free(dh); + dh = nullptr; + } #ifndef OPENSSL_NO_EC if (algorithm == QSsl::Ec && ec) { if (deep) @@ -105,6 +110,12 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey) type = QSsl::PrivateKey; dsa = q_EVP_PKEY_get1_DSA(pkey); return true; + } else if (keyType == EVP_PKEY_DH) { + isNull = false; + algorithm = QSsl::Dh; + type = QSsl::PrivateKey; + dh = q_EVP_PKEY_get1_DH(pkey); + return true; } #ifndef OPENSSL_NO_EC else if (keyType == EVP_PKEY_EC) { @@ -160,6 +171,15 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase); if (dsa && dsa == result) isNull = false; + } else if (algorithm == QSsl::Dh) { + EVP_PKEY *result = (type == QSsl::PublicKey) + ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase) + : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase); + if (result) + dh = q_EVP_PKEY_get1_DH(result); + if (dh) + isNull = false; + q_EVP_PKEY_free(result); #ifndef OPENSSL_NO_EC } else if (algorithm == QSsl::Ec) { EC_KEY *result = (type == QSsl::PublicKey) @@ -181,6 +201,7 @@ int QSslKeyPrivate::length() const switch (algorithm) { case QSsl::Rsa: return q_RSA_bits(rsa); case QSsl::Dsa: return q_DSA_bits(dsa); + case QSsl::Dh: return q_DH_bits(dh); #ifndef OPENSSL_NO_EC case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec)); #endif @@ -215,7 +236,7 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const fail = true; } else { if (!q_PEM_write_bio_RSAPrivateKey( - bio, rsa, cipher, const_cast<uchar *>((const uchar *)passPhrase.data()), + bio, rsa, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr)) { fail = true; } @@ -226,20 +247,33 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const fail = true; } else { if (!q_PEM_write_bio_DSAPrivateKey( - bio, dsa, cipher, const_cast<uchar *>((const uchar *)passPhrase.data()), + bio, dsa, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr)) { fail = true; } } + } else if (algorithm == QSsl::Dh) { + EVP_PKEY *result = q_EVP_PKEY_new(); + if (!result || !q_EVP_PKEY_set1_DH(result, dh)) { + fail = true; + } else if (type == QSsl::PublicKey) { + if (!q_PEM_write_bio_PUBKEY(bio, result)) + fail = true; + } else if (!q_PEM_write_bio_PrivateKey( + bio, result, cipher, (uchar *)passPhrase.data(), + passPhrase.size(), nullptr, nullptr)) { + fail = true; + } + q_EVP_PKEY_free(result); #ifndef OPENSSL_NO_EC } else if (algorithm == QSsl::Ec) { if (type == QSsl::PublicKey) { if (!q_PEM_write_bio_EC_PUBKEY(bio, ec)) fail = true; } else { - if (!q_PEM_write_bio_ECPrivateKey(bio, ec, cipher, - const_cast<uchar *>((const uchar *)passPhrase.data()), - passPhrase.size(), nullptr, nullptr)) { + if (!q_PEM_write_bio_ECPrivateKey( + bio, ec, cipher, (uchar *)passPhrase.data(), + passPhrase.size(), nullptr, nullptr)) { fail = true; } } @@ -267,6 +301,8 @@ Qt::HANDLE QSslKeyPrivate::handle() const return Qt::HANDLE(rsa); case QSsl::Dsa: return Qt::HANDLE(dsa); + case QSsl::Dh: + return Qt::HANDLE(dh); #ifndef OPENSSL_NO_EC case QSsl::Ec: return Qt::HANDLE(ec); diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp index 28e3e2efd8..b29b38beab 100644 --- a/src/network/ssl/qsslkey_p.cpp +++ b/src/network/ssl/qsslkey_p.cpp @@ -116,6 +116,8 @@ QByteArray QSslKeyPrivate::pemHeader() const return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----"); else if (algorithm == QSsl::Ec) return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----"); + else if (algorithm == QSsl::Dh) + return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----"); Q_UNREACHABLE(); return QByteArray(); @@ -141,6 +143,8 @@ QByteArray QSslKeyPrivate::pemFooter() const return QByteArrayLiteral("-----END DSA PRIVATE KEY-----"); else if (algorithm == QSsl::Ec) return QByteArrayLiteral("-----END EC PRIVATE KEY-----"); + else if (algorithm == QSsl::Dh) + return QByteArrayLiteral("-----END PRIVATE KEY-----"); Q_UNREACHABLE(); return QByteArray(); @@ -535,7 +539,9 @@ QDebug operator<<(QDebug debug, const QSslKey &key) debug << "QSslKey(" << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") << ", " << (key.algorithm() == QSsl::Opaque ? "OPAQUE" : - (key.algorithm() == QSsl::Rsa ? "RSA" : ((key.algorithm() == QSsl::Dsa) ? "DSA" : "EC"))) + (key.algorithm() == QSsl::Rsa ? "RSA" : + (key.algorithm() == QSsl::Dsa ? "DSA" : + (key.algorithm() == QSsl::Dh ? "DH" : "EC")))) << ", " << key.length() << ')'; return debug; diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h index 7ae2cc740b..06403b5479 100644 --- a/src/network/ssl/qsslkey_p.h +++ b/src/network/ssl/qsslkey_p.h @@ -116,6 +116,7 @@ public: EVP_PKEY *opaque; RSA *rsa; DSA *dsa; + DH *dh; #ifndef OPENSSL_NO_EC EC_KEY *ec; #endif @@ -129,7 +130,7 @@ public: QAtomicInt ref; private: - Q_DISABLE_COPY(QSslKeyPrivate) + Q_DISABLE_COPY_MOVE(QSslKeyPrivate) }; QT_END_NAMESPACE diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp index a13275f3bb..5ebd8ac3bd 100644 --- a/src/network/ssl/qsslkey_qt.cpp +++ b/src/network/ssl/qsslkey_qt.cpp @@ -165,6 +165,7 @@ static int extractPkcs8KeyLength(const QVector<QAsn1Element> &items, QSslKeyPriv switch (algorithm){ case QSsl::Rsa: return "RSA"; case QSsl::Dsa: return "DSA"; + case QSsl::Dh: return "DH"; case QSsl::Ec: return "EC"; case QSsl::Opaque: return "Opaque"; } @@ -217,6 +218,21 @@ static int extractPkcs8KeyLength(const QVector<QAsn1Element> &items, QSslKeyPriv if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType) return -1; keyLength = numberOfBits(dsaInfo[0].value()); + } else if (value == DH_ENCRYPTION_OID) { + if (Q_UNLIKELY(that->algorithm != QSsl::Dh)) { + // As above for RSA. + qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm) + << "\nLoading will fail."; + return -1; + } + // DH's structure is documented here: + // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9. + if (pkcs8Info[1].type() != QAsn1Element::SequenceType) + return -1; + const QVector<QAsn1Element> dhInfo = pkcs8Info[1].toVector(); + if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType) + return -1; + keyLength = numberOfBits(dhInfo[0].value()); } else { // in case of unexpected formats: qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value @@ -268,6 +284,16 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhra if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType) return; keyLength = numberOfBits(params[0].value()); + } else if (algorithm == QSsl::Dh) { + if (infoItems[0].toObjectId() != DH_ENCRYPTION_OID) + return; + if (infoItems[1].type() != QAsn1Element::SequenceType) + return; + // key params + const QVector<QAsn1Element> params = infoItems[1].toVector(); + if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType) + return; + keyLength = numberOfBits(params[0].value()); } else if (algorithm == QSsl::Ec) { if (infoItems[0].toObjectId() != EC_ENCRYPTION_OID) return; @@ -307,6 +333,12 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhra if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType) return; keyLength = numberOfBits(items[1].value()); + } else if (algorithm == QSsl::Dh) { + if (versionHex != "00") + return; + if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType) + return; + keyLength = numberOfBits(items[1].value()); } else if (algorithm == QSsl::Ec) { if (versionHex != "01") return; diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 4a9d054c0d..068dfb9f2d 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -133,7 +133,8 @@ \list \li The socket's cryptographic cipher suite can be customized before - the handshake phase with setCiphers() and setDefaultCiphers(). + the handshake phase with QSslConfiguration::setCiphers() + and QSslConfiguration::setDefaultCiphers(). \li The socket's local certificate and private key can be customized before the handshake phase with setLocalCertificate() and setPrivateKey(). @@ -906,7 +907,8 @@ void QSslSocket::abort() time without notice. \sa localCertificate(), peerCertificate(), peerCertificateChain(), - sessionCipher(), privateKey(), ciphers(), caCertificates() + sessionCipher(), privateKey(), QSslConfiguration::ciphers(), + QSslConfiguration::caCertificates() */ QSslConfiguration QSslSocket::sslConfiguration() const { @@ -930,7 +932,8 @@ QSslConfiguration QSslSocket::sslConfiguration() const It is not possible to set the SSL-state related fields. - \sa setLocalCertificate(), setPrivateKey(), setCaCertificates(), setCiphers() + \sa setLocalCertificate(), setPrivateKey(), QSslConfiguration::setCaCertificates(), + QSslConfiguration::setCiphers() */ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) { @@ -952,6 +955,9 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.nextAllowedProtocols = configuration.allowedNextProtocols(); d->configuration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol(); d->configuration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus(); +#if QT_CONFIG(ocsp) + d->configuration.ocspStaplingEnabled = configuration.ocspStaplingEnabled(); +#endif // if the CA certificates were set explicitly (either via // QSslConfiguration::setCaCertificates() or QSslSocket::setCaCertificates(), @@ -1113,8 +1119,10 @@ QList<QSslCertificate> QSslSocket::peerCertificateChain() const session cipher. This ordered list must be in place before the handshake phase begins. - \sa ciphers(), setCiphers(), setDefaultCiphers(), defaultCiphers(), - supportedCiphers() + \sa QSslConfiguration::ciphers(), QSslConfiguration::setCiphers(), + QSslConfiguration::setDefaultCiphers(), + QSslConfiguration::defaultCiphers(), + QSslConfiguration::supportedCiphers() */ QSslCipher QSslSocket::sessionCipher() const { @@ -1376,7 +1384,8 @@ bool QSslSocket::addCaCertificates(const QString &path, QSsl::EncodingFormat for To add multiple certificates, use addCaCertificates(). - \sa caCertificates(), setCaCertificates() + \sa QSslConfiguration::caCertificates(), + QSslConfiguration::setCaCertificates() */ void QSslSocket::addCaCertificate(const QSslCertificate &certificate) { @@ -1391,7 +1400,7 @@ void QSslSocket::addCaCertificate(const QSslCertificate &certificate) For more precise control, use addCaCertificate(). - \sa caCertificates(), addDefaultCaCertificate() + \sa QSslConfiguration::caCertificates(), addDefaultCaCertificate() */ void QSslSocket::addCaCertificates(const QList<QSslCertificate> &certificates) { @@ -1454,7 +1463,8 @@ QList<QSslCertificate> QSslSocket::caCertificates() const Each SSL socket's CA certificate database is initialized to the default CA certificate database. - \sa defaultCaCertificates(), addCaCertificates(), addDefaultCaCertificate() + \sa QSslConfiguration::defaultCaCertificates(), addCaCertificates(), + addDefaultCaCertificate() */ bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat encoding, QRegExp::PatternSyntax syntax) @@ -1467,7 +1477,7 @@ bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFor SSL socket's CA certificate database is initialized to the default CA certificate database. - \sa defaultCaCertificates(), addCaCertificates() + \sa QSslConfiguration::defaultCaCertificates(), addCaCertificates() */ void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate) { @@ -1479,7 +1489,7 @@ void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate) SSL socket's CA certificate database is initialized to the default CA certificate database. - \sa defaultCaCertificates(), addCaCertificates() + \sa QSslConfiguration::defaultCaCertificates(), addCaCertificates() */ void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certificates) { @@ -1974,6 +1984,7 @@ void QSslSocket::connectToHost(const QString &hostName, quint16 port, OpenMode o d->createPlainSocket(openMode); } #ifndef QT_NO_NETWORKPROXY + d->plainSocket->setProtocolTag(d->protocolTag); d->plainSocket->setProxy(proxy()); #endif QIODevice::open(openMode); @@ -2324,6 +2335,9 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri #if QT_CONFIG(dtls) ptr->dtlsCookieEnabled = global->dtlsCookieEnabled; #endif +#if QT_CONFIG(ocsp) + ptr->ocspStaplingEnabled = global->ocspStaplingEnabled; +#endif } /*! diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp index 65d98758ac..9c3c98e390 100644 --- a/src/network/ssl/qsslsocket_mac.cpp +++ b/src/network/ssl/qsslsocket_mac.cpp @@ -89,7 +89,7 @@ struct EphemeralSecKeychain ~EphemeralSecKeychain(); SecKeychainRef keychain = nullptr; - Q_DISABLE_COPY(EphemeralSecKeychain) + Q_DISABLE_COPY_MOVE(EphemeralSecKeychain) }; EphemeralSecKeychain::EphemeralSecKeychain() @@ -993,9 +993,6 @@ void QSslSocketBackendPrivate::destroySslContext() context.reset(nullptr); } -static QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase); - - bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription, QAbstractSocket::SocketError &errorCode) { Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)"); @@ -1110,6 +1107,12 @@ bool QSslSocketBackendPrivate::setSessionProtocol() return false; } + // SslV3 is unsupported. + if (configuration.protocol == QSsl::SslV3) { + qCDebug(lcSsl) << "protocol QSsl::SslV3 is disabled"; + return false; + } + // SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported. // Calling SSLSetProtocolVersionMax/Min with any of these two constants results // in errInvalidParam and a failure to set the protocol version. This means @@ -1124,14 +1127,7 @@ bool QSslSocketBackendPrivate::setSessionProtocol() OSStatus err = errSecSuccess; - if (configuration.protocol == QSsl::SslV3) { - #ifdef QSSLSOCKET_DEBUG - qCDebug(lcSsl) << plainSocket << "requesting : SSLv3"; - #endif - err = SSLSetProtocolVersionMin(context, kSSLProtocol3); - if (err == errSecSuccess) - err = SSLSetProtocolVersionMax(context, kSSLProtocol3); - } else if (configuration.protocol == QSsl::TlsV1_0) { + if (configuration.protocol == QSsl::TlsV1_0) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0"; #endif @@ -1156,17 +1152,16 @@ bool QSslSocketBackendPrivate::setSessionProtocol() #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << plainSocket << "requesting : any"; #endif - // kSSLProtocol3, since kSSLProtocol2 is disabled: - err = SSLSetProtocolVersionMin(context, kSSLProtocol3); + err = SSLSetProtocolVersionMin(context, kTLSProtocol1); if (err == errSecSuccess) err = SSLSetProtocolVersionMax(context, kTLSProtocol12); } else if (configuration.protocol == QSsl::TlsV1SslV3) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2"; #endif - err = SSLSetProtocolVersionMin(context, kSSLProtocol3); + err = SSLSetProtocolVersionMin(context, kTLSProtocol1); if (err == errSecSuccess) - err = SSLSetProtocolVersionMax(context, kTLSProtocol12); + err = SSLSetProtocolVersionMax(context, kTLSProtocol1); } else if (configuration.protocol == QSsl::SecureProtocols) { #ifdef QSSLSOCKET_DEBUG qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2"; @@ -1220,7 +1215,7 @@ bool QSslSocketBackendPrivate::verifySessionProtocol() const if (configuration.protocol == QSsl::AnyProtocol) protocolOk = true; else if (configuration.protocol == QSsl::TlsV1SslV3) - protocolOk = (sessionProtocol() >= QSsl::SslV3); + protocolOk = (sessionProtocol() == QSsl::TlsV1_0); else if (configuration.protocol == QSsl::SecureProtocols) protocolOk = (sessionProtocol() >= QSsl::TlsV1_0); else if (configuration.protocol == QSsl::TlsV1_0OrLater) @@ -1511,264 +1506,4 @@ bool QSslSocketBackendPrivate::startHandshake() } } -/* - PKCS12 helpers. -*/ - -static QAsn1Element wrap(quint8 type, const QAsn1Element &child) -{ - QByteArray value; - QDataStream stream(&value, QIODevice::WriteOnly); - child.write(stream); - return QAsn1Element(type, value); -} - -static QAsn1Element _q_PKCS7_data(const QByteArray &data) -{ - QVector<QAsn1Element> items; - items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1"); - items << wrap(QAsn1Element::Context0Type, - QAsn1Element(QAsn1Element::OctetStringType, data)); - return QAsn1Element::fromVector(items); -} - -/*! - PKCS #12 key derivation. - - Some test vectors: - http://www.drh-consultancy.demon.co.uk/test.txt -*/ -static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r) -{ - const int u = 20; - const int v = 64; - - // password formatting - QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0'); - char *p = passUnicode.data(); - for (int i = 0; i < passPhrase.size(); ++i) { - quint16 ch = passPhrase[i].unicode(); - *(p++) = (ch & 0xff00) >> 8; - *(p++) = (ch & 0xff); - } - - // prepare I - QByteArray D(64, id); - QByteArray S, P; - const int sSize = v * ((salt.size() + v - 1) / v); - S.resize(sSize); - for (int i = 0; i < sSize; ++i) { - S[i] = salt[i % salt.size()]; - } - const int pSize = v * ((passUnicode.size() + v - 1) / v); - P.resize(pSize); - for (int i = 0; i < pSize; ++i) { - P[i] = passUnicode[i % passUnicode.size()]; - } - QByteArray I = S + P; - - // apply hashing - const int c = (n + u - 1) / u; - QByteArray A; - QByteArray B; - B.resize(v); - QCryptographicHash hash(QCryptographicHash::Sha1); - for (int i = 0; i < c; ++i) { - // hash r iterations - QByteArray Ai = D + I; - for (int j = 0; j < r; ++j) { - hash.reset(); - hash.addData(Ai); - Ai = hash.result(); - } - - for (int j = 0; j < v; ++j) { - B[j] = Ai[j % u]; - } - - // modify I as Ij = (Ij + B + 1) modulo 2^v - for (int p = 0; p < I.size(); p += v) { - quint8 carry = 1; - for (int j = v - 1; j >= 0; --j) { - quint16 v = quint8(I[p+j]) + quint8(B[j]) + carry; - I[p+j] = v & 0xff; - carry = (v & 0xff00) >> 8; - } - } - A += Ai; - } - return A.left(n); -} - -static QByteArray _q_PKCS12_salt() -{ - QByteArray salt; - salt.resize(8); - for (int i = 0; i < salt.size(); ++i) { - salt[i] = (qrand() & 0xff); - } - return salt; -} - -static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert) -{ - QVector<QAsn1Element> items; - items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3"); - - // certificate - QVector<QAsn1Element> certItems; - certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1"); - certItems << wrap(QAsn1Element::Context0Type, - QAsn1Element(QAsn1Element::OctetStringType, cert.toDer())); - items << wrap(QAsn1Element::Context0Type, - QAsn1Element::fromVector(certItems)); - - // local key id - const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1); - QVector<QAsn1Element> idItems; - idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21"); - idItems << wrap(QAsn1Element::SetType, - QAsn1Element(QAsn1Element::OctetStringType, localKeyId)); - items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems)); - - // dump - QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items)); - QByteArray ba; - QDataStream stream(&ba, QIODevice::WriteOnly); - root.write(stream); - return ba; -} - -static QAsn1Element _q_PKCS12_key(const QSslKey &key) -{ - Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa); - - QVector<QAsn1Element> keyItems; - keyItems << QAsn1Element::fromInteger(0); - QVector<QAsn1Element> algoItems; - if (key.algorithm() == QSsl::Rsa) - algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID); - else if (key.algorithm() == QSsl::Dsa) - algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID); - algoItems << QAsn1Element(QAsn1Element::NullType); - keyItems << QAsn1Element::fromVector(algoItems); - keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer()); - return QAsn1Element::fromVector(keyItems); -} - -static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId) -{ - const int iterations = 2048; - QByteArray salt = _q_PKCS12_salt(); - QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations); - QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations); - - // prepare and encrypt data - QByteArray plain; - QDataStream plainStream(&plain, QIODevice::WriteOnly); - _q_PKCS12_key(key).write(plainStream); - QByteArray crypted = QSslKeyPrivate::encrypt(QSslKeyPrivate::DesEde3Cbc, - plain, cKey, cIv); - - QVector<QAsn1Element> items; - items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2"); - - // key - QVector<QAsn1Element> keyItems; - QVector<QAsn1Element> algoItems; - algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3"); - QVector<QAsn1Element> paramItems; - paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt); - paramItems << QAsn1Element::fromInteger(iterations); - algoItems << QAsn1Element::fromVector(paramItems); - keyItems << QAsn1Element::fromVector(algoItems); - keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted); - items << wrap(QAsn1Element::Context0Type, - QAsn1Element::fromVector(keyItems)); - - // local key id - QVector<QAsn1Element> idItems; - idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21"); - idItems << wrap(QAsn1Element::SetType, - QAsn1Element(QAsn1Element::OctetStringType, localKeyId)); - items << wrap(QAsn1Element::SetType, - QAsn1Element::fromVector(idItems)); - - // dump - QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items)); - QByteArray ba; - QDataStream stream(&ba, QIODevice::WriteOnly); - root.write(stream); - return ba; -} - -static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase) -{ - QVector<QAsn1Element> items; - - // certs - for (int i = 0; i < certs.size(); ++i) - items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i])); - - // key - const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1); - items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId)); - - // dump - QAsn1Element root = QAsn1Element::fromVector(items); - QByteArray ba; - QDataStream stream(&ba, QIODevice::WriteOnly); - root.write(stream); - return ba; -} - -static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase) -{ - const int iterations = 2048; - - // salt generation - QByteArray macSalt = _q_PKCS12_salt(); - QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations); - - // HMAC calculation - QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key); - hmac.addData(data); - - QVector<QAsn1Element> algoItems; - algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26"); - algoItems << QAsn1Element(QAsn1Element::NullType); - - QVector<QAsn1Element> digestItems; - digestItems << QAsn1Element::fromVector(algoItems); - digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result()); - - QVector<QAsn1Element> macItems; - macItems << QAsn1Element::fromVector(digestItems); - macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt); - macItems << QAsn1Element::fromInteger(iterations); - return QAsn1Element::fromVector(macItems); -} - -QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase) -{ - QVector<QAsn1Element> items; - - // version - items << QAsn1Element::fromInteger(3); - - // auth safe - const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase); - items << _q_PKCS7_data(data); - - // HMAC - items << _q_PKCS12_mac(data, passPhrase); - - // dump - QAsn1Element root = QAsn1Element::fromVector(items); - QByteArray ba; - QDataStream stream(&ba, QIODevice::WriteOnly); - root.write(stream); - return ba; -} - QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h index e37171e56a..48aca964a1 100644 --- a/src/network/ssl/qsslsocket_mac_p.h +++ b/src/network/ssl/qsslsocket_mac_p.h @@ -75,7 +75,7 @@ public: private: SSLContextRef context; - Q_DISABLE_COPY(QSecureTransportContext) + Q_DISABLE_COPY_MOVE(QSecureTransportContext) }; class QSslSocketBackendPrivate : public QSslSocketPrivate @@ -129,7 +129,7 @@ private: QSecureTransportContext context; bool renegotiating = false; - Q_DISABLE_COPY(QSslSocketBackendPrivate) + Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate) }; QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 2c6c35ef24..d684100313 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -83,16 +83,16 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qscopedvaluerollback.h> +#if QT_CONFIG(ocsp) +#include <openssl/ocsp.h> +#endif + +#include <algorithm> + #include <string.h> QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN) - PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = nullptr; - PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = nullptr; - PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = nullptr; -#endif - bool QSslSocketPrivate::s_libraryLoaded = false; bool QSslSocketPrivate::s_loadedCiphersAndCerts = false; bool QSslSocketPrivate::s_loadRootCertsOnDemand = false; @@ -137,6 +137,37 @@ static unsigned int q_ssl_psk_server_callback(SSL *ssl, return d->tlsPskServerCallback(identity, psk, max_psk_len); } #endif + +#if QT_CONFIG(ocsp) + +int qt_OCSP_status_server_callback(SSL *ssl, void *ocspRequest) +{ + Q_UNUSED(ocspRequest) + if (!ssl) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + auto d = static_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData)); + if (!d) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + Q_ASSERT(d->mode == QSslSocket::SslServerMode); + const QByteArray &response = d->ocspResponseDer; + Q_ASSERT(response.size()); + + unsigned char *derCopy = static_cast<unsigned char *>(q_OPENSSL_malloc(size_t(response.size()))); + if (!derCopy) + return SSL_TLSEXT_ERR_ALERT_FATAL; + + std::copy(response.data(), response.data() + response.size(), derCopy); + // We don't check the return value: internally OpenSSL simply assignes the + // pointer (it assumes it now owns this memory btw!) and the length. + q_SSL_set_tlsext_status_ocsp_resp(ssl, derCopy, response.size()); + + return SSL_TLSEXT_ERR_OK; +} + +#endif // ocsp + } // extern "C" QSslSocketBackendPrivate::QSslSocketBackendPrivate() @@ -204,8 +235,92 @@ QSslErrorEntry QSslErrorEntry::fromStoreContext(X509_STORE_CTX *ctx) }; } +#if QT_CONFIG(ocsp) + +QSslError qt_OCSP_response_status_to_QSslError(long code) +{ + switch (code) { + case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: + return QSslError::OcspMalformedRequest; + case OCSP_RESPONSE_STATUS_INTERNALERROR: + return QSslError::OcspInternalError; + case OCSP_RESPONSE_STATUS_TRYLATER: + return QSslError::OcspTryLater; + case OCSP_RESPONSE_STATUS_SIGREQUIRED: + return QSslError::OcspSigRequred; + case OCSP_RESPONSE_STATUS_UNAUTHORIZED: + return QSslError::OcspUnauthorized; + case OCSP_RESPONSE_STATUS_SUCCESSFUL: + default: + return {}; + } + Q_UNREACHABLE(); +} + +bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert, X509 *issuer) +{ + // OCSP_basic_verify does verify that the responder is legit, the response is + // correctly signed, CertID is correct. But it does not know which certificate + // we were presented with by our peer, so it does not check if it's a response + // for our peer's certificate. + Q_ASSERT(singleResponse && peerCert && issuer); + + const OCSP_CERTID *certId = q_OCSP_SINGLERESP_get0_id(singleResponse); // Does not increment refcount. + if (!certId) { + qCWarning(lcSsl, "A SingleResponse without CertID"); + return false; + } + + ASN1_OBJECT *md = nullptr; + ASN1_INTEGER *reportedSerialNumber = nullptr; + const int result = q_OCSP_id_get0_info(nullptr, &md, nullptr, &reportedSerialNumber, const_cast<OCSP_CERTID *>(certId)); + if (result != 1 || !md || !reportedSerialNumber) { + qCWarning(lcSsl, "Failed to extract a hash and serial number from CertID structure"); + return false; + } + + if (!q_X509_get_serialNumber(peerCert)) { + // Is this possible at all? But we have to check this, + // ASN1_INTEGER_cmp (called from OCSP_id_cmp) dereferences + // without any checks at all. + qCWarning(lcSsl, "No serial number in peer's ceritificate"); + return false; + } + + const int nid = q_OBJ_obj2nid(md); + if (nid == NID_undef) { + qCWarning(lcSsl, "Unknown hash algorithm in CertID"); + return false; + } + + const EVP_MD *digest = q_EVP_get_digestbynid(nid); // Does not increment refcount. + if (!digest) { + qCWarning(lcSsl) << "No digest for nid" << nid; + return false; + } + + OCSP_CERTID *recreatedId = q_OCSP_cert_to_id(digest, peerCert, issuer); + if (!recreatedId) { + qCWarning(lcSsl, "Failed to re-create CertID"); + return false; + } + const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free); + + if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) { + qDebug(lcSsl, "Certificate ID mismatch"); + return false; + } + // Bingo! + return true; +} + +#endif // ocsp + // ### This list is shared between all threads, and protected by a -// mutex. Investigate using thread local storage instead. +// mutex. Investigate using thread local storage instead. Or better properly +// use OpenSSL's ability to attach application data to an SSL/SSL_CTX +// and extract it in a callback. See how it's done, for example, in PSK +// callback or in DTLS verification callback. struct QSslErrorList { QMutex mutex; @@ -280,7 +395,7 @@ long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, Q { long options; if (protocol == QSsl::TlsV1SslV3) - options = SSL_OP_ALL|SSL_OP_NO_SSLv2; + options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; else if (protocol == QSsl::SecureProtocols) options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; else if (protocol == QSsl::TlsV1_0OrLater) @@ -357,7 +472,7 @@ bool QSslSocketBackendPrivate::initSslContext() if (configuration.protocol != QSsl::SslV2 && configuration.protocol != QSsl::SslV3 && configuration.protocol != QSsl::UnknownProtocol && - mode == QSslSocket::SslClientMode && QSslSocket::sslLibraryVersionNumber() >= 0x00090806fL) { + mode == QSslSocket::SslClientMode) { // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format. QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName; if (tlsHostName.isEmpty()) @@ -412,6 +527,40 @@ bool QSslSocketBackendPrivate::initSslContext() } #endif +#if QT_CONFIG(ocsp) + if (configuration.ocspStaplingEnabled) { + if (mode == QSslSocket::SslServerMode) { + setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, + QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling")); + return false; + } + if (q_SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp) != 1) { + setErrorAndEmit(QAbstractSocket::SslInternalError, + QSslSocket::tr("Failed to enable OCSP stapling")); + return false; + } + } + + ocspResponseDer.clear(); + auto responsePos = configuration.backendConfig.find("Qt-OCSP-response"); + if (responsePos != configuration.backendConfig.end()) { + // This is our private, undocumented 'API' we use for the auto-testing of + // OCSP-stapling. It must be a der-encoded OCSP response, presumably set + // by tst_QOcsp. + const QVariant data(responsePos.value()); + if (data.canConvert<QByteArray>()) + ocspResponseDer = data.toByteArray(); + } + + if (ocspResponseDer.size()) { + if (mode != QSslSocket::SslServerMode) { + setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, + QSslSocket::tr("Client-side sockets do not send OCSP responses")); + return false; + } + } +#endif // ocsp + return true; } @@ -548,22 +697,20 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() #endif QList<QSslCertificate> systemCerts; #if defined(Q_OS_WIN) - if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) { - HCERTSTORE hSystemStore; - hSystemStore = ptrCertOpenSystemStoreW(0, L"ROOT"); - if (hSystemStore) { - PCCERT_CONTEXT pc = nullptr; - while (1) { - pc = ptrCertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc); - if (!pc) - break; - QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded), - static_cast<int>(pc->cbCertEncoded)); - QSslCertificate cert(der, QSsl::Der); - systemCerts.append(cert); - } - ptrCertCloseStore(hSystemStore, 0); + HCERTSTORE hSystemStore; + hSystemStore = CertOpenSystemStoreW(0, L"ROOT"); + if (hSystemStore) { + PCCERT_CONTEXT pc = nullptr; + while (1) { + pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc); + if (!pc) + break; + QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded), + static_cast<int>(pc->cbCertEncoded)); + QSslCertificate cert(der, QSsl::Der); + systemCerts.append(cert); } + CertCloseStore(hSystemStore, 0); } #elif defined(Q_OS_UNIX) QSet<QString> certFiles; @@ -1001,9 +1148,33 @@ bool QSslSocketBackendPrivate::startHandshake() } } - bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer - || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer - && mode == QSslSocket::SslClientMode); + const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer + || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer + && mode == QSslSocket::SslClientMode); + +#if QT_CONFIG(ocsp) + // For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early, + // if it's enabled in QSslSocket::SslServerMode. This can change. + if (!configuration.peerCertificate.isNull() && configuration.ocspStaplingEnabled && doVerifyPeer) { + if (!checkOcspStatus()) { + if (ocspErrors.isEmpty()) { + { + const ScopedBool bg(inSetAndEmitError, true); + setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, ocspErrorDescription); + } + q->abort(); + return false; + } + + for (const QSslError &error : ocspErrors) { + errors << error; + emit q->peerVerifyError(error); + if (q->state() != QAbstractSocket::ConnectedState) + return false; + } + } + } +#endif // ocsp // Check the peer certificate itself. First try the subject's common name // (CN) as a wildcard, then try all alternate subject name DNS entries the @@ -1250,6 +1421,180 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi #endif +#if QT_CONFIG(ocsp) + +bool QSslSocketBackendPrivate::checkOcspStatus() +{ + Q_ASSERT(ssl); + Q_ASSERT(mode == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode + Q_ASSERT(configuration.peerVerifyMode != QSslSocket::VerifyNone); + + ocspErrorDescription.clear(); + ocspErrors.clear(); + + const unsigned char *responseData = nullptr; + const long responseLength = q_SSL_get_tlsext_status_ocsp_resp(ssl, &responseData); + if (responseLength <= 0 || !responseData) { + ocspErrors.push_back(QSslError::OcspNoResponseFound); + return false; + } + + OCSP_RESPONSE *response = q_d2i_OCSP_RESPONSE(nullptr, &responseData, responseLength); + if (!response) { + // Treat this as a fatal SslHandshakeError. + ocspErrorDescription = QSslSocket::tr("Failed to decode OCSP response"); + return false; + } + const QSharedPointer<OCSP_RESPONSE> responseGuard(response, q_OCSP_RESPONSE_free); + + const int ocspStatus = q_OCSP_response_status(response); + if (ocspStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + // It's not a definitive response, it's an error message (not signed by the responder). + ocspErrors.push_back(qt_OCSP_response_status_to_QSslError(ocspStatus)); + return false; + } + + OCSP_BASICRESP *basicResponse = q_OCSP_response_get1_basic(response); + if (!basicResponse) { + // SslHandshakeError. + ocspErrorDescription = QSslSocket::tr("Failed to extract basic OCSP response"); + return false; + } + const QSharedPointer<OCSP_BASICRESP> basicResponseGuard(basicResponse, q_OCSP_BASICRESP_free); + + SSL_CTX *ctx = q_SSL_get_SSL_CTX(ssl); // Does not increment refcount. + Q_ASSERT(ctx); + X509_STORE *store = q_SSL_CTX_get_cert_store(ctx); // Does not increment refcount. + if (!store) { + // SslHandshakeError. + ocspErrorDescription = QSslSocket::tr("No certificate verification store, cannot verify OCSP response"); + return false; + } + + STACK_OF(X509) *peerChain = q_SSL_get_peer_cert_chain(ssl); // Does not increment refcount. + X509 *peerX509 = q_SSL_get_peer_certificate(ssl); + Q_ASSERT(peerChain || peerX509); + const QSharedPointer<X509> peerX509Guard(peerX509, q_X509_free); + // OCSP_basic_verify with 0 as verificationFlags: + // + // 0) Tries to find the OCSP responder's certificate in either peerChain + // or basicResponse->certs. If not found, verification fails. + // 1) It checks the signature using the responder's public key. + // 2) Then it tries to validate the responder's cert (building a chain + // etc.) + // 3) It checks CertID in response. + // 4) Ensures the responder is authorized to sign the status respond. + // + // Here it's important to notice that it calls X509_cert_verify and + // as a result, possibly, our verification callback. Given this callback + // at the moment uses a global variable, we have to lock. This will change + // as soon as we fix our verification procedure. + // Also note, OpenSSL prior to 1.0.2b would only use bs->certs to + // verify the responder's chain (see their commit 4ba9a4265bd). + // Working this around - is too much fuss for ancient versions we + // are dropping quite soon anyway. + { + const unsigned long verificationFlags = 0; + const QMutexLocker locker(&_q_sslErrorList()->mutex); + // Before unlocking the mutex, startHandshake() stores errors (found in SSL_connect() + // or SSL_accept()) into the local variable, so it's safe to clear it here - as soon + // as we managed to lock, whoever had the lock before, already stored their own copy + // of errors. + _q_sslErrorList()->errors.clear(); + const int success = q_OCSP_basic_verify(basicResponse, peerChain, store, verificationFlags); + if (success <= 0 || _q_sslErrorList()->errors.size()) { + _q_sslErrorList()->errors.clear(); + ocspErrors.push_back(QSslError::OcspResponseCannotBeTrusted); + } + } + + if (q_OCSP_resp_count(basicResponse) != 1) { + ocspErrors.push_back(QSslError::OcspMalformedResponse); + return false; + } + + OCSP_SINGLERESP *singleResponse = q_OCSP_resp_get0(basicResponse, 0); + if (!singleResponse) { + ocspErrors.clear(); + // A fatal problem -> SslHandshakeError. + ocspErrorDescription = QSslSocket::tr("Failed to decode a SingleResponse from OCSP status response"); + return false; + } + + // Let's make sure the response is for the correct certificate - we + // can re-create this CertID using our peer's certificate and its + // issuer's public key. + + bool matchFound = false; + if (configuration.peerCertificate.isSelfSigned()) { + matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509); + } else { + const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl); + if (!certs) // Oh, what a cataclysm! Last try: + certs = q_OCSP_resp_get0_certs(basicResponse); + if (certs) { + // It could be the first certificate in 'certs' is our peer's + // certificate. Since it was not captured by the 'self-signed' branch + // above, the CertID will not match and we'll just iterate on to the + // next certificate. So we start from 0, not 1. + for (int i = 0, e = q_sk_X509_num(certs); i < e; ++i) { + X509 *issuer = q_sk_X509_value(certs, i); + matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, issuer); + if (matchFound) { + if (q_X509_check_issued(issuer, peerX509) == X509_V_OK) + break; + matchFound = false; + } + } + } + } + + if (!matchFound) + ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate}); + + // Check if the response is valid time-wise: + ASN1_GENERALIZEDTIME *revTime = nullptr; + ASN1_GENERALIZEDTIME *thisUpdate = nullptr; + ASN1_GENERALIZEDTIME *nextUpdate = nullptr; + int reason; + const int certStatus = q_OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate); + if (!thisUpdate) { + // This is unexpected, treat as SslHandshakeError, OCSP_check_validity assumes this pointer + // to be != nullptr. + ocspErrors.clear(); + ocspErrorDescription = QSslSocket::tr("Failed to extract 'this update time' from the SingleResponse"); + return false; + } + + // OCSP_check_validity(this, next, nsec, maxsec) does this check: + // this <= now <= next. They allow some freedom to account + // for delays/time inaccuracy. + // this > now + nsec ? -> NOT_YET_VALID + // if maxsec >= 0: + // now - maxsec > this ? -> TOO_OLD + // now - nsec > next ? -> EXPIRED + // next < this ? -> NEXT_BEFORE_THIS + // OK. + if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1)) + ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate}); + + // And finally, the status: + switch (certStatus) { + case V_OCSP_CERTSTATUS_GOOD: + // This certificate was not found among the revoked ones. + break; + case V_OCSP_CERTSTATUS_REVOKED: + ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate}); + break; + case V_OCSP_CERTSTATUS_UNKNOWN: + ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate}); + } + + return !ocspErrors.size(); +} + +#endif // ocsp + void QSslSocketBackendPrivate::disconnectFromHost() { if (ssl) { diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp index 2a2667bd48..b60b8be41f 100644 --- a/src/network/ssl/qsslsocket_openssl11.cpp +++ b/src/network/ssl/qsslsocket_openssl11.cpp @@ -122,21 +122,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if QT_CONFIG(library) //load symbols needed to receive certificates from system store -#if defined(Q_OS_WIN) - HINSTANCE hLib = LoadLibraryW(L"Crypt32"); - if (hLib) { - ptrCertOpenSystemStoreW = reinterpret_cast<PtrCertOpenSystemStoreW>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertOpenSystemStoreW"))); - ptrCertFindCertificateInStore = reinterpret_cast<PtrCertFindCertificateInStore>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertFindCertificateInStore"))); - ptrCertCloseStore = reinterpret_cast<PtrCertCloseStore>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertCloseStore"))); - if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) - qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen - } else { - qCWarning(lcSsl, "could not load crypt32 library"); // should never happen - } -#elif defined(Q_OS_QNX) +#if defined(Q_OS_QNX) s_loadRootCertsOnDemand = true; #elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there) diff --git a/src/network/ssl/qsslsocket_openssl11_symbols_p.h b/src/network/ssl/qsslsocket_openssl11_symbols_p.h index fae007e12d..a44d00a830 100644 --- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h @@ -84,12 +84,12 @@ int q_DSA_bits(DSA *a); int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c); int q_EVP_PKEY_base_id(EVP_PKEY *a); int q_RSA_bits(RSA *a); -int q_OPENSSL_sk_num(OPENSSL_STACK *a); -void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *)); -OPENSSL_STACK *q_OPENSSL_sk_new_null(); -void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data); -void q_OPENSSL_sk_free(OPENSSL_STACK *a); -void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b); +Q_AUTOTEST_EXPORT int q_OPENSSL_sk_num(OPENSSL_STACK *a); +Q_AUTOTEST_EXPORT void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *)); +Q_AUTOTEST_EXPORT OPENSSL_STACK *q_OPENSSL_sk_new_null(); +Q_AUTOTEST_EXPORT void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data); +Q_AUTOTEST_EXPORT void q_OPENSSL_sk_free(OPENSSL_STACK *a); +Q_AUTOTEST_EXPORT void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b); int q_SSL_session_reused(SSL *a); unsigned long q_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op); int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings); @@ -102,6 +102,7 @@ const SSL_METHOD *q_TLS_server_method(); ASN1_TIME *q_X509_getm_notBefore(X509 *a); ASN1_TIME *q_X509_getm_notAfter(X509 *a); +Q_AUTOTEST_EXPORT void q_X509_up_ref(X509 *a); long q_X509_get_version(X509 *a); EVP_PKEY *q_X509_get_pubkey(X509 *a); void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify_cb); @@ -172,6 +173,10 @@ void q_BIO_set_init(BIO *a, int init); int q_BIO_get_shutdown(BIO *a); void q_BIO_set_shutdown(BIO *a, int shut); +#if QT_CONFIG(ocsp) +const OCSP_CERTID *q_OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *x); +#endif // ocsp + #define q_SSL_CTX_set_min_proto_version(ctx, version) \ q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, nullptr) diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index c16b9d5f76..c23234e291 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -69,6 +69,9 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include "qsslsocket_p.h" +#include <QtCore/qvector.h> +#include <QtCore/qstring.h> + #ifdef Q_OS_WIN #include <qt_windows.h> #if defined(OCSP_RESPONSE) @@ -152,6 +155,16 @@ public: void _q_caRootLoaded(QSslCertificate,QSslCertificate) override; #endif +#if QT_CONFIG(ocsp) + bool checkOcspStatus(); +#endif + + // This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription) + QString ocspErrorDescription; + // These will go to sslErrors() + QVector<QSslError> ocspErrors; + QByteArray ocspResponseDer; + Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions); static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher); static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509); diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 299df6b685..aa1dc681e0 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -172,6 +172,7 @@ DEFINEFUNC2(unsigned long, SSL_set_options, SSL *ssl, ssl, unsigned long op, op, DEFINEFUNC(const SSL_METHOD *, TLS_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLS_client_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLS_server_method, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC(void, X509_up_ref, X509 *a, a, return, DUMMYARG) DEFINEFUNC(ASN1_TIME *, X509_getm_notBefore, X509 *a, a, return nullptr, return) DEFINEFUNC(ASN1_TIME *, X509_getm_notAfter, X509 *a, a, return nullptr, return) DEFINEFUNC(long, X509_get_version, X509 *a, a, return -1, return) @@ -199,6 +200,35 @@ DEFINEFUNC2(int, BIO_meth_set_create, BIO_METHOD *biom, biom, DgramCreateCallbac DEFINEFUNC2(int, BIO_meth_set_destroy, BIO_METHOD *biom, biom, DgramDestroyCallback dtr, dtr, return 0, return) #endif // dtls +#if QT_CONFIG(ocsp) +DEFINEFUNC(const OCSP_CERTID *, OCSP_SINGLERESP_get0_id, const OCSP_SINGLERESP *x, x, return nullptr, return) +DEFINEFUNC3(OCSP_RESPONSE *, d2i_OCSP_RESPONSE, OCSP_RESPONSE **a, a, const unsigned char **in, in, long len, len, return nullptr, return) +DEFINEFUNC(void, OCSP_RESPONSE_free, OCSP_RESPONSE *rs, rs, return, DUMMYARG) +DEFINEFUNC(OCSP_BASICRESP *, OCSP_response_get1_basic, OCSP_RESPONSE *resp, resp, return nullptr, return) +DEFINEFUNC(void, OCSP_BASICRESP_free, OCSP_BASICRESP *bs, bs, return, DUMMYARG) +DEFINEFUNC(int, OCSP_response_status, OCSP_RESPONSE *resp, resp, return OCSP_RESPONSE_STATUS_INTERNALERROR, return) +DEFINEFUNC4(int, OCSP_basic_verify, OCSP_BASICRESP *bs, bs, STACK_OF(X509) *certs, certs, X509_STORE *st, st, unsigned long flags, flags, return -1, return) +DEFINEFUNC(int, OCSP_resp_count, OCSP_BASICRESP *bs, bs, return 0, return) +DEFINEFUNC2(OCSP_SINGLERESP *, OCSP_resp_get0, OCSP_BASICRESP *bs, bs, int idx, idx, return nullptr, return) +DEFINEFUNC5(int, OCSP_single_get0_status, OCSP_SINGLERESP *single, single, int *reason, reason, ASN1_GENERALIZEDTIME **revtime, revtime, + ASN1_GENERALIZEDTIME **thisupd, thisupd, ASN1_GENERALIZEDTIME **nextupd, nextupd, return -1, return) +DEFINEFUNC4(int, OCSP_check_validity, ASN1_GENERALIZEDTIME *thisupd, thisupd, ASN1_GENERALIZEDTIME *nextupd, nextupd, long nsec, nsec, long maxsec, maxsec, return 0, return) +DEFINEFUNC3(OCSP_CERTID *, OCSP_cert_to_id, const EVP_MD *dgst, dgst, X509 *subject, subject, X509 *issuer, issuer, return nullptr, return) +DEFINEFUNC(void, OCSP_CERTID_free, OCSP_CERTID *cid, cid, return, DUMMYARG) +DEFINEFUNC5(int, OCSP_id_get0_info, ASN1_OCTET_STRING **piNameHash, piNameHash, ASN1_OBJECT **pmd, pmd, + ASN1_OCTET_STRING **piKeyHash, piKeyHash, ASN1_INTEGER **pserial, pserial, OCSP_CERTID *cid, cid, + return 0, return) +DEFINEFUNC2(OCSP_RESPONSE *, OCSP_response_create, int status, status, OCSP_BASICRESP *bs, bs, return nullptr, return) +DEFINEFUNC(const STACK_OF(X509) *, OCSP_resp_get0_certs, const OCSP_BASICRESP *bs, bs, return nullptr, return) +DEFINEFUNC2(int, OCSP_id_cmp, OCSP_CERTID *a, a, OCSP_CERTID *b, b, return -1, return) +DEFINEFUNC7(OCSP_SINGLERESP *, OCSP_basic_add1_status, OCSP_BASICRESP *r, r, OCSP_CERTID *c, c, int s, s, + int re, re, ASN1_TIME *rt, rt, ASN1_TIME *t, t, ASN1_TIME *n, n, return nullptr, return) +DEFINEFUNC(OCSP_BASICRESP *, OCSP_BASICRESP_new, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC2(int, i2d_OCSP_RESPONSE, OCSP_RESPONSE *r, r, unsigned char **ppout, ppout, return 0, return) +DEFINEFUNC6(int, OCSP_basic_sign, OCSP_BASICRESP *br, br, X509 *signer, signer, EVP_PKEY *key, key, + const EVP_MD *dg, dg, STACK_OF(X509) *cs, cs, unsigned long flags, flags, return 0, return) +#endif // ocsp + DEFINEFUNC2(void, BIO_set_data, BIO *a, a, void *ptr, ptr, return, DUMMYARG) DEFINEFUNC(void *, BIO_get_data, BIO *a, a, return nullptr, return) DEFINEFUNC2(void, BIO_set_init, BIO *a, a, int init, init, return, DUMMYARG) @@ -235,17 +265,10 @@ DEFINEFUNC6(void *, PEM_ASN1_write_bio, d2i_of_void *a, a, const char *b, b, BIO DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return) DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG) -#if OPENSSL_VERSION_NUMBER >= 0x10000000L DEFINEFUNC(_STACK *, sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC2(void, sk_push, _STACK *a, a, void *b, b, return, DUMMYARG) DEFINEFUNC(void, sk_free, _STACK *a, a, return, DUMMYARG) DEFINEFUNC2(void *, sk_value, STACK *a, a, int b, b, return nullptr, return) -#else -DEFINEFUNC(STACK *, sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return) -DEFINEFUNC2(void, sk_push, STACK *a, a, char *b, b, return, DUMMYARG) -DEFINEFUNC(void, sk_free, STACK *a, a, return, DUMMYARG) -DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return nullptr, return) -#endif // OPENSSL_VERSION_NUMBER >= 0x10000000L DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return) DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG) @@ -254,49 +277,18 @@ DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG) DEFINEFUNC5(int, SSL_get_ex_new_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return) #endif // OPENSSL_VERSION_NUMBER >= 0x10001000L -#if OPENSSL_VERSION_NUMBER >= 0x10000000L -#ifndef OPENSSL_NO_SSL2 -DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -DEFINEFUNC(const SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif DEFINEFUNC(const SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return nullptr, return) #if OPENSSL_VERSION_NUMBER >= 0x10001000L DEFINEFUNC(const SSL_METHOD *, TLSv1_1_client_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLSv1_2_client_method, DUMMYARG, DUMMYARG, return nullptr, return) #endif -#ifndef OPENSSL_NO_SSL2 -DEFINEFUNC(const SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -DEFINEFUNC(const SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif DEFINEFUNC(const SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return nullptr, return) #if OPENSSL_VERSION_NUMBER >= 0x10001000L DEFINEFUNC(const SSL_METHOD *, TLSv1_1_server_method, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const SSL_METHOD *, TLSv1_2_server_method, DUMMYARG, DUMMYARG, return nullptr, return) #endif -#else -#ifndef OPENSSL_NO_SSL2 -DEFINEFUNC(SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -DEFINEFUNC(SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -DEFINEFUNC(SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -DEFINEFUNC(SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return nullptr, return) -#ifndef OPENSSL_NO_SSL2 -DEFINEFUNC(SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -DEFINEFUNC(SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif -DEFINEFUNC(SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -DEFINEFUNC(SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return nullptr, return) -#endif DEFINEFUNC(STACK_OF(X509) *, X509_STORE_CTX_get_chain, X509_STORE_CTX *a, a, return nullptr, return) @@ -329,6 +321,7 @@ DEFINEFUNC(const char *, SSLeay_version, int a, a, return nullptr, return) #endif // QT_CONFIG(opensslv11) DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return) +DEFINEFUNC2(int, ASN1_INTEGER_cmp, const ASN1_INTEGER *a, a, const ASN1_INTEGER *b, b, return 1, return) DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return) DEFINEFUNC2(int, ASN1_STRING_to_UTF8, unsigned char **a, a, ASN1_STRING *b, b, return 0, return) DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return) @@ -357,6 +350,7 @@ DEFINEFUNC5(int, EVP_CipherInit, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *typ DEFINEFUNC6(int, EVP_CipherInit_ex, EVP_CIPHER_CTX *ctx, ctx, const EVP_CIPHER *cipher, cipher, ENGINE *impl, impl, const unsigned char *key, key, const unsigned char *iv, iv, int enc, enc, return 0, return) DEFINEFUNC5(int, EVP_CipherUpdate, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, const unsigned char *in, in, int inl, inl, return 0, return) DEFINEFUNC3(int, EVP_CipherFinal, EVP_CIPHER_CTX *ctx, ctx, unsigned char *out, out, int *outl, outl, return 0, return) +DEFINEFUNC(const EVP_MD *, EVP_get_digestbyname, const char *name, name, return nullptr, return) #ifndef OPENSSL_NO_DES DEFINEFUNC(const EVP_CIPHER *, EVP_des_cbc, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return nullptr, return) @@ -368,12 +362,14 @@ DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return) DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return) DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return) +DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return) #ifndef OPENSSL_NO_EC DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return) #endif DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG) DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return) DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return) +DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return) #ifndef OPENSSL_NO_EC DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return) #endif @@ -399,6 +395,7 @@ DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_p DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return) DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return) DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return) +DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return) #ifndef OPENSSL_NO_EC DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return) #endif @@ -411,6 +408,7 @@ DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_pass #endif DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return) DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return) +DEFINEFUNC2(int, PEM_write_bio_PUBKEY, BIO *a, a, EVP_PKEY *b, b, return 0, return) #ifndef OPENSSL_NO_EC DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return) #endif @@ -428,12 +426,9 @@ DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return) DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return) DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return) DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG) -#if OPENSSL_VERSION_NUMBER >= 0x10000000L DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return nullptr, return) -#else -DEFINEFUNC(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a, a, return nullptr, return) -#endif DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return) +DEFINEFUNC3(long, SSL_CTX_callback_ctrl, SSL_CTX *ctx, ctx, int dst, dst, GenericCallbackType cb, cb, return 0, return) DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return) DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG) DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG) @@ -453,22 +448,14 @@ DEFINEFUNC3(int, SSL_CONF_cmd, SSL_CONF_CTX *a, a, const char *b, b, const char #endif DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG) DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return nullptr, return) -#if OPENSSL_VERSION_NUMBER >= 0x10000000L DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr, return) -#else -DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return nullptr, return) -#endif DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return) DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return) DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return nullptr, return) DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return nullptr, return) -#if OPENSSL_VERSION_NUMBER >= 0x00908000L -// 0.9.8 broke SC and BC by changing this function's signature. DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return) -#else -DEFINEFUNC(long, SSL_get_verify_result, SSL *a, a, return -1, return) -#endif DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return nullptr, return) +DEFINEFUNC(SSL_CTX *, SSL_get_SSL_CTX, SSL *a, a, return nullptr, return) DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, void *parg, parg, return -1, return) DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return) DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG) @@ -498,6 +485,9 @@ DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return nullptr, return) DEFINEFUNC2(void, X509_print, BIO *a, a, X509 *b, b, return, DUMMYARG); DEFINEFUNC(ASN1_OBJECT *, X509_EXTENSION_get_object, X509_EXTENSION *a, a, return nullptr, return) DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG) +//Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj); +DEFINEFUNC2(ASN1_TIME *, X509_gmtime_adj, ASN1_TIME *s, s, long adj, adj, return nullptr, return) +DEFINEFUNC(void, ASN1_TIME_free, ASN1_TIME *t, t, return, DUMMYARG) DEFINEFUNC2(X509_EXTENSION *, X509_get_ext, X509 *a, a, int b, b, return nullptr, return) DEFINEFUNC(int, X509_get_ext_count, X509 *a, a, return 0, return) DEFINEFUNC4(void *, X509_get_ext_d2i, X509 *a, a, int b, b, int *c, c, int *d, d, return nullptr, return) @@ -508,11 +498,7 @@ DEFINEFUNC(ASN1_OCTET_STRING *, X509_EXTENSION_get_data, X509_EXTENSION *a, a, r DEFINEFUNC(void, BASIC_CONSTRAINTS_free, BASIC_CONSTRAINTS *a, a, return, DUMMYARG) DEFINEFUNC(void, AUTHORITY_KEYID_free, AUTHORITY_KEYID *a, a, return, DUMMYARG) DEFINEFUNC(void, GENERAL_NAME_free, GENERAL_NAME *a, a, return, DUMMYARG) -#if OPENSSL_VERSION_NUMBER >= 0x10000000L DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, const ASN1_STRING *b, b, return 0, return) -#else -DEFINEFUNC2(int, ASN1_STRING_print, BIO *a, a, ASN1_STRING *b, b, return 0, return) -#endif DEFINEFUNC2(int, X509_check_issued, X509 *a, a, X509 *b, b, return -1, return) DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return nullptr, return) DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return nullptr, return) @@ -577,6 +563,7 @@ DEFINEFUNC2(void, BIO_clear_flags, BIO *b, b, int flags, flags, return, DUMMYARG DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, return) DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return) +DEFINEFUNC3(void *, CRYPTO_malloc, size_t num, num, const char *file, file, int line, line, return nullptr, return) DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return) DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG) DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return) @@ -990,6 +977,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(TLS_method) RESOLVEFUNC(TLS_client_method) RESOLVEFUNC(TLS_server_method) + RESOLVEFUNC(X509_up_ref) RESOLVEFUNC(X509_STORE_CTX_get0_chain) RESOLVEFUNC(X509_getm_notBefore) RESOLVEFUNC(X509_getm_notAfter) @@ -1025,7 +1013,30 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(BIO_meth_set_create) RESOLVEFUNC(BIO_meth_set_destroy) #endif // dtls - +#if QT_CONFIG(ocsp) + RESOLVEFUNC(OCSP_SINGLERESP_get0_id) + RESOLVEFUNC(d2i_OCSP_RESPONSE) + RESOLVEFUNC(OCSP_RESPONSE_free) + RESOLVEFUNC(OCSP_response_status) + RESOLVEFUNC(OCSP_response_get1_basic) + RESOLVEFUNC(OCSP_BASICRESP_free) + RESOLVEFUNC(OCSP_basic_verify) + RESOLVEFUNC(OCSP_resp_count) + RESOLVEFUNC(OCSP_resp_get0) + RESOLVEFUNC(OCSP_single_get0_status) + RESOLVEFUNC(OCSP_check_validity) + RESOLVEFUNC(OCSP_cert_to_id) + RESOLVEFUNC(OCSP_id_get0_info) + RESOLVEFUNC(OCSP_resp_get0_certs) + RESOLVEFUNC(OCSP_basic_sign) + RESOLVEFUNC(OCSP_response_create) + RESOLVEFUNC(i2d_OCSP_RESPONSE) + RESOLVEFUNC(OCSP_basic_add1_status) + RESOLVEFUNC(OCSP_BASICRESP_new) + RESOLVEFUNC(OCSP_CERTID_free) + RESOLVEFUNC(OCSP_cert_to_id) + RESOLVEFUNC(OCSP_id_cmp) +#endif // ocsp RESOLVEFUNC(BIO_set_data) RESOLVEFUNC(BIO_get_data) RESOLVEFUNC(BIO_set_init) @@ -1064,24 +1075,12 @@ bool q_resolveOpenSslSymbols() #if OPENSSL_VERSION_NUMBER >= 0x10001000L RESOLVEFUNC(SSL_get_ex_new_index) #endif -#ifndef OPENSSL_NO_SSL2 - RESOLVEFUNC(SSLv2_client_method) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD - RESOLVEFUNC(SSLv3_client_method) -#endif RESOLVEFUNC(SSLv23_client_method) RESOLVEFUNC(TLSv1_client_method) #if OPENSSL_VERSION_NUMBER >= 0x10001000L RESOLVEFUNC(TLSv1_1_client_method) RESOLVEFUNC(TLSv1_2_client_method) #endif -#ifndef OPENSSL_NO_SSL2 - RESOLVEFUNC(SSLv2_server_method) -#endif -#ifndef OPENSSL_NO_SSL3_METHOD - RESOLVEFUNC(SSLv3_server_method) -#endif RESOLVEFUNC(SSLv23_server_method) RESOLVEFUNC(TLSv1_server_method) #if OPENSSL_VERSION_NUMBER >= 0x10001000L @@ -1132,6 +1131,7 @@ bool q_resolveOpenSslSymbols() #endif // !opensslv11 RESOLVEFUNC(ASN1_INTEGER_get) + RESOLVEFUNC(ASN1_INTEGER_cmp) RESOLVEFUNC(ASN1_STRING_length) RESOLVEFUNC(ASN1_STRING_to_UTF8) RESOLVEFUNC(BIO_ctrl) @@ -1168,6 +1168,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(EVP_CipherInit_ex) RESOLVEFUNC(EVP_CipherUpdate) RESOLVEFUNC(EVP_CipherFinal) + RESOLVEFUNC(EVP_get_digestbyname) #ifndef OPENSSL_NO_DES RESOLVEFUNC(EVP_des_cbc) RESOLVEFUNC(EVP_des_ede3_cbc) @@ -1179,12 +1180,14 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(EVP_PKEY_assign) RESOLVEFUNC(EVP_PKEY_set1_RSA) RESOLVEFUNC(EVP_PKEY_set1_DSA) + RESOLVEFUNC(EVP_PKEY_set1_DH) #ifndef OPENSSL_NO_EC RESOLVEFUNC(EVP_PKEY_set1_EC_KEY) #endif RESOLVEFUNC(EVP_PKEY_free) RESOLVEFUNC(EVP_PKEY_get1_DSA) RESOLVEFUNC(EVP_PKEY_get1_RSA) + RESOLVEFUNC(EVP_PKEY_get1_DH) #ifndef OPENSSL_NO_EC RESOLVEFUNC(EVP_PKEY_get1_EC_KEY) #endif @@ -1208,6 +1211,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(PEM_read_bio_DHparams) RESOLVEFUNC(PEM_write_bio_DSAPrivateKey) RESOLVEFUNC(PEM_write_bio_RSAPrivateKey) + RESOLVEFUNC(PEM_write_bio_PrivateKey) #ifndef OPENSSL_NO_EC RESOLVEFUNC(PEM_write_bio_ECPrivateKey) #endif @@ -1221,6 +1225,7 @@ bool q_resolveOpenSslSymbols() #endif RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY) RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY) + RESOLVEFUNC(PEM_write_bio_PUBKEY) #ifndef OPENSSL_NO_EC RESOLVEFUNC(PEM_write_bio_EC_PUBKEY) #endif @@ -1237,6 +1242,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(SSL_CTX_free) RESOLVEFUNC(SSL_CTX_new) RESOLVEFUNC(SSL_CTX_set_cipher_list) + RESOLVEFUNC(SSL_CTX_callback_ctrl) RESOLVEFUNC(SSL_CTX_set_default_verify_paths) RESOLVEFUNC(SSL_CTX_set_verify) RESOLVEFUNC(SSL_CTX_set_verify_depth) @@ -1266,6 +1272,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(SSL_get_peer_certificate) RESOLVEFUNC(SSL_get_verify_result) RESOLVEFUNC(SSL_new) + RESOLVEFUNC(SSL_get_SSL_CTX) RESOLVEFUNC(SSL_ctrl) RESOLVEFUNC(SSL_read) RESOLVEFUNC(SSL_set_accept_state) @@ -1313,6 +1320,8 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(X509_digest) RESOLVEFUNC(X509_EXTENSION_get_object) RESOLVEFUNC(X509_free) + RESOLVEFUNC(X509_gmtime_adj) + RESOLVEFUNC(ASN1_TIME_free) RESOLVEFUNC(X509_get_ext) RESOLVEFUNC(X509_get_ext_count) RESOLVEFUNC(X509_get_ext_d2i) @@ -1350,6 +1359,7 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(DTLS_server_method) RESOLVEFUNC(DTLS_client_method) #endif // dtls + RESOLVEFUNC(CRYPTO_malloc) RESOLVEFUNC(DH_new) RESOLVEFUNC(DH_free) RESOLVEFUNC(d2i_DHparams) diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index bfdfbf0efc..cf426e2ed2 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -72,6 +72,10 @@ #include "qsslsocket_openssl_p.h" #include <QtCore/qglobal.h> +#if QT_CONFIG(ocsp) +#include <openssl/ocsp.h> +#endif + QT_BEGIN_NAMESPACE #define DUMMYARG @@ -224,6 +228,7 @@ QT_BEGIN_NAMESPACE bool q_resolveOpenSslSymbols(); long q_ASN1_INTEGER_get(ASN1_INTEGER *a); +int q_ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y); int q_ASN1_STRING_length(ASN1_STRING *a); int q_ASN1_STRING_to_UTF8(unsigned char **a, ASN1_STRING *b); long q_BIO_ctrl(BIO *a, int b, long c, void *d); @@ -267,6 +272,8 @@ int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc); int q_EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl); int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); +const EVP_MD *q_EVP_get_digestbyname(const char *name); + #ifndef OPENSSL_NO_DES const EVP_CIPHER *q_EVP_des_cbc(); const EVP_CIPHER *q_EVP_des_ede3_cbc(); @@ -274,16 +281,18 @@ const EVP_CIPHER *q_EVP_des_ede3_cbc(); #ifndef OPENSSL_NO_RC2 const EVP_CIPHER *q_EVP_rc2_cbc(); #endif -const EVP_MD *q_EVP_sha1(); +Q_AUTOTEST_EXPORT const EVP_MD *q_EVP_sha1(); int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c); Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b); int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b); +int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b); #ifndef OPENSSL_NO_EC int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b); #endif -void q_EVP_PKEY_free(EVP_PKEY *a); +Q_AUTOTEST_EXPORT void q_EVP_PKEY_free(EVP_PKEY *a); RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a); DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a); +DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a); #ifndef OPENSSL_NO_EC EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a); #endif @@ -297,6 +306,7 @@ int q_OBJ_ln2nid(const char *s); int q_i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *obj); int q_OBJ_obj2txt(char *buf, int buf_len, ASN1_OBJECT *obj, int no_name); int q_OBJ_obj2nid(const ASN1_OBJECT *a); +#define q_EVP_get_digestbynid(a) q_EVP_get_digestbyname(q_OBJ_nid2sn(a)) #ifdef SSLEAY_MACROS // ### verify void *q_PEM_ASN1_read_bio(d2i_of_void *a, const char *b, BIO *c, void **d, pem_password_cb *e, @@ -314,6 +324,8 @@ int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned int e, pem_password_cb *f, void *g); int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d, int e, pem_password_cb *f, void *g); +int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d, + int e, pem_password_cb *f, void *g); #ifndef OPENSSL_NO_EC int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d, int e, pem_password_cb *f, void *g); @@ -327,6 +339,7 @@ EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d #endif int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b); int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b); +int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b); #ifndef OPENSSL_NO_EC int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b); #endif @@ -344,15 +357,15 @@ int q_SSL_connect(SSL *a); int q_SSL_CTX_check_private_key(const SSL_CTX *a); long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d); void q_SSL_CTX_free(SSL_CTX *a); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a); -#else -SSL_CTX *q_SSL_CTX_new(SSL_METHOD *a); -#endif int q_SSL_CTX_set_cipher_list(SSL_CTX *a, const char *b); int q_SSL_CTX_set_default_verify_paths(SSL_CTX *a); void q_SSL_CTX_set_verify(SSL_CTX *a, int b, int (*c)(int, X509_STORE_CTX *)); void q_SSL_CTX_set_verify_depth(SSL_CTX *a, int b); +extern "C" { +typedef void (*GenericCallbackType)(); +} +long q_SSL_CTX_callback_ctrl(SSL_CTX *, int, GenericCallbackType); int q_SSL_CTX_use_certificate(SSL_CTX *a, X509 *b); int q_SSL_CTX_use_certificate_file(SSL_CTX *a, const char *b, int c); int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b); @@ -369,17 +382,14 @@ int q_SSL_CONF_cmd(SSL_CONF_CTX *a, const char *b, const char *c); #endif void q_SSL_free(SSL *a); STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a); -#else -SSL_CIPHER *q_SSL_get_current_cipher(SSL *a); -#endif int q_SSL_version(const SSL *a); int q_SSL_get_error(SSL *a, int b); STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a); X509 *q_SSL_get_peer_certificate(SSL *a); long q_SSL_get_verify_result(const SSL *a); SSL *q_SSL_new(SSL_CTX *a); +SSL_CTX *q_SSL_get_SSL_CTX(SSL *a); long q_SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg); int q_SSL_read(SSL *a, void *b, int c); void q_SSL_set_bio(SSL *a, BIO *b, BIO *c); @@ -414,7 +424,9 @@ X509 *q_X509_dup(X509 *a); void q_X509_print(BIO *a, X509*b); int q_X509_digest(const X509 *x509, const EVP_MD *type, unsigned char *md, unsigned int *len); ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a); -void q_X509_free(X509 *a); +Q_AUTOTEST_EXPORT void q_X509_free(X509 *a); +Q_AUTOTEST_EXPORT ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj); +Q_AUTOTEST_EXPORT void q_ASN1_TIME_free(ASN1_TIME *t); X509_EXTENSION *q_X509_get_ext(X509 *a, int b); int q_X509_get_ext_count(X509 *a); void *q_X509_get_ext_d2i(X509 *a, int b, int *c, int *d); @@ -424,11 +436,7 @@ int q_X509_EXTENSION_get_critical(X509_EXTENSION *a); ASN1_OCTET_STRING *q_X509_EXTENSION_get_data(X509_EXTENSION *a); void q_BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *a); void q_AUTHORITY_KEYID_free(AUTHORITY_KEYID *a); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L int q_ASN1_STRING_print(BIO *a, const ASN1_STRING *b); -#else -int q_ASN1_STRING_print(BIO *a, ASN1_STRING *b); -#endif int q_X509_check_issued(X509 *a, X509 *b); X509_NAME *q_X509_get_issuer_name(X509 *a); X509_NAME *q_X509_get_subject_name(X509 *a); @@ -571,6 +579,57 @@ int q_BIO_set_ex_data(BIO *b, int idx, void *data); class QDateTime; QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime); +#ifndef OPENSSL_NO_TLSEXT + +#define q_SSL_set_tlsext_status_type(ssl, type) \ + q_SSL_ctrl((ssl), SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, (type), nullptr) + +#endif // OPENSSL_NO_TLSEXT + +#if QT_CONFIG(ocsp) + +OCSP_RESPONSE *q_d2i_OCSP_RESPONSE(OCSP_RESPONSE **a, const unsigned char **in, long len); +Q_AUTOTEST_EXPORT int q_i2d_OCSP_RESPONSE(OCSP_RESPONSE *r, unsigned char **ppout); +Q_AUTOTEST_EXPORT OCSP_RESPONSE *q_OCSP_response_create(int status, OCSP_BASICRESP *bs); +Q_AUTOTEST_EXPORT void q_OCSP_RESPONSE_free(OCSP_RESPONSE *rs); +int q_OCSP_response_status(OCSP_RESPONSE *resp); +OCSP_BASICRESP *q_OCSP_response_get1_basic(OCSP_RESPONSE *resp); +Q_AUTOTEST_EXPORT OCSP_SINGLERESP *q_OCSP_basic_add1_status(OCSP_BASICRESP *rsp, OCSP_CERTID *cid, + int status, int reason, ASN1_TIME *revtime, + ASN1_TIME *thisupd, ASN1_TIME *nextupd); +Q_AUTOTEST_EXPORT int q_OCSP_basic_sign(OCSP_BASICRESP *brsp, X509 *signer, EVP_PKEY *key, const EVP_MD *dgst, + STACK_OF(X509) *certs, unsigned long flags); +Q_AUTOTEST_EXPORT OCSP_BASICRESP *q_OCSP_BASICRESP_new(); +Q_AUTOTEST_EXPORT void q_OCSP_BASICRESP_free(OCSP_BASICRESP *bs); +int q_OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags); +int q_OCSP_resp_count(OCSP_BASICRESP *bs); +OCSP_SINGLERESP *q_OCSP_resp_get0(OCSP_BASICRESP *bs, int idx); +int q_OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, ASN1_GENERALIZEDTIME **revtime, + ASN1_GENERALIZEDTIME **thisupd, ASN1_GENERALIZEDTIME **nextupd); +int q_OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec); +int q_OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, ASN1_OCTET_STRING **pikeyHash, + ASN1_INTEGER **pserial, OCSP_CERTID *cid); + +const STACK_OF(X509) *q_OCSP_resp_get0_certs(const OCSP_BASICRESP *bs); +Q_AUTOTEST_EXPORT OCSP_CERTID *q_OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer); +Q_AUTOTEST_EXPORT void q_OCSP_CERTID_free(OCSP_CERTID *cid); +int q_OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b); + +#define q_SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ + q_SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, arg) + +#define q_SSL_CTX_set_tlsext_status_cb(ssl, cb) \ + q_SSL_CTX_callback_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, GenericCallbackType(cb)) + +# define q_SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ + q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, arglen, arg) + +#endif // ocsp + + +void *q_CRYPTO_malloc(size_t num, const char *file, int line); +#define q_OPENSSL_malloc(num) q_CRYPTO_malloc(num, "", 0) + QT_END_NAMESPACE #endif diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp index bc4fd9dc85..f5aab821ea 100644 --- a/src/network/ssl/qsslsocket_opensslpre11.cpp +++ b/src/network/ssl/qsslsocket_opensslpre11.cpp @@ -251,21 +251,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if QT_CONFIG(library) //load symbols needed to receive certificates from system store -#if defined(Q_OS_WIN) - HINSTANCE hLib = LoadLibraryW(L"Crypt32"); - if (hLib) { - ptrCertOpenSystemStoreW = reinterpret_cast<PtrCertOpenSystemStoreW>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertOpenSystemStoreW"))); - ptrCertFindCertificateInStore = reinterpret_cast<PtrCertFindCertificateInStore>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertFindCertificateInStore"))); - ptrCertCloseStore = reinterpret_cast<PtrCertCloseStore>( - reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertCloseStore"))); - if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) - qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen - } else { - qCWarning(lcSsl, "could not load crypt32 library"); // should never happen - } -#elif defined(Q_OS_QNX) +#if defined(Q_OS_QNX) s_loadRootCertsOnDemand = true; #elif defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there) diff --git a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h index b7bac5d2a2..46b6505346 100644 --- a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h +++ b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h @@ -89,9 +89,7 @@ void q_ERR_free_strings(); void q_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a); void q_EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L typedef _STACK STACK; -#endif // The typedef we use to make our pre 1.1 code look more like 1.1 (less ifdefs). typedef STACK OPENSSL_STACK; @@ -111,22 +109,13 @@ void q_sk_free(STACK *a); // address of this: #define q_OPENSSL_sk_free q_sk_free -#if OPENSSL_VERSION_NUMBER >= 0x10000000L void *q_sk_value(STACK *a, int b); void q_sk_push(STACK *st, void *data); -#else -char *q_sk_value(STACK *a, int b); -void q_sk_push(STACK *st, char *data); -#endif // OPENSSL_VERSION_NUMBER >= 0x10000000L #define q_OPENSSL_sk_value(a, b) q_sk_value(a, b) #define q_OPENSSL_sk_push(st, data) q_sk_push(st, data) -#if OPENSSL_VERSION_NUMBER >= 0x10000000L SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a); -#else -SSL_CTX *q_SSL_CTX_new(SSL_METHOD *a); -#endif int q_SSL_library_init(); void q_SSL_load_error_strings(); @@ -135,49 +124,14 @@ void q_SSL_load_error_strings(); int q_SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); #endif -#if OPENSSL_VERSION_NUMBER >= 0x10000000L -#ifndef OPENSSL_NO_SSL2 -const SSL_METHOD *q_SSLv2_client_method(); -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -const SSL_METHOD *q_SSLv3_client_method(); -#endif const SSL_METHOD *q_SSLv23_client_method(); const SSL_METHOD *q_TLSv1_client_method(); const SSL_METHOD *q_TLSv1_1_client_method(); const SSL_METHOD *q_TLSv1_2_client_method(); -#ifndef OPENSSL_NO_SSL2 -const SSL_METHOD *q_SSLv2_server_method(); -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -const SSL_METHOD *q_SSLv3_server_method(); -#endif const SSL_METHOD *q_SSLv23_server_method(); const SSL_METHOD *q_TLSv1_server_method(); const SSL_METHOD *q_TLSv1_1_server_method(); const SSL_METHOD *q_TLSv1_2_server_method(); -#else -#ifndef OPENSSL_NO_SSL2 -SSL_METHOD *q_SSLv2_client_method(); -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -SSL_METHOD *q_SSLv3_client_method(); -#endif -SSL_METHOD *q_SSLv23_client_method(); -SSL_METHOD *q_TLSv1_client_method(); -SSL_METHOD *q_TLSv1_1_client_method(); -SSL_METHOD *q_TLSv1_2_client_method(); -#ifndef OPENSSL_NO_SSL2 -SSL_METHOD *q_SSLv2_server_method(); -#endif -#ifndef OPENSSL_NO_SSL3_METHOD -SSL_METHOD *q_SSLv3_server_method(); -#endif -SSL_METHOD *q_SSLv23_server_method(); -SSL_METHOD *q_TLSv1_server_method(); -SSL_METHOD *q_TLSv1_1_server_method(); -SSL_METHOD *q_TLSv1_2_server_method(); -#endif STACK_OF(X509) *q_X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); @@ -218,6 +172,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length); #define q_SSL_SESSION_get_ticket_lifetime_hint(s) ((s)->tlsext_tick_lifetime_hint) #define q_RSA_bits(rsa) q_BN_num_bits((rsa)->n) #define q_DSA_bits(dsa) q_BN_num_bits((dsa)->p) +#define q_DH_bits(dsa) q_BN_num_bits((dh)->p) #define q_X509_STORE_set_verify_cb(s,c) X509_STORE_set_verify_cb_func((s),(c)) char *q_CONF_get1_default_config_file(); diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 6f34c6c888..2f394f013b 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -89,14 +89,6 @@ QT_BEGIN_NAMESPACE typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*); #endif -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - typedef HCERTSTORE (WINAPI *PtrCertOpenSystemStoreW)(HCRYPTPROV_LEGACY, LPCWSTR); - typedef PCCERT_CONTEXT (WINAPI *PtrCertFindCertificateInStore)(HCERTSTORE, DWORD, DWORD, DWORD, const void*, PCCERT_CONTEXT); - typedef BOOL (WINAPI *PtrCertCloseStore)(HCERTSTORE, DWORD); -#endif // Q_OS_WIN && !Q_OS_WINRT - - - class QSslSocketPrivate : public QTcpSocketPrivate { Q_DECLARE_PUBLIC(QSslSocket) @@ -155,12 +147,6 @@ public: const QString &peerName); Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW; - static PtrCertFindCertificateInStore ptrCertFindCertificateInStore; - static PtrCertCloseStore ptrCertCloseStore; -#endif // Q_OS_WIN && !Q_OS_WINRT - // The socket itself, including private slots. QTcpSocket *plainSocket; void createPlainSocket(QIODevice::OpenMode openMode); @@ -222,6 +208,11 @@ protected: bool flushTriggered; }; +#if QT_CONFIG(securetransport) +// Implemented in qsslsocket_qt.cpp +QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase); +#endif + QT_END_NAMESPACE #endif diff --git a/src/network/ssl/qsslsocket_qt.cpp b/src/network/ssl/qsslsocket_qt.cpp new file mode 100644 index 0000000000..b0fb60ea76 --- /dev/null +++ b/src/network/ssl/qsslsocket_qt.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtCore/qbytearray.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qmessageauthenticationcode.h> + +#include "qsslsocket_p.h" +#include "qasn1element_p.h" +#include "qsslkey_p.h" + +QT_BEGIN_NAMESPACE + +/* + PKCS12 helpers. +*/ + +static QAsn1Element wrap(quint8 type, const QAsn1Element &child) +{ + QByteArray value; + QDataStream stream(&value, QIODevice::WriteOnly); + child.write(stream); + return QAsn1Element(type, value); +} + +static QAsn1Element _q_PKCS7_data(const QByteArray &data) +{ + QVector<QAsn1Element> items; + items << QAsn1Element::fromObjectId("1.2.840.113549.1.7.1"); + items << wrap(QAsn1Element::Context0Type, + QAsn1Element(QAsn1Element::OctetStringType, data)); + return QAsn1Element::fromVector(items); +} + +/*! + PKCS #12 key derivation. + + Some test vectors: + http://www.drh-consultancy.demon.co.uk/test.txt +*/ +static QByteArray _q_PKCS12_keygen(char id, const QByteArray &salt, const QString &passPhrase, int n, int r) +{ + const int u = 20; + const int v = 64; + + // password formatting + QByteArray passUnicode(passPhrase.size() * 2 + 2, '\0'); + char *p = passUnicode.data(); + for (int i = 0; i < passPhrase.size(); ++i) { + quint16 ch = passPhrase[i].unicode(); + *(p++) = (ch & 0xff00) >> 8; + *(p++) = (ch & 0xff); + } + + // prepare I + QByteArray D(64, id); + QByteArray S, P; + const int sSize = v * ((salt.size() + v - 1) / v); + S.resize(sSize); + for (int i = 0; i < sSize; ++i) + S[i] = salt[i % salt.size()]; + const int pSize = v * ((passUnicode.size() + v - 1) / v); + P.resize(pSize); + for (int i = 0; i < pSize; ++i) + P[i] = passUnicode[i % passUnicode.size()]; + QByteArray I = S + P; + + // apply hashing + const int c = (n + u - 1) / u; + QByteArray A; + QByteArray B; + B.resize(v); + QCryptographicHash hash(QCryptographicHash::Sha1); + for (int i = 0; i < c; ++i) { + // hash r iterations + QByteArray Ai = D + I; + for (int j = 0; j < r; ++j) { + hash.reset(); + hash.addData(Ai); + Ai = hash.result(); + } + + for (int j = 0; j < v; ++j) + B[j] = Ai[j % u]; + + // modify I as Ij = (Ij + B + 1) modulo 2^v + for (int p = 0; p < I.size(); p += v) { + quint8 carry = 1; + for (int j = v - 1; j >= 0; --j) { + quint16 v = quint8(I[p + j]) + quint8(B[j]) + carry; + I[p + j] = v & 0xff; + carry = (v & 0xff00) >> 8; + } + } + A += Ai; + } + return A.left(n); +} + +static QByteArray _q_PKCS12_salt() +{ + QByteArray salt; + salt.resize(8); + for (int i = 0; i < salt.size(); ++i) + salt[i] = (qrand() & 0xff); + return salt; +} + +static QByteArray _q_PKCS12_certBag(const QSslCertificate &cert) +{ + QVector<QAsn1Element> items; + items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.3"); + + // certificate + QVector<QAsn1Element> certItems; + certItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.22.1"); + certItems << wrap(QAsn1Element::Context0Type, + QAsn1Element(QAsn1Element::OctetStringType, cert.toDer())); + items << wrap(QAsn1Element::Context0Type, + QAsn1Element::fromVector(certItems)); + + // local key id + const QByteArray localKeyId = cert.digest(QCryptographicHash::Sha1); + QVector<QAsn1Element> idItems; + idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21"); + idItems << wrap(QAsn1Element::SetType, + QAsn1Element(QAsn1Element::OctetStringType, localKeyId)); + items << wrap(QAsn1Element::SetType, QAsn1Element::fromVector(idItems)); + + // dump + QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items)); + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + root.write(stream); + return ba; +} + +static QAsn1Element _q_PKCS12_key(const QSslKey &key) +{ + Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa); + + QVector<QAsn1Element> keyItems; + keyItems << QAsn1Element::fromInteger(0); + QVector<QAsn1Element> algoItems; + if (key.algorithm() == QSsl::Rsa) + algoItems << QAsn1Element::fromObjectId(RSA_ENCRYPTION_OID); + else if (key.algorithm() == QSsl::Dsa) + algoItems << QAsn1Element::fromObjectId(DSA_ENCRYPTION_OID); + algoItems << QAsn1Element(QAsn1Element::NullType); + keyItems << QAsn1Element::fromVector(algoItems); + keyItems << QAsn1Element(QAsn1Element::OctetStringType, key.toDer()); + return QAsn1Element::fromVector(keyItems); +} + +static QByteArray _q_PKCS12_shroudedKeyBag(const QSslKey &key, const QString &passPhrase, const QByteArray &localKeyId) +{ + const int iterations = 2048; + QByteArray salt = _q_PKCS12_salt(); + QByteArray cKey = _q_PKCS12_keygen(1, salt, passPhrase, 24, iterations); + QByteArray cIv = _q_PKCS12_keygen(2, salt, passPhrase, 8, iterations); + + // prepare and encrypt data + QByteArray plain; + QDataStream plainStream(&plain, QIODevice::WriteOnly); + _q_PKCS12_key(key).write(plainStream); + QByteArray crypted = QSslKeyPrivate::encrypt(QSslKeyPrivate::DesEde3Cbc, + plain, cKey, cIv); + + QVector<QAsn1Element> items; + items << QAsn1Element::fromObjectId("1.2.840.113549.1.12.10.1.2"); + + // key + QVector<QAsn1Element> keyItems; + QVector<QAsn1Element> algoItems; + algoItems << QAsn1Element::fromObjectId("1.2.840.113549.1.12.1.3"); + QVector<QAsn1Element> paramItems; + paramItems << QAsn1Element(QAsn1Element::OctetStringType, salt); + paramItems << QAsn1Element::fromInteger(iterations); + algoItems << QAsn1Element::fromVector(paramItems); + keyItems << QAsn1Element::fromVector(algoItems); + keyItems << QAsn1Element(QAsn1Element::OctetStringType, crypted); + items << wrap(QAsn1Element::Context0Type, + QAsn1Element::fromVector(keyItems)); + + // local key id + QVector<QAsn1Element> idItems; + idItems << QAsn1Element::fromObjectId("1.2.840.113549.1.9.21"); + idItems << wrap(QAsn1Element::SetType, + QAsn1Element(QAsn1Element::OctetStringType, localKeyId)); + items << wrap(QAsn1Element::SetType, + QAsn1Element::fromVector(idItems)); + + // dump + QAsn1Element root = wrap(QAsn1Element::SequenceType, QAsn1Element::fromVector(items)); + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + root.write(stream); + return ba; +} + +static QByteArray _q_PKCS12_bag(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase) +{ + QVector<QAsn1Element> items; + + // certs + for (int i = 0; i < certs.size(); ++i) + items << _q_PKCS7_data(_q_PKCS12_certBag(certs[i])); + + // key + if (!key.isNull()) { + const QByteArray localKeyId = certs.first().digest(QCryptographicHash::Sha1); + items << _q_PKCS7_data(_q_PKCS12_shroudedKeyBag(key, passPhrase, localKeyId)); + } + + // dump + QAsn1Element root = QAsn1Element::fromVector(items); + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + root.write(stream); + return ba; +} + +static QAsn1Element _q_PKCS12_mac(const QByteArray &data, const QString &passPhrase) +{ + const int iterations = 2048; + + // salt generation + QByteArray macSalt = _q_PKCS12_salt(); + QByteArray key = _q_PKCS12_keygen(3, macSalt, passPhrase, 20, iterations); + + // HMAC calculation + QMessageAuthenticationCode hmac(QCryptographicHash::Sha1, key); + hmac.addData(data); + + QVector<QAsn1Element> algoItems; + algoItems << QAsn1Element::fromObjectId("1.3.14.3.2.26"); + algoItems << QAsn1Element(QAsn1Element::NullType); + + QVector<QAsn1Element> digestItems; + digestItems << QAsn1Element::fromVector(algoItems); + digestItems << QAsn1Element(QAsn1Element::OctetStringType, hmac.result()); + + QVector<QAsn1Element> macItems; + macItems << QAsn1Element::fromVector(digestItems); + macItems << QAsn1Element(QAsn1Element::OctetStringType, macSalt); + macItems << QAsn1Element::fromInteger(iterations); + return QAsn1Element::fromVector(macItems); +} + +QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase) +{ + QVector<QAsn1Element> items; + + // version + items << QAsn1Element::fromInteger(3); + + // auth safe + const QByteArray data = _q_PKCS12_bag(certs, key, passPhrase); + items << _q_PKCS7_data(data); + + // HMAC + items << _q_PKCS12_mac(data, passPhrase); + + // dump + QAsn1Element root = QAsn1Element::fromVector(items); + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + root.write(stream); + return ba; +} + +QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp index cc69b9ac96..d54ac2ad73 100644 --- a/src/network/ssl/qsslsocket_winrt.cpp +++ b/src/network/ssl/qsslsocket_winrt.cpp @@ -207,9 +207,9 @@ void QSslSocketPrivate::resetDefaultCiphers() QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers() { QList<QSslCipher> ciphers; - const QString protocolStrings[] = { QStringLiteral("SSLv3"), QStringLiteral("TLSv1"), + const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") }; - const QSsl::SslProtocol protocols[] = { QSsl::SslV3, QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 }; + const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 }; const int size = static_cast<int>(ARRAYSIZE(protocols)); ciphers.reserve(size); for (int i = 0; i < size; ++i) { @@ -234,10 +234,14 @@ void QSslSocketBackendPrivate::startClientEncryption() QSsl::SslProtocol protocol = q->protocol(); switch (q->protocol()) { - case QSsl::AnyProtocol: + case QSsl::SslV2: case QSsl::SslV3: + setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, + QStringLiteral("unsupported protocol")); + return; + case QSsl::AnyProtocol: case QSsl::TlsV1SslV3: - protectionLevel = SocketProtectionLevel_Ssl; // Only use this value if weak cipher support is required + protectionLevel = SocketProtectionLevel_Tls10; break; case QSsl::TlsV1_0: protectionLevel = SocketProtectionLevel_Tls10; diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 6975264038..b5603c1258 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -56,6 +56,7 @@ qtConfig(ssl) { ssl/qsslkey_mac.cpp \ ssl/qsslsocket_mac_shared.cpp \ ssl/qsslsocket_mac.cpp \ + ssl/qsslsocket_qt.cpp \ ssl/qsslellipticcurve_dummy.cpp } |