diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp index 795b69a873..02d0b8fba7 100644 --- a/src/core/hle/service/ssl/ssl_backend_openssl.cpp +++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp @@ -19,6 +19,10 @@ #include "core/internal_network/network.h" #include "core/internal_network/sockets.h" +#ifdef YUZU_BUNDLED_OPENSSL +#include +#endif + using namespace Common::FS; namespace Service::SSL { @@ -41,11 +45,85 @@ void OneTimeInit(); void OneTimeInitLogFile(); bool OneTimeInitBIO(); +#ifdef YUZU_BUNDLED_OPENSSL +// This is ported from httplib +struct scope_exit { + explicit scope_exit(std::function &&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 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(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(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 class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend { public: 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); if (!one_time_init_success) {