/**************************************************************************** ** ** Copyright (C) 2015 Mikkel Krautz ** Copyright (C) 2016 Richard J. Moore ** 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 "qsslsocket_openssl_symbols_p.h" #include "qtlsbackend_openssl_p.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE #ifndef OPENSSL_NO_DEPRECATED_3_0 namespace { bool isSafeDH(DH *dh) { int status = 0; int bad = 0; // TLSTODO: check it's needed or if supportsSsl() // is enough. QSslSocketPrivate::ensureInitialized(); // From https://wiki.openssl.org/index.php/Diffie-Hellman_parameters: // // The additional call to BN_mod_word(dh->p, 24) // (and unmasking of DH_NOT_SUITABLE_GENERATOR) // is performed to ensure your program accepts // IETF group parameters. OpenSSL checks the prime // is congruent to 11 when g = 2; while the IETF's // primes are congruent to 23 when g = 2. // Without the test, the IETF parameters would // fail validation. For details, see Diffie-Hellman // Parameter Check (when g = 2, must p mod 24 == 11?). // Mark p < 1024 bits as unsafe. if (q_DH_bits(dh) < 1024) return false; if (q_DH_check(dh, &status) != 1) return false; const BIGNUM *p = nullptr; const BIGNUM *q = nullptr; const BIGNUM *g = nullptr; q_DH_get0_pqg(dh, &p, &q, &g); if (q_BN_is_word(const_cast(g), DH_GENERATOR_2)) { const unsigned long residue = q_BN_mod_word(p, 24); if (residue == 11 || residue == 23) status &= ~DH_NOT_SUITABLE_GENERATOR; } bad |= DH_CHECK_P_NOT_PRIME; bad |= DH_CHECK_P_NOT_SAFE_PRIME; bad |= DH_NOT_SUITABLE_GENERATOR; return !(status & bad); } } // unnamed namespace #endif int QTlsBackendOpenSSL::dhParametersFromDer(const QByteArray &der, QByteArray *derData) const { #ifndef OPENSSL_NO_DEPRECATED_3_0 Q_ASSERT(derData); if (der.isEmpty()) return DHParams::InvalidInputDataError; const unsigned char *data = reinterpret_cast(der.data()); const int len = der.size(); // TLSTODO: check it's needed (loading ciphers and certs in // addition to the library!) QSslSocketPrivate::ensureInitialized(); DH *dh = q_d2i_DHparams(nullptr, &data, len); if (dh) { const auto dhRaii = qScopeGuard([dh] {q_DH_free(dh);}); if (isSafeDH(dh)) *derData = der; else return DHParams::UnsafeParametersError; } else { return DHParams::InvalidInputDataError; } #else Q_UNUSED(der); Q_UNUSED(derData); qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed"); #endif return DHParams::NoError; } int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *data) const { #ifndef OPENSSL_NO_DEPRECATED_3_0 Q_ASSERT(data); if (pem.isEmpty()) return DHParams::InvalidInputDataError; // TLSTODO: check it was not a cargo-cult programming in case of // DH ... QSslSocketPrivate::ensureInitialized(); BIO *bio = q_BIO_new_mem_buf(const_cast(pem.data()), pem.size()); if (!bio) return DHParams::InvalidInputDataError; const auto bioRaii = qScopeGuard([bio] { q_BIO_free(bio); }); DH *dh = nullptr; q_PEM_read_bio_DHparams(bio, &dh, nullptr, nullptr); if (dh) { const auto dhGuard = qScopeGuard([dh] { q_DH_free(dh); }); if (isSafeDH(dh)) { char *buf = nullptr; const int len = q_i2d_DHparams(dh, reinterpret_cast(&buf)); if (len > 0) *data = QByteArray(buf, len); else return DHParams::InvalidInputDataError; } else { return DHParams::UnsafeParametersError; } } else { return DHParams::InvalidInputDataError; } #else Q_UNUSED(pem); Q_UNUSED(data); qCWarning(lcTlsBackend, "Diffie-Hellman parameters are not supported, because OpenSSL v3 was built with deprecated API removed"); #endif return DHParams::NoError; } QT_END_NAMESPACE