diff options
author | Richard J. Moore <rich@kde.org> | 2017-03-23 12:43:22 +0100 |
---|---|---|
committer | André Klitzing <aklitzing@gmail.com> | 2017-07-04 18:03:59 +0000 |
commit | cfbe03a6e035ab3cce5f04962cddd06bd414dcea (patch) | |
tree | 6623e0eac0924a92662d3953609d84d4d94dda8d /src/network/ssl/qsslkey_openssl.cpp | |
parent | 10de063ff12cdba07b4620182aced8ed05ee3505 (diff) |
QSslSocket: OpenSSL 1.1 backend
This patch-set implements a new QSslSocket backend based on OpenSSL 1.1.
1. General.
The code in this patch was organized to achieve these (somewhat contradicting)
objectives:
- keep the new code free of #if-ery, as far as possible;
- make it easy to clean away dead code when we're eventually able to retire
out-dated OpenSSL versions;
- reduce the amount of code duplication.
If changes in some file/component were insignificant (~5 one-liners per file),
we still use pp-checks like: #if QT_CONFIG(opensslv11) ... #else ... #endif -
the logic is simple and it's still easy to clean the code if we remove the legacy
back-end. Where it saved #if-ery, we also introduced 'forward-compatible'
macros implementing equivalents of 1.1 functions using older OpenSSL.
In case some class contains a lot of version-specific ifdefs (particularly where
nested #if-ery was complex) we choose to split code into: "pre11" h/cpp files,
"shared" h/cpp files (they preserve their original names, e.g qsslsocket_openssl.cpp)
and "11" h/cpp files. If in future we remove the legacy back-end, "pre11" should be
removed; "shared" and "11" parts - merged.
2. Configuration.
We introduced a new feature 'opensslv11' which complements the pre-existing
'openssl' and 'openssl-linked' features. The 'opensslv11' feature is enabled
by a simple test which either compiles successfully or ends in a compilation
error, depending on a value of the OPENSSL_VERSION_NUMBER constant. If the
feature was enabled, we also append an additional compilation flag
-DOPENSSL_API_COMPAT=0x10100000L to make sure our new code does not contain
deprecated structures, function calls, macro-invocations from OpenSSL < 1.1.
Change-Id: I2064efbe9685def5d2bb2233a66f7581954fb74a
Reviewed-by: André Klitzing <aklitzing@gmail.com>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/network/ssl/qsslkey_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslkey_openssl.cpp | 79 |
1 files changed, 53 insertions, 26 deletions
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp index 79df33ecca..be7033c8aa 100644 --- a/src/network/ssl/qsslkey_openssl.cpp +++ b/src/network/ssl/qsslkey_openssl.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2016 Richard J. Moore <rich@kde.org> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtNetwork module of the Qt Toolkit. @@ -84,33 +85,30 @@ void QSslKeyPrivate::clear(bool deep) bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey) { - if (pkey->type == EVP_PKEY_RSA) { +#if QT_CONFIG(opensslv11) + const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey)); +#else + const int keyType = pkey->type; +#endif + if (keyType == EVP_PKEY_RSA) { isNull = false; algorithm = QSsl::Rsa; type = QSsl::PrivateKey; - - rsa = q_RSA_new(); - memcpy(rsa, q_EVP_PKEY_get1_RSA(pkey), sizeof(RSA)); - + rsa = q_EVP_PKEY_get1_RSA(pkey); return true; - } - else if (pkey->type == EVP_PKEY_DSA) { + } else if (keyType == EVP_PKEY_DSA) { isNull = false; algorithm = QSsl::Dsa; type = QSsl::PrivateKey; - - dsa = q_DSA_new(); - memcpy(dsa, q_EVP_PKEY_get1_DSA(pkey), sizeof(DSA)); - + dsa = q_EVP_PKEY_get1_DSA(pkey); return true; } #ifndef OPENSSL_NO_EC - else if (pkey->type == EVP_PKEY_EC) { + else if (keyType == EVP_PKEY_EC) { isNull = false; algorithm = QSsl::Ec; type = QSsl::PrivateKey; - ec = q_EC_KEY_dup(q_EVP_PKEY_get1_EC_KEY(pkey)); - + ec = q_EVP_PKEY_get1_EC_KEY(pkey); return true; } #endif @@ -178,8 +176,8 @@ int QSslKeyPrivate::length() const return -1; switch (algorithm) { - case QSsl::Rsa: return q_BN_num_bits(rsa->n); - case QSsl::Dsa: return q_BN_num_bits(dsa->p); + case QSsl::Rsa: return q_RSA_bits(rsa); + case QSsl::Dsa: return q_DSA_bits(dsa); #ifndef OPENSSL_NO_EC case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec)); #endif @@ -273,7 +271,13 @@ Qt::HANDLE QSslKeyPrivate::handle() const static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, int enc) { - EVP_CIPHER_CTX ctx; +#if QT_CONFIG(opensslv11) + EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new(); +#else + EVP_CIPHER_CTX evpCipherContext; + EVP_CIPHER_CTX *ctx = &evpCipherContext; +#endif + const EVP_CIPHER* type = 0; int i = 0, len = 0; @@ -291,21 +295,44 @@ static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, QByteArray output; output.resize(data.size() + EVP_MAX_BLOCK_LENGTH); - q_EVP_CIPHER_CTX_init(&ctx); - q_EVP_CipherInit(&ctx, type, NULL, NULL, enc); - q_EVP_CIPHER_CTX_set_key_length(&ctx, key.size()); + +#if QT_CONFIG(opensslv11) + q_EVP_CIPHER_CTX_reset(ctx); +#else + q_EVP_CIPHER_CTX_init(ctx); +#endif + + q_EVP_CipherInit(ctx, type, NULL, NULL, enc); + q_EVP_CIPHER_CTX_set_key_length(ctx, key.size()); if (cipher == QSslKeyPrivate::Rc2Cbc) - q_EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), NULL); - q_EVP_CipherInit(&ctx, NULL, + q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), NULL); + +#if QT_CONFIG(opensslv11) + // EVP_CipherInit in 1.1 resets the context thus making the calls above useless. + // We call EVP_CipherInit_ex instead. + q_EVP_CipherInit_ex(ctx, nullptr, nullptr, + reinterpret_cast<const unsigned char *>(key.constData()), + reinterpret_cast<const unsigned char *>(iv.constData()), + enc); +#else + q_EVP_CipherInit(ctx, NULL, reinterpret_cast<const unsigned char *>(key.constData()), reinterpret_cast<const unsigned char *>(iv.constData()), enc); - q_EVP_CipherUpdate(&ctx, +#endif // opensslv11 + + q_EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char *>(output.data()), &len, reinterpret_cast<const unsigned char *>(data.constData()), data.size()); - q_EVP_CipherFinal(&ctx, + q_EVP_CipherFinal(ctx, reinterpret_cast<unsigned char *>(output.data()) + len, &i); len += i; - q_EVP_CIPHER_CTX_cleanup(&ctx); + +#if QT_CONFIG(opensslv11) + q_EVP_CIPHER_CTX_reset(ctx); + q_EVP_CIPHER_CTX_free(ctx); +#else + q_EVP_CIPHER_CTX_cleanup(ctx); +#endif return output.left(len); } |