mirror of
https://github.com/nginx/nginx.git
synced 2024-11-23 20:19:02 +08:00
SSL: caching CRLs.
Based on previous work by Mini Hawthorne.
This commit is contained in:
parent
7ea2fb6cb1
commit
61314518de
@ -18,6 +18,7 @@ typedef struct {
|
||||
} ngx_openssl_conf_t;
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t ngx_ssl_cert_already_in_hash(void);
|
||||
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);
|
||||
@ -739,17 +740,16 @@ ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
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 *x509;
|
||||
X509_STORE *store;
|
||||
STACK_OF(X509_CRL) *chain;
|
||||
|
||||
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) {
|
||||
@ -758,22 +758,36 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
||||
chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CRL, &err, crl, NULL);
|
||||
if (chain == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load CRL \"%s\": %s", crl->data, err);
|
||||
}
|
||||
|
||||
if (lookup == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_STORE_add_lookup() failed");
|
||||
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(chain);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
x509 = sk_X509_CRL_value(chain, i);
|
||||
|
||||
if (X509_STORE_add_crl(store, x509) != 1) {
|
||||
|
||||
if (ngx_ssl_cert_already_in_hash()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_STORE_add_crl(\"%s\") failed", crl->data);
|
||||
sk_X509_CRL_pop_free(chain, X509_CRL_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_CRL_pop_free(chain, X509_CRL_free);
|
||||
|
||||
X509_STORE_set_flags(store,
|
||||
X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
|
||||
|
||||
@ -781,6 +795,32 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_ssl_cert_already_in_hash(void)
|
||||
{
|
||||
#if !(OPENSSL_VERSION_NUMBER >= 0x1010009fL \
|
||||
|| LIBRESSL_VERSION_NUMBER >= 0x3050000fL)
|
||||
u_long error;
|
||||
|
||||
/*
|
||||
* OpenSSL prior to 1.1.0i doesn't ignore duplicate certificate entries,
|
||||
* see https://github.com/openssl/openssl/commit/c0452248
|
||||
*/
|
||||
|
||||
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();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
|
||||
{
|
||||
|
@ -195,6 +195,7 @@ typedef struct {
|
||||
|
||||
#define NGX_SSL_CACHE_CERT 0
|
||||
#define NGX_SSL_CACHE_PKEY 1
|
||||
#define NGX_SSL_CACHE_CRL 2
|
||||
|
||||
|
||||
ngx_int_t ngx_ssl_init(ngx_log_t *log);
|
||||
|
@ -65,6 +65,11 @@ static int ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
|
||||
static void ngx_ssl_cache_pkey_free(void *data);
|
||||
static void *ngx_ssl_cache_pkey_ref(char **err, void *data);
|
||||
|
||||
static void *ngx_ssl_cache_crl_create(ngx_ssl_cache_key_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_ssl_cache_key_t *id, char **err);
|
||||
|
||||
static void *ngx_openssl_cache_create_conf(ngx_cycle_t *cycle);
|
||||
@ -107,6 +112,11 @@ static ngx_ssl_cache_type_t ngx_ssl_cache_types[] = {
|
||||
{ ngx_ssl_cache_pkey_create,
|
||||
ngx_ssl_cache_pkey_free,
|
||||
ngx_ssl_cache_pkey_ref },
|
||||
|
||||
/* NGX_SSL_CACHE_CRL */
|
||||
{ ngx_ssl_cache_crl_create,
|
||||
ngx_ssl_cache_crl_free,
|
||||
ngx_ssl_cache_crl_ref },
|
||||
};
|
||||
|
||||
|
||||
@ -177,7 +187,9 @@ static ngx_int_t
|
||||
ngx_ssl_cache_init_key(ngx_pool_t *pool, ngx_uint_t index, ngx_str_t *path,
|
||||
ngx_ssl_cache_key_t *id)
|
||||
{
|
||||
if (ngx_strncmp(path->data, "data:", sizeof("data:") - 1) == 0) {
|
||||
if (index <= NGX_SSL_CACHE_PKEY
|
||||
&& ngx_strncmp(path->data, "data:", sizeof("data:") - 1) == 0)
|
||||
{
|
||||
id->type = NGX_SSL_CACHE_DATA;
|
||||
|
||||
} else if (index == NGX_SSL_CACHE_PKEY
|
||||
@ -517,6 +529,100 @@ ngx_ssl_cache_pkey_ref(char **err, void *data)
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_ssl_cache_crl_create(ngx_ssl_cache_key_t *id, char **err, void *data)
|
||||
{
|
||||
BIO *bio;
|
||||
u_long n;
|
||||
X509_CRL *x509;
|
||||
STACK_OF(X509_CRL) *chain;
|
||||
|
||||
chain = sk_X509_CRL_new_null();
|
||||
if (chain == NULL) {
|
||||
*err = "sk_X509_CRL_new_null() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio = ngx_ssl_cache_create_bio(id, err);
|
||||
if (bio == NULL) {
|
||||
sk_X509_CRL_pop_free(chain, X509_CRL_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
x509 = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
|
||||
if (x509 == NULL) {
|
||||
n = ERR_peek_last_error();
|
||||
|
||||
if (ERR_GET_LIB(n) == ERR_LIB_PEM
|
||||
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE
|
||||
&& sk_X509_CRL_num(chain) > 0)
|
||||
{
|
||||
/* end of file */
|
||||
ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
/* some real error */
|
||||
|
||||
*err = "PEM_read_bio_X509_CRL() failed";
|
||||
BIO_free(bio);
|
||||
sk_X509_CRL_pop_free(chain, X509_CRL_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sk_X509_CRL_push(chain, x509) == 0) {
|
||||
*err = "sk_X509_CRL_push() failed";
|
||||
BIO_free(bio);
|
||||
X509_CRL_free(x509);
|
||||
sk_X509_CRL_pop_free(chain, X509_CRL_free);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
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 *x509;
|
||||
STACK_OF(X509_CRL) *chain;
|
||||
|
||||
chain = sk_X509_CRL_dup(data);
|
||||
if (chain == NULL) {
|
||||
*err = "sk_X509_CRL_dup() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = sk_X509_CRL_num(chain);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
x509 = sk_X509_CRL_value(chain, i);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
X509_CRL_up_ref(x509);
|
||||
#else
|
||||
CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509_CRL);
|
||||
#endif
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
static BIO *
|
||||
ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user