Skip to content

Commit

Permalink
Merge pull request paullouisageneau#1195 from paullouisageneau/openss…
Browse files Browse the repository at this point in the history
…l-certificate-chain

Add TLS certificate chain support with OpenSSL
  • Loading branch information
paullouisageneau committed May 30, 2024
2 parents 3b826f8 + f9ee7af commit 0f174a5
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
40 changes: 32 additions & 8 deletions src/impl/certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "certificate.hpp"
#include "threadpool.hpp"

#include <algorithm>
#include <cassert>
#include <chrono>
#include <iomanip>
Expand Down Expand Up @@ -384,9 +385,16 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) {
BIO *bio = BIO_new(BIO_s_mem());
BIO_write(bio, crt_pem.data(), int(crt_pem.size()));
auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
BIO_free(bio);
if (!x509)
if (!x509) {
BIO_free(bio);
throw std::invalid_argument("Unable to import PEM certificate");
}
std::vector<shared_ptr<X509>> chain;
while (auto extra =
shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
chain.push_back(std::move(extra));
}
BIO_free(bio);

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

return Certificate(x509, pkey);
return Certificate(x509, pkey, std::move(chain));
}

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

auto x509 = shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free);
BIO_free(bio);
if (!x509)
if (!x509) {
BIO_free(bio);
throw std::invalid_argument("Unable to import PEM certificate from file");
}
std::vector<shared_ptr<X509>> chain;
while (auto extra =
shared_ptr<X509>(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) {
chain.push_back(std::move(extra));
}
BIO_free(bio);

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

return Certificate(x509, pkey);
return Certificate(x509, pkey, std::move(chain));
}

Certificate Certificate::Generate(CertificateType type, const string &commonName) {
Expand Down Expand Up @@ -514,14 +529,23 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName
return Certificate(x509, pkey);
}

Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey)
: mX509(std::move(x509)), mPKey(std::move(pkey)),
Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey,
std::vector<shared_ptr<X509>> chain)
: mX509(std::move(x509)), mPKey(std::move(pkey)), mChain(std::move(chain)),
mFingerprint(make_fingerprint(mX509.get(), CertificateFingerprint::Algorithm::Sha256)) {}

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

std::vector<X509 *> Certificate::chain() const {
std::vector<X509 *> v;
v.reserve(mChain.size());
std::transform(mChain.begin(), mChain.end(), std::back_inserter(v),
[](const auto &c) { return c.get(); });
return v;
}

string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm) {
size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
std::vector<unsigned char> buffer(size);
Expand Down
4 changes: 3 additions & 1 deletion src/impl/certificate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ class Certificate {
Certificate(shared_ptr<mbedtls_x509_crt> crt, shared_ptr<mbedtls_pk_context> pk);
std::tuple<shared_ptr<mbedtls_x509_crt>, shared_ptr<mbedtls_pk_context>> credentials() const;
#else // OPENSSL
Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey);
Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey, std::vector<shared_ptr<X509>> chain = {});
std::tuple<X509 *, EVP_PKEY *> credentials() const;
std::vector<X509 *> chain() const;
#endif

CertificateFingerprint fingerprint() const;
Expand All @@ -52,6 +53,7 @@ class Certificate {
#else
const shared_ptr<X509> mX509;
const shared_ptr<EVP_PKEY> mPKey;
const std::vector<shared_ptr<X509>> mChain;
#endif

const string mFingerprint;
Expand Down
3 changes: 3 additions & 0 deletions src/impl/tlstransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,9 @@ TlsTransport::TlsTransport(variant<shared_ptr<TcpTransport>, shared_ptr<HttpProx
auto [x509, pkey] = certificate->credentials();
SSL_CTX_use_certificate(mCtx, x509);
SSL_CTX_use_PrivateKey(mCtx, pkey);

for (auto c : certificate->chain())
SSL_CTX_add1_chain_cert(mCtx, c); // add1 increments reference count
}

SSL_CTX_set_options(mCtx, SSL_OP_NO_SSLv3 | SSL_OP_NO_RENEGOTIATION);
Expand Down

0 comments on commit 0f174a5

Please sign in to comment.