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
31 void AccumulateIntoSetOfCipherNames_ (const ::EVP_CIPHER* ciph, Set<String>* ciphers)
34 if (ciph !=
nullptr) {
35#if USE_NOISY_TRACE_IN_THIS_MODULE_
36#if OPENSSL_VERSION_MAJOR >= 3
37 DbgTrace (
"cipher: {} (name: {}), provider: {} (name {})"_f, ciph, CipherAlgorithm{ciph}.name (), ::EVP_CIPHER_get0_provider (ciph),
38 (::EVP_CIPHER_get0_provider (ciph) ==
nullptr
40 :
String::FromNarrowSDKString (::OSSL_PROVIDER_get0_name (::EVP_CIPHER_get0_provider (ciph)))));
42 DbgTrace (
"cipher: {} (name: {})"_f, ciph, CipherAlgorithm{ciph}.name ());
45 ciphers->Add (CipherAlgorithm{ciph}.name ());
48 void AccumulateIntoSetOfDigestNames_ (const ::EVP_MD* digest, Set<String>* digestNames)
51 if (digest !=
nullptr) {
52#if USE_NOISY_TRACE_IN_THIS_MODULE_
53#if OPENSSL_VERSION_MAJOR >= 3
54 DbgTrace (
"digest: {} (name: {}), provider: {} (name {})"_f, digest, DigestAlgorithm{digest}.name (), ::EVP_MD_get0_provider (digest),
55 (::EVP_MD_get0_provider (digest) ==
nullptr
57 :
String::FromNarrowSDKString (::OSSL_PROVIDER_get0_name (::EVP_MD_get0_provider (digest)))));
59 DbgTrace (
"digest: {} (name: {})"_f, digest, DigestAlgorithm{digest}.name ());
62 digestNames->Add (DigestAlgorithm{digest}.name ());
72LibraryContext::LibraryInit_::LibraryInit_ ()
74 constexpr auto kOpts_ = OPENSSL_INIT_LOAD_SSL_STRINGS;
75 Verify (::OPENSSL_init_ssl (kOpts_,
nullptr) == 1);
83LibraryContext::LibraryContext ()
84 : availableCipherAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]] const auto* property) -> Set<CipherAlgorithm> {
85 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::availableCipherAlgorithms);
87 Set<String> cipherNames;
88#if OPENSSL_VERSION_MAJOR >= 3
89 ::EVP_CIPHER_do_all_provided (
90 nullptr, [] (::EVP_CIPHER* ciph,
void* arg) { AccumulateIntoSetOfCipherNames_ (ciph,
reinterpret_cast<Set<String>*
> (arg)); }, &cipherNames);
92 ::EVP_CIPHER_do_all_sorted ([] (const ::EVP_CIPHER* ciph, [[maybe_unused]]
const char* from, [[maybe_unused]]
const char* to,
93 void* arg) { AccumulateIntoSetOfCipherNames_ (ciph,
reinterpret_cast<Set<String>*
> (arg)); },
96#if USE_NOISY_TRACE_IN_THIS_MODULE_
97 DbgTrace (
"Found availableCipherAlgorithms-FIRST-PASS (cnt={}): {}"_f, cipherNames.size (), cipherNames);
100 Set<CipherAlgorithm> results{cipherNames.Map<Set<CipherAlgorithm>> (
101 [] (
const String& n) -> optional<CipherAlgorithm> {
return OpenSSL::CipherAlgorithm::GetByNameQuietly (n); })};
102#if USE_NOISY_TRACE_IN_THIS_MODULE_
103 DbgTrace (
"Found availableCipherAlgorithms (cnt={}): {}"_f, results.size (), results);
107 , standardCipherAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<CipherAlgorithm> {
108 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::standardCipherAlgorithms);
110 Set<CipherAlgorithm> results;
112 results += CipherAlgorithms::kAES_128_CBC;
113 results += CipherAlgorithms::kAES_128_ECB;
114 results += CipherAlgorithms::kAES_128_OFB;
115 results += CipherAlgorithms::kAES_128_CFB1;
116 results += CipherAlgorithms::kAES_128_CFB8;
117 results += CipherAlgorithms::kAES_128_CFB128;
118 results += CipherAlgorithms::kAES_192_CBC;
119 results += CipherAlgorithms::kAES_192_ECB;
120 results += CipherAlgorithms::kAES_192_OFB;
121 results += CipherAlgorithms::kAES_192_CFB1;
122 results += CipherAlgorithms::kAES_192_CFB8;
123 results += CipherAlgorithms::kAES_192_CFB128;
124 results += CipherAlgorithms::kAES_256_CBC;
125 results += CipherAlgorithms::kAES_256_ECB;
126 results += CipherAlgorithms::kAES_256_OFB;
127 results += CipherAlgorithms::kAES_256_CFB1;
128 results += CipherAlgorithms::kAES_256_CFB8;
129 results += CipherAlgorithms::kAES_256_CFB128;
139#if OPENSSL_VERSION_MAJOR < 3
140 results += CipherAlgorithms::kBlowfish_CBC;
141 results += CipherAlgorithms::kBlowfish_ECB;
142 results += CipherAlgorithms::kBlowfish_CFB;
143 results += CipherAlgorithms::kBlowfish_OFB;
144 results += CipherAlgorithms::kBlowfish;
145 results += CipherAlgorithms::kRC2_CBC;
146 results += CipherAlgorithms::kRC2_ECB;
147 results += CipherAlgorithms::kRC2_CFB;
148 results += CipherAlgorithms::kRC2_OFB;
149 results += CipherAlgorithms::kRC4;
154 , availableDigestAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<DigestAlgorithm> {
155 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::availableDigestAlgorithms);
158 Set<String> digestNames;
159#if OPENSSL_VERSION_MAJOR >= 3
160 ::EVP_MD_do_all_provided (
161 nullptr, [] (::EVP_MD* md,
void* arg) { AccumulateIntoSetOfDigestNames_ (md,
reinterpret_cast<Set<String>*
> (arg)); }, &digestNames);
163 ::EVP_MD_do_all_sorted ([] (const ::EVP_MD* md, [[maybe_unused]]
const char* from, [[maybe_unused]]
const char* to,
164 void* arg) { AccumulateIntoSetOfDigestNames_ (md,
reinterpret_cast<Set<String>*
> (arg)); },
167#if USE_NOISY_TRACE_IN_THIS_MODULE_
168 DbgTrace (
"Found availableDigestAlgorithms-FIRST-PASS (cnt={}): {}"_f, digestNames.size (), digestNames);
171 Set<DigestAlgorithm> results{digestNames.Map<Set<DigestAlgorithm>> (
172 [] (
const String& n) -> optional<DigestAlgorithm> {
return OpenSSL::DigestAlgorithm::GetByNameQuietly (n); })};
173#if USE_NOISY_TRACE_IN_THIS_MODULE_
174 DbgTrace (
"Found availableDigestAlgorithms (cnt={}): {}"_f, results.size (), results);
178 , standardDigestAlgorithms{[qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]
const auto* property) -> Set<DigestAlgorithm> {
179 const LibraryContext* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &LibraryContext::standardDigestAlgorithms);
181 Set<DigestAlgorithm> results;
182 results += DigestAlgorithms::kMD5;
183 results += DigestAlgorithms::kSHA1;
184 results += DigestAlgorithms::kSHA1_224;
185 results += DigestAlgorithms::kSHA1_256;
186 results += DigestAlgorithms::kSHA1_384;
187 results += DigestAlgorithms::kSHA1_512;
188 results += DigestAlgorithms::kSHA3_224;
189 results += DigestAlgorithms::kSHA3_256;
190 results += DigestAlgorithms::kSHA3_384;
191 results += DigestAlgorithms::kSHA3_512;
195 LoadProvider (kDefaultProvider);
198LibraryContext ::~LibraryContext ()
201#if OPENSSL_VERSION_MAJOR >= 3
203 for (
auto i : fLoadedProviders_.MappedValues ()) {
204 Verify (::OSSL_PROVIDER_unload (i) == 1);
209void LibraryContext::LoadProvider ([[maybe_unused]]
const String& providerName)
213#if OPENSSL_VERSION_MAJOR >= 3
214 auto p = fLoadedProviders_.LookupOneValue (providerName);
217 DbgTrace (
"calling OSSL_PROVIDER_load"_f);
218 p = ::OSSL_PROVIDER_load (
nullptr, providerName.AsNarrowSDKString ().c_str ());
220 Execution::ThrowIfNull (p, kErr_);
222 fLoadedProviders_.Add (providerName, p);
224 Require (providerName == kDefaultProvider or providerName == kLegacyProvider);
228void LibraryContext ::UnLoadProvider ([[maybe_unused]]
const String& providerName)
232#if OPENSSL_VERSION_MAJOR >= 3
233 Require (fLoadedProviders_.ContainsKey (providerName));
234 auto providerToMaybeRemove = fLoadedProviders_.LookupOneValue (providerName);
235 fLoadedProviders_.Remove (providerName);
236 if (not fLoadedProviders_.ContainsKey (providerName)) {
237 DbgTrace (
"calling OSSL_PROVIDER_unload"_f);
238 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...