# HG changeset patch # User Mini Hawthorne <m...@f5.com> # Date 1721762914 0 # Tue Jul 23 19:28:34 2024 +0000 # Node ID 867e05f555e6f593589a0278c865e7dcffe597f4 # Parent 42e86c051200bf00d9ae6e38d6c87a916391b642 SSL: caching certificate revocation lists.
Added ngx_ssl_cache_crl which is similar to certificate caching. It basically calls X509_CRL versions of APIs instead of X509 versions. 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 @@ -886,17 +886,16 @@ ngx_ssl_trusted_certificate(ngx_conf_t * ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) { - X509_STORE *store; - X509_LOOKUP *lookup; + int n, i; + char *err; + X509_CRL *xc; + X509_STORE *store; + STACK_OF(X509_CRL) *xcsk; if (crl->len == 0) { return NGX_OK; } - if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) { - return NGX_ERROR; - } - store = SSL_CTX_get_cert_store(ssl->ctx); if (store == NULL) { @@ -905,20 +904,44 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *s return NGX_ERROR; } - lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); - - if (lookup == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "X509_STORE_add_lookup() failed"); + xcsk = ngx_ssl_cache_fetch(cf->cycle, cf->pool, &ngx_ssl_cache_crl, + &err, crl, NULL); + if (xcsk == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "failed to load \"%s\": %s", crl->data, err); + } + return NGX_ERROR; } - if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "X509_LOOKUP_load_file(\"%s\") failed", crl->data); - return NGX_ERROR; + n = sk_X509_CRL_num(xcsk); + + for (i = 0; i < n; i++) { + xc = sk_X509_CRL_value(xcsk, i); + + if (X509_STORE_add_crl(store, xc) != 1) { + +#if !(OPENSSL_VERSION_NUMBER >= 0x1010009fL \ + || LIBRESSL_VERSION_NUMBER >= 0x3050000fL) + u_long error; + + /* not reported in OpenSSL 1.1.0i+ */ + + error = ERR_peek_last_error(); + + if (ERR_GET_LIB(error) == ERR_LIB_X509 + && ERR_GET_REASON(error) == X509_R_CERT_ALREADY_IN_HASH_TABLE) + { + ERR_clear_error(); + continue; + } +#endif + + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_STORE_add_crl() failed"); + return NGX_ERROR; + } } X509_STORE_set_flags(store, diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -352,6 +352,7 @@ extern int ngx_ssl_index; extern ngx_ssl_cache_type_t ngx_ssl_cache_cert; +extern ngx_ssl_cache_type_t ngx_ssl_cache_crl; #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */ diff --git a/src/event/ngx_event_openssl_cache.c b/src/event/ngx_event_openssl_cache.c --- a/src/event/ngx_event_openssl_cache.c +++ b/src/event/ngx_event_openssl_cache.c @@ -50,6 +50,10 @@ static void *ngx_ssl_cache_cert_create(n static void ngx_ssl_cache_cert_free(void *data); static void *ngx_ssl_cache_cert_ref(char **err, void *data); +static void *ngx_ssl_cache_crl_create(ngx_str_t *id, char **err, void *data); +static void ngx_ssl_cache_crl_free(void *data); +static void *ngx_ssl_cache_crl_ref(char **err, void *data); + static BIO *ngx_ssl_cache_create_bio(ngx_str_t *id, char **err); @@ -69,6 +73,15 @@ ngx_ssl_cache_type_t ngx_ssl_cache_cert }; +ngx_ssl_cache_type_t ngx_ssl_cache_crl = { + "certificate revocation list", + + ngx_ssl_cache_crl_create, + ngx_ssl_cache_crl_free, + ngx_ssl_cache_crl_ref, +}; + + ngx_module_t ngx_openssl_cache_module = { NGX_MODULE_V1, &ngx_openssl_cache_module_ctx, /* module context */ @@ -405,6 +418,96 @@ ngx_ssl_cache_cert_ref(char **err, void } +static void * +ngx_ssl_cache_crl_create(ngx_str_t *id, char **err, void *data) +{ + BIO *bio; + u_long n; + X509_CRL *xc; + STACK_OF(X509_CRL) *sk; + + /* start with an empty revocation list */ + sk = sk_X509_CRL_new_null(); + if (sk == NULL) { + *err = "sk_X509_CRL_new_null() failed"; + return NULL; + } + + /* figure out where to load from */ + bio = ngx_ssl_cache_create_bio(id, err); + if (bio == NULL) { + sk_X509_CRL_pop_free(sk, X509_CRL_free); + return NULL; + } + + /* read all of the revocations */ + while ((xc = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) != NULL) { + if (sk_X509_CRL_push(sk, xc) <= 0) { + *err = "sk_X509_CRL_push() failed"; + BIO_free(bio); + sk_X509_CRL_pop_free(sk, X509_CRL_free); + return NULL; + } + } + + BIO_free(bio); + + n = ERR_peek_last_error(); + if (sk_X509_CRL_num(sk) == 0 + || ERR_GET_LIB(n) != ERR_LIB_PEM + || ERR_GET_REASON(n) != PEM_R_NO_START_LINE) + { + /* the failure wasn't "no more revocations to load" */ + *err = "PEM_read_bio_X509_CRL() failed"; + sk_X509_CRL_pop_free(sk, X509_CRL_free); + return NULL; + } + + /* success leaves errors on the error stack */ + ERR_clear_error(); + + return sk; +} + + +static void +ngx_ssl_cache_crl_free(void *data) +{ + sk_X509_CRL_pop_free(data, X509_CRL_free); +} + + +static void * +ngx_ssl_cache_crl_ref(char **err, void *data) +{ + int n, i; + X509_CRL *xc; + STACK_OF(X509_CRL) *sk; + + /* stacks aren't reference-counted, so shallow copy into a new stack */ + sk = sk_X509_CRL_dup(data); + if (sk == NULL) { + *err = "sk_X509_CRL_dup() failed"; + return NULL; + } + + /* bump the revocations' reference counts */ + n = sk_X509_CRL_num(sk); + + for (i = 0; i < n; i++) { + xc = sk_X509_CRL_value(sk, i); + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + X509_CRL_up_ref(xc); +#else + CRYPTO_add(&xc->references, 1, CRYPTO_LOCK_X509_CRL); +#endif + } + + return sk; +} + + static BIO * ngx_ssl_cache_create_bio(ngx_str_t *id, char **err) { _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel