diff options
Diffstat (limited to 'src/plugins/tls/openssl/qtlskey_openssl.cpp')
-rw-r--r-- | src/plugins/tls/openssl/qtlskey_openssl.cpp | 194 |
1 files changed, 112 insertions, 82 deletions
diff --git a/src/plugins/tls/openssl/qtlskey_openssl.cpp b/src/plugins/tls/openssl/qtlskey_openssl.cpp index 5333623d70..294fc2ffcd 100644 --- a/src/plugins/tls/openssl/qtlskey_openssl.cpp +++ b/src/plugins/tls/openssl/qtlskey_openssl.cpp @@ -1,43 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qsslsocket_openssl_symbols_p.h" +#include "qtlsbackend_openssl_p.h" #include "qtlskey_openssl_p.h" #include <QtNetwork/private/qsslkey_p.h> @@ -84,6 +49,16 @@ void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteA void *phrase = const_cast<char *>(passPhrase.data()); +#ifdef OPENSSL_NO_DEPRECATED_3_0 + if (type == QSsl::PublicKey) + genericKey = q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase); + else + genericKey = q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase); + keyIsNull = !genericKey; + if (keyIsNull) + QTlsBackendOpenSSL::logAndClearErrorQueue(); +#else + if (algorithm == QSsl::Rsa) { RSA *result = (type == QSsl::PublicKey) ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, nullptr, phrase) @@ -112,8 +87,10 @@ void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteA : q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase); if (ec && ec == result) keyIsNull = false; -#endif +#endif // OPENSSL_NO_EC } + +#endif // OPENSSL_NO_DEPRECATED_3_0 } QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const @@ -124,19 +101,19 @@ QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QBy QByteArray der(pem); int headerIndex = der.indexOf(header); - int footerIndex = der.indexOf(footer, headerIndex + header.length()); + int footerIndex = der.indexOf(footer, headerIndex + header.size()); if (type() != QSsl::PublicKey) { if (headerIndex == -1 || footerIndex == -1) { header = pkcs8Header(true); footer = pkcs8Footer(true); headerIndex = der.indexOf(header); - footerIndex = der.indexOf(footer, headerIndex + header.length()); + footerIndex = der.indexOf(footer, headerIndex + header.size()); } if (headerIndex == -1 || footerIndex == -1) { header = pkcs8Header(false); footer = pkcs8Footer(false); headerIndex = der.indexOf(header); - footerIndex = der.indexOf(footer, headerIndex + header.length()); + footerIndex = der.indexOf(footer, headerIndex + header.size()); } } if (headerIndex == -1 || footerIndex == -1) @@ -147,7 +124,7 @@ QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QBy if (der.contains("Proc-Type:")) { // taken from QHttpNetworkReplyPrivate::parseHeader int i = 0; - while (i < der.count()) { + while (i < der.size()) { int j = der.indexOf(':', i); // field-name if (j == -1) break; @@ -166,7 +143,7 @@ QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QBy int length = i -(hasCR ? 1: 0) - j; value += der.mid(j, length).trimmed(); j = ++i; - } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t')); + } while (i < der.size() && (der.at(i) == ' ' || der.at(i) == '\t')); if (i == -1) break; // something is wrong @@ -182,6 +159,7 @@ void TlsKeyOpenSSL::clear(bool deep) { keyIsNull = true; +#ifndef OPENSSL_NO_DEPRECATED_3_0 if (algorithm() == QSsl::Rsa && rsa) { if (deep) q_RSA_free(rsa); @@ -204,18 +182,30 @@ void TlsKeyOpenSSL::clear(bool deep) ec = nullptr; } #endif +#endif // OPENSSL_NO_DEPRECATED_3_0 + if (algorithm() == QSsl::Opaque && opaque) { if (deep) q_EVP_PKEY_free(opaque); opaque = nullptr; } + + if (genericKey) { + // None of the above cleared it. genericKey is either + // initialised by PEM read operation, or from X509, and + // we are the owners and not sharing. So we free it. + q_EVP_PKEY_free(genericKey); + genericKey = nullptr; + } } Qt::HANDLE TlsKeyOpenSSL::handle() const { - switch (keyAlgorithm) { - case QSsl::Opaque: + if (keyAlgorithm == QSsl::Opaque) return Qt::HANDLE(opaque); + +#ifndef OPENSSL_NO_DEPRECATED_3_0 + switch (keyAlgorithm) { case QSsl::Rsa: return Qt::HANDLE(rsa); case QSsl::Dsa: @@ -229,6 +219,11 @@ Qt::HANDLE TlsKeyOpenSSL::handle() const default: return Qt::HANDLE(nullptr); } +#else + qCWarning(lcTlsBackend, + "This version of OpenSSL disabled direct manipulation with RSA/DSA/DH/EC_KEY structures, consider using QSsl::Opaque instead."); + return Qt::HANDLE(genericKey); +#endif } int TlsKeyOpenSSL::length() const @@ -236,6 +231,7 @@ int TlsKeyOpenSSL::length() const if (isNull() || algorithm() == QSsl::Opaque) return -1; +#ifndef OPENSSL_NO_DEPRECATED_3_0 switch (algorithm()) { case QSsl::Rsa: return q_RSA_bits(rsa); @@ -250,6 +246,10 @@ int TlsKeyOpenSSL::length() const default: return -1; } +#else // OPENSSL_NO_DEPRECATED_3_0 + Q_ASSERT(genericKey); + return q_EVP_PKEY_get_bits(genericKey); +#endif // OPENSSL_NO_DEPRECATED_3_0 } QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const @@ -272,54 +272,61 @@ QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);}); - bool fail = false; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + +#define write_pubkey(alg, key) q_PEM_write_bio_##alg##_PUBKEY(bio, key) +#define write_privatekey(alg, key) \ + q_PEM_write_bio_##alg##PrivateKey(bio, key, cipher, (uchar *)passPhrase.data(), \ + passPhrase.size(), nullptr, nullptr) + +#else + +#define write_pubkey(alg, key) q_PEM_write_bio_PUBKEY(bio, genericKey) +#define write_privatekey(alg, key) \ + q_PEM_write_bio_PrivateKey_traditional(bio, genericKey, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr) + +#endif // OPENSSL_NO_DEPRECATED_3_0 + bool fail = false; if (algorithm() == QSsl::Rsa) { if (type() == QSsl::PublicKey) { - if (!q_PEM_write_bio_RSA_PUBKEY(bio, rsa)) - fail = true; - } else { - if (!q_PEM_write_bio_RSAPrivateKey( - bio, rsa, cipher, (uchar *)passPhrase.data(), - passPhrase.size(), nullptr, nullptr)) { + if (!write_pubkey(RSA, rsa)) fail = true; - } + } else if (!write_privatekey(RSA, rsa)) { + fail = true; } } else if (algorithm() == QSsl::Dsa) { if (type() == QSsl::PublicKey) { - if (!q_PEM_write_bio_DSA_PUBKEY(bio, dsa)) - fail = true; - } else { - if (!q_PEM_write_bio_DSAPrivateKey( - bio, dsa, cipher, (uchar *)passPhrase.data(), - passPhrase.size(), nullptr, nullptr)) { + if (!write_pubkey(DSA, dsa)) fail = true; - } + } else if (!write_privatekey(DSA, dsa)) { + fail = true; } } else if (algorithm() == QSsl::Dh) { +#ifdef OPENSSL_NO_DEPRECATED_3_0 + EVP_PKEY *result = genericKey; +#else EVP_PKEY *result = q_EVP_PKEY_new(); + const auto guard = qScopeGuard([result]{if (result) q_EVP_PKEY_free(result);}); if (!result || !q_EVP_PKEY_set1_DH(result, dh)) { fail = true; - } else if (type() == QSsl::PublicKey) { + } else +#endif + 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)) { + } 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)) + if (!write_pubkey(EC, ec)) fail = true; } else { - if (!q_PEM_write_bio_ECPrivateKey( - bio, ec, cipher, (uchar *)passPhrase.data(), - passPhrase.size(), nullptr, nullptr)) { + if (!write_privatekey(EC, ec)) fail = true; - } } #endif } else { @@ -332,6 +339,8 @@ QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const const long size = q_BIO_get_mem_data(bio, &data); if (size > 0 && data) pem = QByteArray(data, size); + } else { + QTlsBackendOpenSSL::logAndClearErrorQueue(); } return pem; @@ -356,34 +365,37 @@ bool TlsKeyOpenSSL::fromEVP_PKEY(EVP_PKEY *pkey) if (!pkey) return false; +#ifndef OPENSSL_NO_DEPRECATED_3_0 +#define get_key(key, alg) key = q_EVP_PKEY_get1_##alg(pkey) +#else +#define get_key(key, alg) q_EVP_PKEY_up_ref(pkey); genericKey = pkey; +#endif + switch (q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey))) { case EVP_PKEY_RSA: keyIsNull = false; keyAlgorithm = QSsl::Rsa; keyType = QSsl::PrivateKey; - rsa = q_EVP_PKEY_get1_RSA(pkey); - + get_key(rsa, RSA); return true; case EVP_PKEY_DSA: keyIsNull = false; keyAlgorithm = QSsl::Dsa; keyType = QSsl::PrivateKey; - dsa = q_EVP_PKEY_get1_DSA(pkey); - + get_key(dsa, DSA); return true; case EVP_PKEY_DH: keyIsNull = false; keyAlgorithm = QSsl::Dh; keyType = QSsl::PrivateKey; - dh = q_EVP_PKEY_get1_DH(pkey); + get_key(dh, DH); return true; #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: keyIsNull = false; keyAlgorithm = QSsl::Ec; keyType = QSsl::PrivateKey; - ec = q_EVP_PKEY_get1_EC_KEY(pkey); - + get_key(ec, EC_KEY); return true; #endif default:; @@ -437,7 +449,12 @@ QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new(); q_EVP_CIPHER_CTX_reset(ctx); - q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc); + if (q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc) != 1) { + q_EVP_CIPHER_CTX_free(ctx); + QTlsBackendOpenSSL::logAndClearErrorQueue(); + return {}; + } + q_EVP_CIPHER_CTX_set_key_length(ctx, key.size()); if (cipher == Cipher::Rc2Cbc) q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), nullptr); @@ -478,21 +495,31 @@ TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x) tlsKey->keyType = QSsl::PublicKey; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + +#define get_pubkey(keyName, alg) tlsKey->keyName = q_EVP_PKEY_get1_##alg(pkey) + +#else + +#define get_pubkey(a, b) tlsKey->genericKey = pkey + +#endif + EVP_PKEY *pkey = q_X509_get_pubkey(x); Q_ASSERT(pkey); const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey)); if (keyType == EVP_PKEY_RSA) { - tlsKey->rsa = q_EVP_PKEY_get1_RSA(pkey); + get_pubkey(rsa, RSA); tlsKey->keyAlgorithm = QSsl::Rsa; tlsKey->keyIsNull = false; } else if (keyType == EVP_PKEY_DSA) { - tlsKey->dsa = q_EVP_PKEY_get1_DSA(pkey); + get_pubkey(dsa, DSA); tlsKey->keyAlgorithm = QSsl::Dsa; tlsKey->keyIsNull = false; #ifndef OPENSSL_NO_EC } else if (keyType == EVP_PKEY_EC) { - tlsKey->ec = q_EVP_PKEY_get1_EC_KEY(pkey); + get_pubkey(ec, EC_KEY); tlsKey->keyAlgorithm = QSsl::Ec; tlsKey->keyIsNull = false; #endif @@ -502,7 +529,10 @@ TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x) // error? (key is null) } +#ifndef OPENSSL_NO_DEPRECATED_3_0 q_EVP_PKEY_free(pkey); +#endif + return keyRaii.release(); } |