diff options
Diffstat (limited to 'src/shrpx_tls.cc')
-rw-r--r-- | src/shrpx_tls.cc | 159 |
1 files changed, 146 insertions, 13 deletions
diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index aa0c9f2..10bbbf2 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -72,6 +72,11 @@ # endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL #endif // ENABLE_HTTP3 +#ifdef HAVE_LIBBROTLI +# include <brotli/encode.h> +# include <brotli/decode.h> +#endif // HAVE_LIBBROTLI + #include "shrpx_log.h" #include "shrpx_client_handler.h" #include "shrpx_config.h" @@ -158,6 +163,35 @@ int ssl_pem_passwd_cb(char *buf, int size, int rwflag, void *user_data) { } // namespace namespace { +std::shared_ptr<std::vector<uint8_t>> +get_ocsp_data(TLSContextData *tls_ctx_data) { +#ifdef HAVE_ATOMIC_STD_SHARED_PTR + return std::atomic_load_explicit(&tls_ctx_data->ocsp_data, + std::memory_order_acquire); +#else // !HAVE_ATOMIC_STD_SHARED_PTR + std::lock_guard<std::mutex> g(tls_ctx_data->mu); + return tls_ctx_data->ocsp_data; +#endif // !HAVE_ATOMIC_STD_SHARED_PTR +} +} // namespace + +namespace { +void set_ocsp_response(SSL *ssl) { +#ifdef NGHTTP2_OPENSSL_IS_BORINGSSL + auto tls_ctx_data = + static_cast<TLSContextData *>(SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); + auto data = get_ocsp_data(tls_ctx_data); + + if (!data) { + return; + } + + SSL_set_ocsp_response(ssl, data->data(), data->size()); +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL +} +} // namespace + +namespace { // *al is set to SSL_AD_UNRECOGNIZED_NAME by openssl, so we don't have // to set it explicitly. int servername_callback(SSL *ssl, int *al, void *arg) { @@ -167,12 +201,16 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto rawhost = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (rawhost == nullptr) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } auto len = strlen(rawhost); // NI_MAXHOST includes terminal NULL. if (len == 0 || len + 1 > NI_MAXHOST) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } @@ -194,6 +232,8 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto idx = cert_tree->lookup(hostname); if (idx == -1) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } @@ -290,25 +330,14 @@ int servername_callback(SSL *ssl, int *al, void *arg) { SSL_set_SSL_CTX(ssl, ssl_ctx_list[0]); + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_OK; } } // namespace #ifndef NGHTTP2_OPENSSL_IS_BORINGSSL namespace { -std::shared_ptr<std::vector<uint8_t>> -get_ocsp_data(TLSContextData *tls_ctx_data) { -# ifdef HAVE_ATOMIC_STD_SHARED_PTR - return std::atomic_load_explicit(&tls_ctx_data->ocsp_data, - std::memory_order_acquire); -# else // !HAVE_ATOMIC_STD_SHARED_PTR - std::lock_guard<std::mutex> g(tls_ctx_data->mu); - return tls_ctx_data->ocsp_data; -# endif // !HAVE_ATOMIC_STD_SHARED_PTR -} -} // namespace - -namespace { int ocsp_resp_cb(SSL *ssl, void *arg) { auto ssl_ctx = SSL_get_SSL_CTX(ssl); auto tls_ctx_data = @@ -817,6 +846,83 @@ unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity_out, } // namespace #endif // !OPENSSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) +namespace { +int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) { + uint8_t *dest; + + size_t compressed_size = BrotliEncoderMaxCompressedSize(in_len); + if (compressed_size == 0) { + LOG(ERROR) << "BrotliEncoderMaxCompressedSize failed"; + + return 0; + } + + if (LOG_ENABLED(INFO)) { + LOG(INFO) << "Maximum compressed size is " << compressed_size + << " bytes against input " << in_len << " bytes"; + } + + if (!CBB_reserve(out, &dest, compressed_size)) { + LOG(ERROR) << "CBB_reserve failed"; + + return 0; + } + + if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW, + BROTLI_MODE_GENERIC, in_len, in, &compressed_size, + dest) != BROTLI_TRUE) { + LOG(ERROR) << "BrotliEncoderCompress failed"; + + return 0; + } + + if (LOG_ENABLED(INFO)) { + LOG(INFO) << "BrotliEncoderCompress succeeded, produced " << compressed_size + << " bytes, " << (in_len - compressed_size) * 100 / in_len + << "% reduction"; + } + + if (!CBB_did_write(out, compressed_size)) { + LOG(ERROR) << "CBB_did_write failed"; + + return 0; + } + + return 1; +} + +int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len, + const uint8_t *in, size_t in_len) { + uint8_t *dest; + auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len); + auto len = uncompressed_len; + + if (BrotliDecoderDecompress(in_len, in, &len, dest) != + BROTLI_DECODER_RESULT_SUCCESS) { + LOG(ERROR) << "BrotliDecoderDecompress failed"; + + CRYPTO_BUFFER_free(buf); + + return 0; + } + + if (uncompressed_len != len) { + LOG(ERROR) << "Unexpected uncompressed length: expected " + << uncompressed_len << " bytes, actual " << len << " bytes"; + + CRYPTO_BUFFER_free(buf); + + return 0; + } + + *out = buf; + + return 1; +} +} // namespace +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + struct TLSProtocol { StringRef name; long int mask; @@ -1110,6 +1216,15 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file, SSL_CTX_set_psk_server_callback(ssl_ctx, psk_server_cb); #endif // !LIBRESSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } @@ -1369,6 +1484,15 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, SSL_CTX_set_psk_server_callback(ssl_ctx, psk_server_cb); # endif // !LIBRESSL_NO_PSK +# if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +# endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } #endif // ENABLE_HTTP3 @@ -1478,6 +1602,15 @@ SSL_CTX *create_ssl_client_context( SSL_CTX_set_psk_client_callback(ssl_ctx, psk_client_cb); #endif // !OPENSSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } |