nghttpx: Add TLS signed_certificate_timestamp extension support
This commit is contained in:
parent
2795da840c
commit
412c8f9e67
|
@ -209,6 +209,24 @@ from the given file. In this case, nghttpx does not rotate key
|
|||
automatically. To rotate key, one has to restart nghttpx (see
|
||||
SIGNALS).
|
||||
|
||||
CERTIFICATE TRANSPARENCY
|
||||
------------------------
|
||||
|
||||
nghttpx supports TLS ``signed_certificate_timestamp`` extension (`RFC
|
||||
6962 <https://tools.ietf.org/html/rfc6962>`_). The relevant options
|
||||
are :option:`--tls-sct-dir` and ``sct-dir`` parameter in
|
||||
:option:`--subcert`. They takes a directory, and nghttpx reads all
|
||||
files whose extension is ``.sct`` under the directory. The ``*.sct``
|
||||
files are encoded as ``SignedCertificateTimestamp`` struct described
|
||||
in `section 3.2 of RFC 69662
|
||||
<https://tools.ietf.org/html/rfc6962#section-3.2>`_. This format is
|
||||
the same one used by `nginx-ct
|
||||
<https://github.com/grahamedgecombe/nginx-ct>`_ and `mod_ssl_ct
|
||||
<https://httpd.apache.org/docs/trunk/mod/mod_ssl_ct.html>`_.
|
||||
`ct-submit <https://github.com/grahamedgecombe/ct-submit>`_ can be
|
||||
used to submit certificates to log servers, and obtain the
|
||||
``SignedCertificateTimestamp`` struct which can be used with nghttpx.
|
||||
|
||||
MRUBY SCRIPTING
|
||||
---------------
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ OPTIONS = [
|
|||
"backend-http2-encoder-dynamic-table-size",
|
||||
"backend-http2-decoder-dynamic-table-size",
|
||||
"ecdh-curves",
|
||||
"tls-sct-dir",
|
||||
]
|
||||
|
||||
LOGVARS = [
|
||||
|
|
25
src/shrpx.cc
25
src/shrpx.cc
|
@ -1843,12 +1843,21 @@ SSL/TLS:
|
|||
Path to file that contains password for the server's
|
||||
private key. If none is given and the private key is
|
||||
password protected it'll be requested interactively.
|
||||
--subcert=<KEYPATH>:<CERTPATH>
|
||||
--subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
|
||||
Specify additional certificate and private key file.
|
||||
nghttpx will choose certificates based on the hostname
|
||||
indicated by client using TLS SNI extension. This
|
||||
option can be used multiple times. To make OCSP
|
||||
stapling work, <CERTPATH> must be absolute path.
|
||||
|
||||
Additional parameter can be specified in <PARAM>. The
|
||||
available <PARAM> is "sct-dir=<DIR>".
|
||||
|
||||
"sct-dir=<DIR>" specifies the path to directory which
|
||||
contains *.sct files for TLS
|
||||
signed_certificate_timestamp extension (RFC 6962). This
|
||||
feature requires OpenSSL >= 1.0.2. See also
|
||||
--tls-sct-dir option.
|
||||
--dh-param-file=<PATH>
|
||||
Path to file that contains DH parameters in PEM format.
|
||||
Without this option, DHE cipher suites are not
|
||||
|
@ -2004,6 +2013,15 @@ SSL/TLS:
|
|||
Allow black listed cipher suite on HTTP/2 connection.
|
||||
See https://tools.ietf.org/html/rfc7540#appendix-A for
|
||||
the complete HTTP/2 cipher suites black list.
|
||||
--tls-sct-dir=<DIR>
|
||||
Specifies the directory where *.sct files exist. All
|
||||
*.sct files in <DIR> are read, and sent as
|
||||
extension_data of TLS signed_certificate_timestamp (RFC
|
||||
6962) to client. These *.sct files are for the
|
||||
certificate specified in positional command-line
|
||||
argument <CERT>, or certificate option in configuration
|
||||
file. For additional certificates, use --subcert
|
||||
option. This option requires OpenSSL >= 1.0.2.
|
||||
|
||||
HTTP/2 and SPDY:
|
||||
-c, --frontend-http2-max-concurrent-streams=<N>
|
||||
|
@ -2937,6 +2955,7 @@ int main(int argc, char **argv) {
|
|||
{SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
|
||||
required_argument, &flag, 139},
|
||||
{SHRPX_OPT_ECDH_CURVES.c_str(), required_argument, &flag, 140},
|
||||
{SHRPX_OPT_TLS_SCT_DIR.c_str(), required_argument, &flag, 141},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
int option_index = 0;
|
||||
|
@ -3601,6 +3620,10 @@ int main(int argc, char **argv) {
|
|||
// --ecdh-curves
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_ECDH_CURVES, StringRef{optarg});
|
||||
break;
|
||||
case 141:
|
||||
// --tls-sct-dir
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_SCT_DIR, StringRef{optarg});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif // HAVE_UNISTD_H
|
||||
#include <dirent.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
@ -1016,6 +1017,162 @@ int parse_error_page(std::vector<ErrorPage> &error_pages, const StringRef &opt,
|
|||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
// Maximum size of SCT extension payload length.
|
||||
constexpr size_t MAX_SCT_EXT_LEN = 16_k;
|
||||
} // namespace
|
||||
|
||||
struct SubcertParams {
|
||||
StringRef sct_dir;
|
||||
};
|
||||
|
||||
namespace {
|
||||
// Parses subcert parameter |src_params|, and stores parsed results
|
||||
// into |out|. This function returns 0 if it succeeds, or -1.
|
||||
int parse_subcert_params(SubcertParams &out, const StringRef &src_params) {
|
||||
auto last = std::end(src_params);
|
||||
for (auto first = std::begin(src_params); first != last;) {
|
||||
auto end = std::find(first, last, ';');
|
||||
auto param = StringRef{first, end};
|
||||
|
||||
if (util::istarts_with_l(param, "sct-dir=")) {
|
||||
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
auto sct_dir =
|
||||
StringRef{std::begin(param) + str_size("sct-dir="), std::end(param)};
|
||||
if (sct_dir.empty()) {
|
||||
LOG(ERROR) << "subcert: " << param << ": empty sct-dir";
|
||||
return -1;
|
||||
}
|
||||
out.sct_dir = sct_dir;
|
||||
#else // !(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
LOG(WARN) << "subcert: sct-dir requires OpenSSL >= 1.0.2";
|
||||
#endif // !(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
} else if (!param.empty()) {
|
||||
LOG(ERROR) << "subcert: " << param << ": unknown keyword";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (end == last) {
|
||||
break;
|
||||
}
|
||||
|
||||
first = end + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
// Reads *.sct files from directory denoted by |dir_path|. |dir_path|
|
||||
// must be NULL-terminated string.
|
||||
int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt,
|
||||
const StringRef &dir_path) {
|
||||
auto dir = opendir(dir_path.c_str());
|
||||
if (dir == nullptr) {
|
||||
auto error = errno;
|
||||
LOG(ERROR) << opt << ": " << dir_path << ": " << strerror(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto closer = defer(closedir, dir);
|
||||
|
||||
// 2 bytes total length field
|
||||
auto len_idx = std::distance(std::begin(dst), std::end(dst));
|
||||
dst.insert(std::end(dst), 2, 0);
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
auto ent = readdir(dir);
|
||||
if (ent == nullptr) {
|
||||
if (errno != 0) {
|
||||
auto error = errno;
|
||||
LOG(ERROR) << opt << ": failed to read directory " << dir_path << ": "
|
||||
<< strerror(error);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
auto name = StringRef{ent->d_name};
|
||||
|
||||
if (name[0] == '.' || !util::iends_with_l(name, ".sct")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
path.resize(dir_path.size() + 1 + name.size());
|
||||
{
|
||||
auto p = std::begin(path);
|
||||
p = std::copy(std::begin(dir_path), std::end(dir_path), p);
|
||||
*p++ = '/';
|
||||
std::copy(std::begin(name), std::end(name), p);
|
||||
}
|
||||
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if (fd == -1) {
|
||||
auto error = errno;
|
||||
LOG(ERROR) << opt << ": failed to read SCT from " << path << ": "
|
||||
<< strerror(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2 bytes length field for this SCT.
|
||||
auto len_idx = std::distance(std::begin(dst), std::end(dst));
|
||||
dst.insert(std::end(dst), 2, 0);
|
||||
|
||||
// *.sct file tends to be small; around 110+ bytes.
|
||||
std::array<char, 256> buf;
|
||||
for (;;) {
|
||||
ssize_t nread;
|
||||
while ((nread = read(fd, buf.data(), buf.size())) == -1 && errno == EINTR)
|
||||
;
|
||||
|
||||
if (nread == -1) {
|
||||
auto error = errno;
|
||||
LOG(ERROR) << opt << ": failed to read SCT data from " << path << ": "
|
||||
<< strerror(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nread == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst.insert(std::end(dst), std::begin(buf), std::begin(buf) + nread);
|
||||
|
||||
if (dst.size() > MAX_SCT_EXT_LEN) {
|
||||
LOG(ERROR) << opt << ": the concatenated SCT data from " << dir_path
|
||||
<< " is too large. Max " << MAX_SCT_EXT_LEN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto len = dst.size() - len_idx - 2;
|
||||
|
||||
if (len == 0) {
|
||||
dst.resize(dst.size() - 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
dst[len_idx] = len >> 8;
|
||||
dst[len_idx + 1] = len;
|
||||
}
|
||||
|
||||
auto len = dst.size() - len_idx - 2;
|
||||
|
||||
if (len == 0) {
|
||||
dst.resize(dst.size() - 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dst[len_idx] = len >> 8;
|
||||
dst[len_idx + 1] = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// generated by gennghttpxfun.py
|
||||
int option_lookup_token(const char *name, size_t namelen) {
|
||||
switch (namelen) {
|
||||
|
@ -1171,6 +1328,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||
return SHRPX_OPTID_SERVER_NAME;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (util::strieq_l("tls-sct-di", name, 10)) {
|
||||
return SHRPX_OPTID_TLS_SCT_DIR;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (util::strieq_l("backend-tl", name, 10)) {
|
||||
return SHRPX_OPTID_BACKEND_TLS;
|
||||
|
@ -2165,30 +2327,51 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||
|
||||
return 0;
|
||||
case SHRPX_OPTID_SUBCERT: {
|
||||
auto end_keys = std::find(std::begin(optarg), std::end(optarg), ';');
|
||||
auto src_params = StringRef{end_keys, std::end(optarg)};
|
||||
|
||||
SubcertParams params;
|
||||
if (parse_subcert_params(params, src_params) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> sct_data;
|
||||
|
||||
if (!params.sct_dir.empty()) {
|
||||
// Make sure that dir_path is NULL terminated string.
|
||||
if (read_tls_sct_from_dir(sct_data, opt,
|
||||
StringRef{params.sct_dir.str()}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Private Key file and certificate file separated by ':'.
|
||||
auto sp = std::find(std::begin(optarg), std::end(optarg), ':');
|
||||
if (sp == std::end(optarg)) {
|
||||
LOG(ERROR) << opt << ": missing ':' in " << optarg;
|
||||
auto sp = std::find(std::begin(optarg), end_keys, ':');
|
||||
if (sp == end_keys) {
|
||||
LOG(ERROR) << opt << ": missing ':' in "
|
||||
<< StringRef{std::begin(optarg), end_keys};
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto private_key_file = StringRef{std::begin(optarg), sp};
|
||||
|
||||
if (private_key_file.empty()) {
|
||||
LOG(ERROR) << opt << ": missing private key file: " << optarg;
|
||||
LOG(ERROR) << opt << ": missing private key file: "
|
||||
<< StringRef{std::begin(optarg), end_keys};
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto cert_file = StringRef{sp + 1, std::end(optarg)};
|
||||
auto cert_file = StringRef{sp + 1, end_keys};
|
||||
|
||||
if (cert_file.empty()) {
|
||||
LOG(ERROR) << opt << ": missing certificate file: " << optarg;
|
||||
LOG(ERROR) << opt << ": missing certificate file: "
|
||||
<< StringRef{std::begin(optarg), end_keys};
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->tls.subcerts.emplace_back(
|
||||
make_string_ref(config->balloc, private_key_file),
|
||||
make_string_ref(config->balloc, cert_file));
|
||||
make_string_ref(config->balloc, cert_file), std::move(sct_data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2875,6 +3058,13 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||
LOG(WARN) << opt << ": This option requires OpenSSL >= 1.0.2";
|
||||
#endif // !(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_SCT_DIR:
|
||||
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
return read_tls_sct_from_dir(config->tls.sct_data, opt, optarg);
|
||||
#else // !(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
LOG(WARN) << opt << ": This option requires OpenSSL >= 1.0.2";
|
||||
return 0;
|
||||
#endif // !(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
case SHRPX_OPTID_CONF:
|
||||
LOG(WARN) << "conf: ignored";
|
||||
|
||||
|
|
|
@ -309,6 +309,7 @@ constexpr auto SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE =
|
|||
constexpr auto SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE =
|
||||
StringRef::from_lit("backend-http2-decoder-dynamic-table-size");
|
||||
constexpr auto SHRPX_OPT_ECDH_CURVES = StringRef::from_lit("ecdh-curves");
|
||||
constexpr auto SHRPX_OPT_TLS_SCT_DIR = StringRef::from_lit("tls-sct-dir");
|
||||
|
||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||
|
||||
|
@ -437,6 +438,18 @@ struct TicketKeys {
|
|||
std::vector<TicketKey> keys;
|
||||
};
|
||||
|
||||
struct TLSCertificate {
|
||||
TLSCertificate(StringRef private_key_file, StringRef cert_file,
|
||||
std::vector<uint8_t> sct_data)
|
||||
: private_key_file(std::move(private_key_file)),
|
||||
cert_file(std::move(cert_file)),
|
||||
sct_data(std::move(sct_data)) {}
|
||||
|
||||
StringRef private_key_file;
|
||||
StringRef cert_file;
|
||||
std::vector<uint8_t> sct_data;
|
||||
};
|
||||
|
||||
struct HttpProxy {
|
||||
Address addr;
|
||||
// host in http proxy URI
|
||||
|
@ -522,14 +535,15 @@ struct TLSConfig {
|
|||
StringRef cert_file;
|
||||
} client;
|
||||
|
||||
// The list of (private key file, certificate file) pair
|
||||
std::vector<std::pair<StringRef, StringRef>> subcerts;
|
||||
// The list of additional TLS certificate pair
|
||||
std::vector<TLSCertificate> subcerts;
|
||||
std::vector<unsigned char> alpn_prefs;
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// preference.
|
||||
std::vector<StringRef> npn_list;
|
||||
// list of supported SSL/TLS protocol strings.
|
||||
std::vector<StringRef> tls_proto_list;
|
||||
std::vector<uint8_t> sct_data;
|
||||
BIO_METHOD *bio_method;
|
||||
// Bit mask to disable SSL/TLS protocol versions. This will be
|
||||
// passed to SSL_CTX_set_options().
|
||||
|
@ -942,6 +956,7 @@ enum {
|
|||
SHRPX_OPTID_TLS_DYN_REC_IDLE_TIMEOUT,
|
||||
SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD,
|
||||
SHRPX_OPTID_TLS_PROTO_LIST,
|
||||
SHRPX_OPTID_TLS_SCT_DIR,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
|
||||
|
|
|
@ -485,6 +485,44 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
|||
} // namespace
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
namespace {
|
||||
// https://tools.ietf.org/html/rfc6962#section-6
|
||||
constexpr unsigned int TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP = 18;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int sct_add_cb(SSL *ssl, unsigned int ext_type, const unsigned char **out,
|
||||
size_t *outlen, int *al, void *add_arg) {
|
||||
assert(ext_type == TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP);
|
||||
auto ssl_ctx = SSL_get_SSL_CTX(ssl);
|
||||
auto tls_ctx_data =
|
||||
static_cast<TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
|
||||
|
||||
*out = tls_ctx_data->sct_data.data();
|
||||
*outlen = tls_ctx_data->sct_data.size();
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void sct_free_cb(SSL *ssl, unsigned int ext_type, const unsigned char *out,
|
||||
void *add_arg) {
|
||||
assert(ext_type == TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int sct_parse_cb(SSL *ssl, unsigned int ext_type, const unsigned char *in,
|
||||
size_t inlen, int *al, void *parse_arg) {
|
||||
assert(ext_type == TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP);
|
||||
// client SHOULD send 0 length extension_data, but it is still
|
||||
// SHOULD, and not MUST.
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct TLSProtocol {
|
||||
StringRef name;
|
||||
long int mask;
|
||||
|
@ -513,7 +551,8 @@ long int create_tls_proto_mask(const std::vector<StringRef> &tls_proto_list) {
|
|||
return res;
|
||||
}
|
||||
|
||||
SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
const std::vector<uint8_t> &sct_data
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
,
|
||||
neverbleed_t *nb
|
||||
|
@ -678,8 +717,22 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
|||
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, nullptr);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
if (!sct_data.empty() &&
|
||||
SSL_extension_supported(TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP) == 0) {
|
||||
if (SSL_CTX_add_server_custom_ext(
|
||||
ssl_ctx, TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP, sct_add_cb,
|
||||
sct_free_cb, nullptr, sct_parse_cb, nullptr) != 1) {
|
||||
LOG(FATAL) << "SSL_CTX_add_server_custom_ext failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
}
|
||||
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
auto tls_ctx_data = new TLSContextData();
|
||||
tls_ctx_data->cert_file = cert_file;
|
||||
tls_ctx_data->sct_data = sct_data;
|
||||
|
||||
SSL_CTX_set_app_data(ssl_ctx, tls_ctx_data);
|
||||
|
||||
|
@ -1372,8 +1425,9 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
|||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
|
||||
auto ssl_ctx = ssl::create_ssl_context(tlsconf.private_key_file.c_str(),
|
||||
tlsconf.cert_file.c_str()
|
||||
auto ssl_ctx =
|
||||
ssl::create_ssl_context(tlsconf.private_key_file.c_str(),
|
||||
tlsconf.cert_file.c_str(), tlsconf.sct_data
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
,
|
||||
nb
|
||||
|
@ -1407,12 +1461,9 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
|||
DIE();
|
||||
}
|
||||
|
||||
for (auto &keycert : tlsconf.subcerts) {
|
||||
auto &priv_key_file = keycert.first;
|
||||
auto &cert_file = keycert.second;
|
||||
|
||||
auto ssl_ctx =
|
||||
ssl::create_ssl_context(priv_key_file.c_str(), cert_file.c_str()
|
||||
for (auto &c : tlsconf.subcerts) {
|
||||
auto ssl_ctx = ssl::create_ssl_context(c.private_key_file.c_str(),
|
||||
c.cert_file.c_str(), c.sct_data
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
,
|
||||
nb
|
||||
|
@ -1424,7 +1475,7 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
|||
auto cert = SSL_CTX_get0_certificate(ssl_ctx);
|
||||
#else // defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER <
|
||||
// 0x10002000L
|
||||
auto cert = load_certificate(cert_file.c_str());
|
||||
auto cert = load_certificate(c.cert_file.c_str());
|
||||
auto cert_deleter = defer(X509_free, cert);
|
||||
#endif // defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER <
|
||||
// 0x10002000L
|
||||
|
|
|
@ -63,6 +63,9 @@ struct TLSSessionCache {
|
|||
// This struct stores the additional information per SSL_CTX. This is
|
||||
// attached to SSL_CTX using SSL_CTX_set_app_data().
|
||||
struct TLSContextData {
|
||||
// SCT data formatted so that this can be directly sent as
|
||||
// extension_data of signed_certificate_timestamp.
|
||||
std::vector<uint8_t> sct_data;
|
||||
#ifndef HAVE_ATOMIC_STD_SHARED_PTR
|
||||
// Protects ocsp_data;
|
||||
std::mutex mu;
|
||||
|
@ -75,7 +78,9 @@ struct TLSContextData {
|
|||
};
|
||||
|
||||
// Create server side SSL_CTX
|
||||
SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
||||
const std::vector<uint8_t> &sct_data
|
||||
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
,
|
||||
neverbleed_t *nb
|
||||
|
|
Loading…
Reference in New Issue