Branch data Line data Source code
1 : : // Copyright (C) 2021 The Qt Company Ltd.
2 : : // Copyright (C) 2019 Luxoft Sweden AB
3 : : // Copyright (C) 2018 Pelagicore AG
4 : : // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
5 : :
6 : : #include <QLibrary>
7 : : #include <QString>
8 : : #include <QSslSocket>
9 : :
10 : : #include "libcryptofunction.h"
11 : :
12 : : // we want at least openssl 1.0.1 or 1.1.0
13 : : #define QT_AM_MINIMUM_OPENSSL10_VERSION 0x1000100fL
14 : : #define QT_AM_MINIMUM_OPENSSL11_VERSION 0x1010000fL
15 : : #define QT_AM_MINIMUM_OPENSSL30_VERSION 0x3000000fL
16 : :
17 : : QT_BEGIN_NAMESPACE_AM
18 : :
19 : : // clazy:excludeall=non-pod-global-static
20 : : // AXIVION DISABLE Qt-NonPodGlobalStatic
21 : :
22 : : static QT_AM_LIBCRYPTO_FUNCTION(SSLeay, unsigned long(*)(), 0);
23 : : static QT_AM_LIBCRYPTO_FUNCTION(OPENSSL_add_all_algorithms_noconf, void(*)());
24 : : static QT_AM_LIBCRYPTO_FUNCTION(ERR_load_crypto_strings, void(*)());
25 : :
26 : : static QT_AM_LIBCRYPTO_FUNCTION(OpenSSL_version_num, unsigned long(*)(), 0);
27 : : static QT_AM_LIBCRYPTO_FUNCTION(OPENSSL_init_crypto, int(*)(uint64_t, void *), 0);
28 : :
29 : : struct OSSL_PROVIDER;
30 : : struct OSSL_LIB_CTX;
31 : : static QT_AM_LIBCRYPTO_FUNCTION(OSSL_PROVIDER_load, OSSL_PROVIDER *(*)(OSSL_LIB_CTX *, const char *), nullptr);
32 : :
33 : : // AXIVION ENABLE Qt-NonPodGlobalStatic
34 : :
35 : : QLibrary *Cryptography::LibCryptoFunctionBase::s_library = nullptr;
36 : : bool Cryptography::LibCryptoFunctionBase::s_isOpenSSL11 = false;
37 : : bool Cryptography::LibCryptoFunctionBase::s_isOpenSSL30 = false;
38 : :
39 : 3 : bool Cryptography::LibCryptoFunctionBase::initialize(bool loadOpenSsl3LegacyProvider)
40 : : {
41 [ + - ]: 3 : if (s_library)
42 : : return true;
43 : :
44 : 3 : const char *libname =
45 : : #ifdef Q_OS_WIN32
46 : : "libeay32";
47 : : #else
48 : : "crypto";
49 : : #endif
50 : :
51 : : // Loading libcrypto is a mess, since distros are not creating links for libcrypto.so.1
52 : : // anymore. In order to not duplicate a lot of bad hacks, we simply let QtNetwork do the
53 : : // dirty work.
54 [ + - ]: 3 : if (!QSslSocket::supportsSsl())
55 : : return false;
56 : :
57 [ + - + - ]: 3 : s_library = new QLibrary(QString::fromLatin1(libname), 1);
58 : 3 : bool ok = s_library->load();
59 [ + - ]: 3 : if (!ok) {
60 [ + - + - ]: 9 : s_library->setFileNameAndVersion(QString::fromLatin1(libname), QString());
61 : 3 : ok = s_library->load();
62 : : }
63 [ + - ]: 3 : if (ok) {
64 : 3 : unsigned long version = 0;
65 : :
66 [ + - + - ]: 6 : if (am_OpenSSL_version_num.functionPointer())
67 : 3 : version = am_OpenSSL_version_num(); // 1.1 and 3.x
68 [ # # # # ]: 0 : else if (am_SSLeay.functionPointer())
69 : 0 : version = am_SSLeay(); // 1.0
70 : :
71 [ + - ]: 3 : if (version > 0) {
72 [ + - ]: 3 : if (version >= QT_AM_MINIMUM_OPENSSL11_VERSION) {
73 : 3 : s_isOpenSSL11 = true;
74 : :
75 [ + - ]: 3 : if (version >= QT_AM_MINIMUM_OPENSSL30_VERSION) {
76 : 3 : s_isOpenSSL30 = true;
77 : :
78 [ + + ]: 3 : if (loadOpenSsl3LegacyProvider) {
79 : : // openSSL 3.0 might need the legacy provider to read old PKCS12 certs
80 : 1 : auto legacyLoaded = am_OSSL_PROVIDER_load(nullptr, "legacy");
81 : 1 : auto defaultLoaded = am_OSSL_PROVIDER_load(nullptr, "default");
82 [ - + ]: 1 : if (!legacyLoaded || !defaultLoaded)
83 : 0 : qCritical("Loaded libcrypto version 3, but couldn't load the 'legacy provider' as requested");
84 : : }
85 : : }
86 : :
87 : 3 : return (am_OPENSSL_init_crypto(4 /*OPENSSL_INIT_ADD_ALL_CIPHERS*/
88 : : | 8 /*OPENSSL_INIT_ADD_ALL_DIGESTS*/
89 : 6 : | 2 /*OPENSSL_INIT_LOAD_CRYPTO_STRINGS*/,
90 : 3 : nullptr) == 1);
91 [ # # ]: 0 : } else if (version >= QT_AM_MINIMUM_OPENSSL10_VERSION) {
92 : 0 : am_OPENSSL_add_all_algorithms_noconf();
93 : 0 : am_ERR_load_crypto_strings();
94 : 0 : return true;
95 : : } else {
96 [ # # ]: 0 : qCritical("Loaded libcrypto (%s), but the version is too old: 0x%08lx (minimum supported version is: 0x%08lx)",
97 [ # # ]: 0 : qPrintable(s_library->fileName()), version, QT_AM_MINIMUM_OPENSSL10_VERSION);
98 : : }
99 : : } else {
100 : 0 : qCritical("Could not get version information from libcrypto: neither of the symbols 'SSLeay' or 'OpenSSL_version_num' were found");
101 : : }
102 : 0 : s_library->unload();
103 : : } else {
104 [ # # # # ]: 0 : qCritical("Could not find a suitable libcrypto: %s", qPrintable(s_library->errorString()));
105 : : }
106 [ # # ]: 0 : delete s_library;
107 : 0 : s_library = nullptr;
108 : 0 : return false;
109 : : }
110 : :
111 : 1301 : Cryptography::LibCryptoFunctionBase::LibCryptoFunctionBase(const char *symbol)
112 : 1301 : : m_symbol(symbol)
113 : 1301 : { }
114 : :
115 : 67 : void Cryptography::LibCryptoFunctionBase::resolve()
116 : : {
117 [ + - ]: 67 : if (!m_tried) {
118 [ - + ]: 67 : if (!s_library) {
119 : 0 : qCritical("Failed to resolve libcrypto symbol %s: library not loaded yet", m_symbol);
120 : 0 : return;
121 : : }
122 : 67 : m_functionPtr = s_library->resolve(m_symbol);
123 [ - + ]: 67 : if (!m_functionPtr)
124 [ # # # # ]: 0 : qCritical("Failed to resolve libcrypto symbol %s: %s", m_symbol, qPrintable(s_library->errorString()));
125 : 67 : m_tried = true;
126 : : }
127 : : }
128 : :
129 : : QT_END_NAMESPACE_AM
|