|
|
@ -19,6 +19,10 @@ |
|
|
#include "core/internal_network/network.h"
|
|
|
#include "core/internal_network/network.h"
|
|
|
#include "core/internal_network/sockets.h"
|
|
|
#include "core/internal_network/sockets.h"
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef YUZU_BUNDLED_OPENSSL
|
|
|
|
|
|
#include <openssl/cert.h>
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
using namespace Common::FS; |
|
|
using namespace Common::FS; |
|
|
|
|
|
|
|
|
namespace Service::SSL { |
|
|
namespace Service::SSL { |
|
|
@ -41,11 +45,85 @@ void OneTimeInit(); |
|
|
void OneTimeInitLogFile(); |
|
|
void OneTimeInitLogFile(); |
|
|
bool OneTimeInitBIO(); |
|
|
bool OneTimeInitBIO(); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef YUZU_BUNDLED_OPENSSL
|
|
|
|
|
|
// This is ported from httplib
|
|
|
|
|
|
struct scope_exit { |
|
|
|
|
|
explicit scope_exit(std::function<void(void)> &&f) |
|
|
|
|
|
: exit_function(std::move(f)), execute_on_destruction{true} {} |
|
|
|
|
|
|
|
|
|
|
|
scope_exit(scope_exit &&rhs) noexcept |
|
|
|
|
|
: exit_function(std::move(rhs.exit_function)), |
|
|
|
|
|
execute_on_destruction{rhs.execute_on_destruction} { |
|
|
|
|
|
rhs.release(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~scope_exit() { |
|
|
|
|
|
if (execute_on_destruction) { this->exit_function(); } |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void release() { this->execute_on_destruction = false; } |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
scope_exit(const scope_exit &) = delete; |
|
|
|
|
|
void operator=(const scope_exit &) = delete; |
|
|
|
|
|
scope_exit &operator=(scope_exit &&) = delete; |
|
|
|
|
|
|
|
|
|
|
|
std::function<void(void)> exit_function; |
|
|
|
|
|
bool execute_on_destruction; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
inline X509_STORE *CreateCaCertStore(const char *ca_cert, |
|
|
|
|
|
std::size_t size) { |
|
|
|
|
|
auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size)); |
|
|
|
|
|
auto se = scope_exit([&] { BIO_free_all(mem); }); |
|
|
|
|
|
if (!mem) { return nullptr; } |
|
|
|
|
|
|
|
|
|
|
|
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr); |
|
|
|
|
|
if (!inf) { return nullptr; } |
|
|
|
|
|
|
|
|
|
|
|
auto cts = X509_STORE_new(); |
|
|
|
|
|
if (cts) { |
|
|
|
|
|
for (auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) { |
|
|
|
|
|
auto itmp = sk_X509_INFO_value(inf, i); |
|
|
|
|
|
if (!itmp) { continue; } |
|
|
|
|
|
|
|
|
|
|
|
if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); } |
|
|
|
|
|
if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); } |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sk_X509_INFO_pop_free(inf, X509_INFO_free); |
|
|
|
|
|
return cts; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
inline void SetCaCertStore(SSL_CTX *ctx, X509_STORE *ca_cert_store) { |
|
|
|
|
|
if (ca_cert_store) { |
|
|
|
|
|
if (ctx) { |
|
|
|
|
|
if (SSL_CTX_get_cert_store(ctx) != ca_cert_store) { |
|
|
|
|
|
// Free memory allocated for old cert and use new store `ca_cert_store`
|
|
|
|
|
|
SSL_CTX_set_cert_store(ctx, ca_cert_store); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
X509_STORE_free(ca_cert_store); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
inline void LoadCaCertStore(SSL_CTX* ctx, const char* ca_cert, std::size_t size) |
|
|
|
|
|
{ |
|
|
|
|
|
SetCaCertStore(ctx, CreateCaCertStore(ca_cert, size)); |
|
|
|
|
|
} |
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend { |
|
|
class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend { |
|
|
public: |
|
|
public: |
|
|
Result Init() { |
|
|
Result Init() { |
|
|
|
|
|
// on bundled OpenSSL, load ca cert store
|
|
|
|
|
|
#ifdef YUZU_BUNDLED_OPENSSL
|
|
|
|
|
|
LoadCaCertStore(ssl_ctx, kCert, sizeof(kCert)); |
|
|
|
|
|
#endif
|
|
|
std::call_once(one_time_init_flag, OneTimeInit); |
|
|
std::call_once(one_time_init_flag, OneTimeInit); |
|
|
|
|
|
|
|
|
if (!one_time_init_success) { |
|
|
if (!one_time_init_success) { |
|
|
|