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