Skip to content

Commit eab5ea0

Browse files
authored
Load in-memory CA certificates (#1579)
* Load in-memory CA certs * Add test cases for in-memory cert loading * Don't use the IIFE style
1 parent 3e287b3 commit eab5ea0

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

httplib.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ class ClientImpl {
11241124
void set_ca_cert_path(const std::string &ca_cert_file_path,
11251125
const std::string &ca_cert_dir_path = std::string());
11261126
void set_ca_cert_store(X509_STORE *ca_cert_store);
1127+
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size);
11271128
#endif
11281129

11291130
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -1504,6 +1505,7 @@ class Client {
15041505
const std::string &ca_cert_dir_path = std::string());
15051506

15061507
void set_ca_cert_store(X509_STORE *ca_cert_store);
1508+
void load_ca_cert_store(const char *ca_cert, std::size_t size);
15071509

15081510
long get_openssl_verify_result() const;
15091511

@@ -1563,6 +1565,7 @@ class SSLClient : public ClientImpl {
15631565
bool is_valid() const override;
15641566

15651567
void set_ca_cert_store(X509_STORE *ca_cert_store);
1568+
void load_ca_cert_store(const char *ca_cert, std::size_t size);
15661569

15671570
long get_openssl_verify_result() const;
15681571

@@ -7590,6 +7593,35 @@ inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
75907593
ca_cert_store_ = ca_cert_store;
75917594
}
75927595
}
7596+
7597+
inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
7598+
std::size_t size) {
7599+
auto mem = BIO_new_mem_buf(ca_cert, size);
7600+
if (!mem) return nullptr;
7601+
7602+
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
7603+
if (!inf) {
7604+
BIO_free_all(mem);
7605+
return nullptr;
7606+
}
7607+
7608+
auto cts = X509_STORE_new();
7609+
if (cts) {
7610+
for (int first = 0, last = sk_X509_INFO_num(inf); first < last; ++first) {
7611+
auto itmp = sk_X509_INFO_value(inf, first);
7612+
if (!itmp) continue;
7613+
7614+
if (itmp->x509) X509_STORE_add_cert(cts, itmp->x509);
7615+
7616+
if (itmp->crl) X509_STORE_add_crl(cts, itmp->crl);
7617+
}
7618+
}
7619+
7620+
sk_X509_INFO_pop_free(inf, X509_INFO_free);
7621+
BIO_free_all(mem);
7622+
7623+
return cts;
7624+
}
75937625
#endif
75947626

75957627
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
@@ -7990,6 +8022,11 @@ inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
79908022
}
79918023
}
79928024

8025+
inline void SSLClient::load_ca_cert_store(const char *ca_cert,
8026+
std::size_t size) {
8027+
set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
8028+
}
8029+
79938030
inline long SSLClient::get_openssl_verify_result() const {
79948031
return verify_result_;
79958032
}
@@ -8773,6 +8810,10 @@ inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
87738810
}
87748811
}
87758812

8813+
inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
8814+
set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
8815+
}
8816+
87768817
inline long Client::get_openssl_verify_result() const {
87778818
if (is_ssl_) {
87788819
return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();

test/test.cc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4710,6 +4710,49 @@ TEST(SSLClientTest, ServerCertificateVerification4) {
47104710
ASSERT_EQ(200, res->status);
47114711
}
47124712

4713+
TEST(SSLClientTest, ServerCertificateVerification5_Online) {
4714+
std::string cert;
4715+
detail::read_file(CA_CERT_FILE, cert);
4716+
4717+
SSLClient cli("google.com");
4718+
cli.load_ca_cert_store(cert.data(), cert.size());
4719+
const auto res = cli.Get("/");
4720+
ASSERT_TRUE(res);
4721+
ASSERT_EQ(301, res->status);
4722+
}
4723+
4724+
TEST(SSLClientTest, ServerCertificateVerification6_Online) {
4725+
// clang-format off
4726+
static constexpr char cert[] =
4727+
"GlobalSign Root CA\n"
4728+
"==================\n"
4729+
"-----BEGIN CERTIFICATE-----\n"
4730+
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n"
4731+
"GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n"
4732+
"b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n"
4733+
"BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n"
4734+
"VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n"
4735+
"DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n"
4736+
"THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n"
4737+
"Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n"
4738+
"c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n"
4739+
"gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
4740+
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n"
4741+
"AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n"
4742+
"Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n"
4743+
"j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n"
4744+
"hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n"
4745+
"X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
4746+
"-----END CERTIFICATE-----\n";
4747+
// clang-format on
4748+
4749+
SSLClient cli("google.com");
4750+
cli.load_ca_cert_store(cert, sizeof(cert));
4751+
const auto res = cli.Get("/");
4752+
ASSERT_TRUE(res);
4753+
ASSERT_EQ(301, res->status);
4754+
}
4755+
47134756
TEST(SSLClientTest, WildcardHostNameMatch_Online) {
47144757
SSLClient cli("www.youtube.com");
47154758

0 commit comments

Comments
 (0)