[PATCH 2 of 2] SSL: support for TLSv1.3 certificate compression with BoringSSL
Sergey Kandaurov
pluknet at nginx.com
Wed Apr 12 12:55:50 UTC 2023
# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1681304032 -14400
# Wed Apr 12 16:53:52 2023 +0400
# Node ID 09a8a2f9aa68656ee45fd90119d4402c6f707a6f
# Parent 06458cd5733cd2ffaa4e2d26d357524a0934a7eb
SSL: support for TLSv1.3 certificate compression with BoringSSL.
Certificates are compressed with zlib and cached in SSL context exdata
on the first callback invocation.
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -9,6 +9,10 @@
#include <ngx_core.h>
#include <ngx_event.h>
+#if (defined TLSEXT_cert_compression_zlib && NGX_ZLIB)
+#include <zlib.h>
+#endif
+
#define NGX_SSL_PASSWORD_BUFFER_SIZE 4096
@@ -24,6 +28,10 @@ static EVP_PKEY *ngx_ssl_load_certificat
ngx_str_t *key, ngx_array_t *passwords);
static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
void *userdata);
+#if (defined TLSEXT_cert_compression_zlib && NGX_ZLIB)
+static int ngx_ssl_cert_compression_callback(ngx_ssl_conn_t *ssl_conn,
+ CBB *out, const uint8_t *in, size_t in_len);
+#endif
static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
int ret);
@@ -137,6 +145,7 @@ int ngx_ssl_ocsp_index;
int ngx_ssl_certificate_index;
int ngx_ssl_next_certificate_index;
int ngx_ssl_certificate_name_index;
+int ngx_ssl_certificate_comp_index;
int ngx_ssl_stapling_index;
@@ -247,6 +256,14 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR;
}
+ ngx_ssl_certificate_comp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
+ NULL, NULL);
+ if (ngx_ssl_certificate_comp_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);
if (ngx_ssl_stapling_index == -1) {
@@ -280,6 +297,14 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
return NGX_ERROR;
}
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_comp_index, NULL)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ return NGX_ERROR;
+ }
+
ssl->buffer_size = NGX_SSL_BUFSIZE;
/* client side options */
@@ -860,6 +885,15 @@ ngx_ssl_certificate_compression(ngx_conf
return NGX_OK;
}
+#elif (defined TLSEXT_cert_compression_zlib && NGX_ZLIB)
+
+ if (SSL_CTX_add_cert_compression_alg(ssl->ctx, TLSEXT_cert_compression_zlib,
+ ngx_ssl_cert_compression_callback,
+ NULL))
+ {
+ return NGX_OK;
+ }
+
#endif
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
@@ -869,6 +903,49 @@ ngx_ssl_certificate_compression(ngx_conf
}
+#if (defined TLSEXT_cert_compression_zlib && NGX_ZLIB)
+
+static int
+ngx_ssl_cert_compression_callback(ngx_ssl_conn_t *ssl_conn, CBB *out,
+ const uint8_t *in, size_t in_len)
+{
+ SSL_CTX *ssl_ctx;
+ ngx_str_t *comp;
+ ngx_connection_t *c;
+
+ ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
+ comp = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_certificate_comp_index);
+
+ if (comp == NULL) {
+ c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
+
+ comp = ngx_alloc(sizeof(ngx_str_t), c->log);
+ if (comp == NULL) {
+ return 0;
+ }
+
+ comp->len = compressBound(in_len);
+ comp->data = ngx_alloc(comp->len, c->log);
+ if (comp->data == NULL) {
+ ngx_free(comp);
+ return 0;
+ }
+
+ if (compress(comp->data, &comp->len, in, in_len) != Z_OK) {
+ ngx_free(comp->data);
+ ngx_free(comp);
+ return 0;
+ }
+
+ SSL_CTX_set_ex_data(ssl_ctx, ngx_ssl_certificate_comp_index, comp);
+ }
+
+ return CBB_add_bytes(out, comp->data, comp->len);
+}
+
+#endif
+
+
ngx_int_t
ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
ngx_uint_t prefer_server_ciphers)
@@ -4832,7 +4909,8 @@ ngx_ssl_cleanup_ctx(void *data)
{
ngx_ssl_t *ssl = data;
- X509 *cert, *next;
+ X509 *cert, *next;
+ ngx_str_t *comp;
cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
@@ -4842,6 +4920,13 @@ ngx_ssl_cleanup_ctx(void *data)
cert = next;
}
+ comp = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_comp_index);
+
+ if (comp != NULL) {
+ ngx_free(comp->data);
+ ngx_free(comp);
+ }
+
SSL_CTX_free(ssl->ctx);
}
More information about the nginx-devel
mailing list