Skip to content

Commit 0f174a5

Browse files
Merge pull request #1195 from paullouisageneau/openssl-certificate-chain
Add TLS certificate chain support with OpenSSL
2 parents 3b826f8 + f9ee7af commit 0f174a5

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

src/impl/certificate.cpp

+32-8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "certificate.hpp"
1010
#include "threadpool.hpp"
1111

12+
#include <algorithm>
1213
#include <cassert>
1314
#include <chrono>
1415
#include <iomanip>
@@ -384,9 +385,16 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) {
384385
BIO *bio = BIO_new(BIO_s_mem());
385386
BIO_write(bio, crt_pem.data(), int(crt_pem.size()));
386387
auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
387-
BIO_free(bio);
388-
if (!x509)
388+
if (!x509) {
389+
BIO_free(bio);
389390
throw std::invalid_argument("Unable to import PEM certificate");
391+
}
392+
std::vector<shared_ptr<X509>> chain;
393+
while (auto extra =
394+
shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
395+
chain.push_back(std::move(extra));
396+
}
397+
BIO_free(bio);
390398

391399
bio = BIO_new(BIO_s_mem());
392400
BIO_write(bio, key_pem.data(), int(key_pem.size()));
@@ -396,7 +404,7 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) {
396404
if (!pkey)
397405
throw std::invalid_argument("Unable to import PEM key");
398406

399-
return Certificate(x509, pkey);
407+
return Certificate(x509, pkey, std::move(chain));
400408
}
401409

402410
Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file,
@@ -408,9 +416,16 @@ Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_
408416
throw std::invalid_argument("Unable to open PEM certificate file");
409417

410418
auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
411-
BIO_free(bio);
412-
if (!x509)
419+
if (!x509) {
420+
BIO_free(bio);
413421
throw std::invalid_argument("Unable to import PEM certificate from file");
422+
}
423+
std::vector<shared_ptr<X509>> chain;
424+
while (auto extra =
425+
shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
426+
chain.push_back(std::move(extra));
427+
}
428+
BIO_free(bio);
414429

415430
bio = openssl::BIO_new_from_file(key_pem_file);
416431
if (!bio)
@@ -423,7 +438,7 @@ Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_
423438
if (!pkey)
424439
throw std::invalid_argument("Unable to import PEM key from file");
425440

426-
return Certificate(x509, pkey);
441+
return Certificate(x509, pkey, std::move(chain));
427442
}
428443

429444
Certificate Certificate::Generate(CertificateType type, const string &commonName) {
@@ -514,14 +529,23 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName
514529
return Certificate(x509, pkey);
515530
}
516531

517-
Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey)
518-
: mX509(std::move(x509)), mPKey(std::move(pkey)),
532+
Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey,
533+
std::vector<shared_ptr<X509>> chain)
534+
: mX509(std::move(x509)), mPKey(std::move(pkey)), mChain(std::move(chain)),
519535
mFingerprint(make_fingerprint(mX509.get(), CertificateFingerprint::Algorithm::Sha256)) {}
520536

521537
std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const {
522538
return {mX509.get(), mPKey.get()};
523539
}
524540

541+
std::vector<X509 *> Certificate::chain() const {
542+
std::vector<X509 *> v;
543+
v.reserve(mChain.size());
544+
std::transform(mChain.begin(), mChain.end(), std::back_inserter(v),
545+
[](const auto &c) { return c.get(); });
546+
return v;
547+
}
548+
525549
string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm) {
526550
size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
527551
std::vector<unsigned char> buffer(size);

src/impl/certificate.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ class Certificate {
3434
Certificate(shared_ptr<mbedtls_x509_crt> crt, shared_ptr<mbedtls_pk_context> pk);
3535
std::tuple<shared_ptr<mbedtls_x509_crt>, shared_ptr<mbedtls_pk_context>> credentials() const;
3636
#else // OPENSSL
37-
Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey);
37+
Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey, std::vector<shared_ptr<X509>> chain = {});
3838
std::tuple<X509 *, EVP_PKEY *> credentials() const;
39+
std::vector<X509 *> chain() const;
3940
#endif
4041

4142
CertificateFingerprint fingerprint() const;
@@ -52,6 +53,7 @@ class Certificate {
5253
#else
5354
const shared_ptr<X509> mX509;
5455
const shared_ptr<EVP_PKEY> mPKey;
56+
const std::vector<shared_ptr<X509>> mChain;
5557
#endif
5658

5759
const string mFingerprint;

src/impl/tlstransport.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,9 @@ TlsTransport::TlsTransport(variant<shared_ptr<TcpTransport>, shared_ptr<HttpProx
603603
auto [x509, pkey] = certificate->credentials();
604604
SSL_CTX_use_certificate(mCtx, x509);
605605
SSL_CTX_use_PrivateKey(mCtx, pkey);
606+
607+
for (auto c : certificate->chain())
608+
SSL_CTX_add1_chain_cert(mCtx, c); // add1 increments reference count
606609
}
607610

608611
SSL_CTX_set_options(mCtx, SSL_OP_NO_SSLv3 | SSL_OP_NO_RENEGOTIATION);

0 commit comments

Comments
 (0)