nghttpx: Enable signed_certificate_timestamp extension for TLSv1.3

This commit is contained in:
Tatsuhiro Tsujikawa 2017-04-09 13:40:38 +09:00
parent 980570de71
commit 2d9fd87029
4 changed files with 94 additions and 23 deletions

View File

@ -123,6 +123,7 @@ void Connection::disconnect() {
tls.handshake_state = 0;
tls.initial_handshake_done = false;
tls.reneg_started = false;
tls.sct_requested = false;
}
if (fd != -1) {

View File

@ -71,6 +71,9 @@ struct TLSConnection {
bool reneg_started;
// true if ssl is prepared to do handshake as server.
bool server_handshake;
// true if ssl is initialized as server, and client requested
// signed_certificate_timestamp extension.
bool sct_requested;
};
struct TCPHint {

View File

@ -534,16 +534,26 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
} // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace {
// https://tools.ietf.org/html/rfc6962#section-6
constexpr unsigned int TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP = 18;
} // namespace
#ifndef TLSEXT_TYPE_signed_certificate_timestamp
#define TLSEXT_TYPE_signed_certificate_timestamp 18
#endif // !TLSEXT_TYPE_signed_certificate_timestamp
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);
int sct_add_cb(SSL *ssl, unsigned int ext_type, unsigned int context,
const unsigned char **out, size_t *outlen, X509 *x,
size_t chainidx, int *al, void *add_arg) {
assert(ext_type == TLSEXT_TYPE_signed_certificate_timestamp);
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
if (!conn->tls.sct_requested) {
return 0;
}
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "sct_add_cb is called, chainidx=" << chainidx << ", x=" << x
<< ", context=" << std::hex << context;
}
auto ssl_ctx = SSL_get_SSL_CTX(ssl);
auto tls_ctx_data =
static_cast<TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
@ -556,23 +566,59 @@ int sct_add_cb(SSL *ssl, unsigned int ext_type, const unsigned char **out,
} // 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);
void sct_free_cb(SSL *ssl, unsigned int ext_type, unsigned int context,
const unsigned char *out, void *add_arg) {
assert(ext_type == TLSEXT_TYPE_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);
int sct_parse_cb(SSL *ssl, unsigned int ext_type, unsigned int context,
const unsigned char *in, size_t inlen, X509 *x,
size_t chainidx, int *al, void *parse_arg) {
assert(ext_type == TLSEXT_TYPE_signed_certificate_timestamp);
// client SHOULD send 0 length extension_data, but it is still
// SHOULD, and not MUST.
// For TLSv1.3 Certificate message, sct_add_cb is called even if
// client has not sent signed_certificate_timestamp extension in its
// ClientHello. Explicitly remember that client has included it
// here.
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
conn->tls.sct_requested = true;
return 1;
}
} // namespace
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \
!OPENSSL_1_1_1_API
namespace {
int legacy_sct_add_cb(SSL *ssl, unsigned int ext_type,
const unsigned char **out, size_t *outlen, int *al,
void *add_arg) {
return sct_add_cb(ssl, ext_type, 0, out, outlen, nullptr, 0, al, add_arg);
}
} // namespace
namespace {
void legacy_sct_free_cb(SSL *ssl, unsigned int ext_type,
const unsigned char *out, void *add_arg) {
sct_free_cb(ssl, ext_type, 0, out, add_arg);
}
} // namespace
namespace {
int legacy_sct_parse_cb(SSL *ssl, unsigned int ext_type,
const unsigned char *in, size_t inlen, int *al,
void *parse_arg) {
return sct_parse_cb(ssl, ext_type, 0, in, inlen, nullptr, 0, al, parse_arg);
}
} // namespace
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L &&
// !OPENSSL_1_1_1_API
#if !LIBRESSL_IN_USE
namespace {
@ -832,17 +878,35 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
// SSL_extension_supported(TLS_EXT_SIGNED_CERTIFICATE_TIMESTAMP)
// SSL_extension_supported(TLSEXT_TYPE_signed_certificate_timestamp)
// returns 1, which means OpenSSL internally handles it. But
// OpenSSL handles signed_certificate_timestamp extension specially,
// and it lets custom handler to process the extension.
if (!sct_data.empty() &&
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();
if (!sct_data.empty()) {
#if OPENSSL_1_1_1_API
// It is not entirely clear to me that SSL_EXT_CLIENT_HELLO is
// required here. sct_parse_cb is called without
// SSL_EXT_CLIENT_HELLO being set. But the passed context value
// is SSL_EXT_CLIENT_HELLO.
if (SSL_CTX_add_custom_ext(
ssl_ctx, TLSEXT_TYPE_signed_certificate_timestamp,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_2_SERVER_HELLO |
SSL_EXT_TLS1_3_CERTIFICATE | SSL_EXT_IGNORE_ON_RESUMPTION,
sct_add_cb, sct_free_cb, nullptr, sct_parse_cb, nullptr) != 1) {
LOG(FATAL) << "SSL_CTX_add_custom_ext failed: "
<< ERR_error_string(ERR_get_error(), nullptr);
DIE();
}
#else // !OPENSSL_1_1_1_API
if (SSL_CTX_add_server_custom_ext(
ssl_ctx, TLSEXT_TYPE_signed_certificate_timestamp,
legacy_sct_add_cb, legacy_sct_free_cb, nullptr, legacy_sct_parse_cb,
nullptr) != 1) {
LOG(FATAL) << "SSL_CTX_add_server_custom_ext failed: "
<< ERR_error_string(ERR_get_error(), nullptr);
DIE();
}
#endif // !OPENSSL_1_1_1_API
}
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L

View File

@ -35,4 +35,7 @@
#define OPENSSL_1_1_API \
(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x1010000fL)
#define OPENSSL_1_1_1_API \
(!LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10101000L)
#endif // OPENSSL_COMPAT_H