4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_HasComponent_OpenSSL
7#include <openssl/evp.h>
8#include <openssl/ssl.h>
9#if OPENSSL_VERSION_MAJOR >= 3
10#include <openssl/provider.h>
15#include "Stroika/Foundation/Execution/Exceptions.h"
21using namespace Stroika::Foundation::Cryptography;
22using namespace Stroika::Foundation::Cryptography::Providers::OpenSSL;
23using namespace Stroika::Foundation::Debug;
28#if qStroika_HasComponent_OpenSSL && defined(_MSC_VER)
30#if OPENSSL_VERSION_NUMBER < 0x1010000fL
31#pragma comment(lib, "libeay32.lib")
32#pragma comment(lib, "ssleay32.lib")
34#pragma comment(lib, "libcrypto.lib")
35#pragma comment(lib, "libssl.lib")
36#pragma comment(lib, "ws2_32.lib")
37#pragma comment(lib, "crypt32.lib")
41#if qStroika_HasComponent_OpenSSL
44 void AccumulateIntoSetOfCipherNames_ (const ::EVP_CIPHER* ciph, Set<String>* ciphers)
47 if (ciph !=
nullptr) {
48#if USE_NOISY_TRACE_IN_THIS_MODULE_
49#if OPENSSL_VERSION_MAJOR >= 3
50 DbgTrace (
"cipher: {} (name: {}), provider: {} (name {})"_f, ciph, CipherAlgorithm{ciph}.name (), ::EVP_CIPHER_get0_provider (ciph),
51 (::EVP_CIPHER_get0_provider (ciph) ==
nullptr
53 :
String::FromNarrowSDKString (::OSSL_PROVIDER_get0_name (::EVP_CIPHER_get0_provider (ciph)))));
55 DbgTrace (
"cipher: {} (name: {})"_f, ciph, CipherAlgorithm{ciph}.name ());
58 ciphers->Add (CipherAlgorithm{ciph}.name ());
61 void AccumulateIntoSetOfDigestNames_ (const ::EVP_MD* digest, Set<String>* digestNames)
64 if (digest !=
nullptr) {
65#if USE_NOISY_TRACE_IN_THIS_MODULE_
66#if OPENSSL_VERSION_MAJOR >= 3
67 DbgTrace (
"digest: {} (name: {}), provider: {} (name {})"_f, digest, DigestAlgorithm{digest}.name (), ::EVP_MD_get0_provider (digest),
68 (::EVP_MD_get0_provider (digest) ==
nullptr
70 :
String::FromNarrowSDKString (::OSSL_PROVIDER_get0_name (::EVP_MD_get0_provider (digest)))));
72 DbgTrace (
"digest: {} (name: {})"_f, digest, DigestAlgorithm{digest}.name ());
75 digestNames->Add (DigestAlgorithm{digest}.name ());
85LibraryContext::LibraryInit_::LibraryInit_ ()
87 constexpr auto kOpts_ = OPENSSL_INIT_LOAD_SSL_STRINGS;
88 Verify (::OPENSSL_init_ssl (kOpts_,
nullptr) == 1);
96LibraryContext::LibraryContext ()
97 : availableCipherAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> Set<CipherAlgorithm> {
98 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::availableCipherAlgorithms);
100 Set<String> cipherNames;
101#if OPENSSL_VERSION_MAJOR >= 3
102 ::EVP_CIPHER_do_all_provided (
103 nullptr, [] (::EVP_CIPHER* ciph,
void* arg) { AccumulateIntoSetOfCipherNames_ (ciph,
reinterpret_cast<Set<String>*
> (arg)); }, &cipherNames);
105 ::EVP_CIPHER_do_all_sorted ([] (const ::EVP_CIPHER* ciph, [[maybe_unused]]
const char* from, [[maybe_unused]]
const char* to,
106 void* arg) { AccumulateIntoSetOfCipherNames_ (ciph,
reinterpret_cast<Set<String>*
> (arg)); },
109#if USE_NOISY_TRACE_IN_THIS_MODULE_
110 DbgTrace (
"Found availableCipherAlgorithms-FIRST-PASS (cnt={}): {}"_f, cipherNames.size (), cipherNames);
113 Set<CipherAlgorithm> results{cipherNames.Map<Set<CipherAlgorithm>> (
114 [] (
const String& n) -> optional<CipherAlgorithm> {
return OpenSSL::CipherAlgorithm::GetByNameQuietly (n); })};
115#if USE_NOISY_TRACE_IN_THIS_MODULE_
116 DbgTrace (
"Found availableCipherAlgorithms (cnt={}): {}"_f, results.size (), results);
120 , standardCipherAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<CipherAlgorithm> {
121 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::standardCipherAlgorithms);
123 Set<CipherAlgorithm> results;
125 results += CipherAlgorithms::kAES_128_CBC;
126 results += CipherAlgorithms::kAES_128_ECB;
127 results += CipherAlgorithms::kAES_128_OFB;
128 results += CipherAlgorithms::kAES_128_CFB1;
129 results += CipherAlgorithms::kAES_128_CFB8;
130 results += CipherAlgorithms::kAES_128_CFB128;
131 results += CipherAlgorithms::kAES_192_CBC;
132 results += CipherAlgorithms::kAES_192_ECB;
133 results += CipherAlgorithms::kAES_192_OFB;
134 results += CipherAlgorithms::kAES_192_CFB1;
135 results += CipherAlgorithms::kAES_192_CFB8;
136 results += CipherAlgorithms::kAES_192_CFB128;
137 results += CipherAlgorithms::kAES_256_CBC;
138 results += CipherAlgorithms::kAES_256_ECB;
139 results += CipherAlgorithms::kAES_256_OFB;
140 results += CipherAlgorithms::kAES_256_CFB1;
141 results += CipherAlgorithms::kAES_256_CFB8;
142 results += CipherAlgorithms::kAES_256_CFB128;
152#if OPENSSL_VERSION_MAJOR < 3
153 results += CipherAlgorithms::kBlowfish_CBC;
154 results += CipherAlgorithms::kBlowfish_ECB;
155 results += CipherAlgorithms::kBlowfish_CFB;
156 results += CipherAlgorithms::kBlowfish_OFB;
157 results += CipherAlgorithms::kBlowfish;
158 results += CipherAlgorithms::kRC2_CBC;
159 results += CipherAlgorithms::kRC2_ECB;
160 results += CipherAlgorithms::kRC2_CFB;
161 results += CipherAlgorithms::kRC2_OFB;
162 results += CipherAlgorithms::kRC4;
167 , availableDigestAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<DigestAlgorithm> {
168 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::availableDigestAlgorithms);
171 Set<String> digestNames;
172#if OPENSSL_VERSION_MAJOR >= 3
173 ::EVP_MD_do_all_provided (
174 nullptr, [] (::EVP_MD* md,
void* arg) { AccumulateIntoSetOfDigestNames_ (md,
reinterpret_cast<Set<String>*
> (arg)); }, &digestNames);
176 ::EVP_MD_do_all_sorted ([] (const ::EVP_MD* md, [[maybe_unused]]
const char* from, [[maybe_unused]]
const char* to,
177 void* arg) { AccumulateIntoSetOfDigestNames_ (md,
reinterpret_cast<Set<String>*
> (arg)); },
180#if USE_NOISY_TRACE_IN_THIS_MODULE_
181 DbgTrace (
"Found availableDigestAlgorithms-FIRST-PASS (cnt={}): {}"_f, digestNames.size (), digestNames);
184 Set<DigestAlgorithm> results{digestNames.Map<Set<DigestAlgorithm>> (
185 [] (
const String& n) -> optional<DigestAlgorithm> {
return OpenSSL::DigestAlgorithm::GetByNameQuietly (n); })};
186#if USE_NOISY_TRACE_IN_THIS_MODULE_
187 DbgTrace (
"Found availableDigestAlgorithms (cnt={}): {}"_f, results.size (), results);
191 , standardDigestAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<DigestAlgorithm> {
192 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::standardDigestAlgorithms);
194 Set<DigestAlgorithm> results;
195 results += DigestAlgorithms::kMD5;
196 results += DigestAlgorithms::kSHA1;
197 results += DigestAlgorithms::kSHA1_224;
198 results += DigestAlgorithms::kSHA1_256;
199 results += DigestAlgorithms::kSHA1_384;
200 results += DigestAlgorithms::kSHA1_512;
201 results += DigestAlgorithms::kSHA3_224;
202 results += DigestAlgorithms::kSHA3_256;
203 results += DigestAlgorithms::kSHA3_384;
204 results += DigestAlgorithms::kSHA3_512;
208 LoadProvider (kDefaultProvider);
211LibraryContext ::~LibraryContext ()
214#if OPENSSL_VERSION_MAJOR >= 3
216 for (
auto i : fLoadedProviders_.MappedValues ()) {
217 Verify (::OSSL_PROVIDER_unload (i) == 1);
222void LibraryContext::LoadProvider ([[maybe_unused]]
const String& providerName)
226#if OPENSSL_VERSION_MAJOR >= 3
227 auto p = fLoadedProviders_.LookupOneValue (providerName);
230 DbgTrace (
"calling OSSL_PROVIDER_load"_f);
231 p = ::OSSL_PROVIDER_load (
nullptr, providerName.AsNarrowSDKString ().c_str ());
235 fLoadedProviders_.Add (providerName, p);
237 Require (providerName == kDefaultProvider or providerName == kLegacyProvider);
241void LibraryContext ::UnLoadProvider ([[maybe_unused]]
const String& providerName)
245#if OPENSSL_VERSION_MAJOR >= 3
246 Require (fLoadedProviders_.ContainsKey (providerName));
247 auto providerToMaybeRemove = fLoadedProviders_.LookupOneValue (providerName);
248 fLoadedProviders_.Remove (providerName);
249 if (not fLoadedProviders_.ContainsKey (providerName)) {
250 DbgTrace (
"calling OSSL_PROVIDER_unload"_f);
251 Verify (::OSSL_PROVIDER_unload (providerToMaybeRemove) == 1);
#define RequireNotNull(p)
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
void ThrowIfNull(const Private_::ConstVoidStar &p, const HRESULT &hr)
Template specialization for ThrowIfNull (), for thing being thrown HRESULT - really throw HRESULTErro...