Latest update - GitHub 5917e9d
This commit is contained in:
+262
-385
@@ -18,15 +18,12 @@ typedef struct {
|
||||
} ngx_openssl_conf_t;
|
||||
|
||||
|
||||
static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err,
|
||||
ngx_str_t *cert, STACK_OF(X509) **chain);
|
||||
static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
|
||||
ngx_str_t *key, ngx_array_t *passwords);
|
||||
static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
|
||||
void *userdata);
|
||||
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);
|
||||
static int ngx_ssl_cmp_x509_name(const X509_NAME *const *a,
|
||||
const X509_NAME *const *b);
|
||||
static void ngx_ssl_passwords_cleanup(void *data);
|
||||
static int ngx_ssl_new_client_session(ngx_ssl_conn_t *ssl_conn,
|
||||
ngx_ssl_session_t *sess);
|
||||
@@ -131,10 +128,8 @@ int ngx_ssl_server_conf_index;
|
||||
int ngx_ssl_session_cache_index;
|
||||
int ngx_ssl_ticket_keys_index;
|
||||
int ngx_ssl_ocsp_index;
|
||||
int ngx_ssl_certificate_index;
|
||||
int ngx_ssl_next_certificate_index;
|
||||
int ngx_ssl_index;
|
||||
int ngx_ssl_certificate_name_index;
|
||||
int ngx_ssl_stapling_index;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
@@ -258,21 +253,14 @@ ngx_ssl_init(ngx_log_t *log)
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (ngx_ssl_certificate_index == -1) {
|
||||
ngx_ssl_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (ngx_ssl_index == -1) {
|
||||
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
|
||||
"SSL_CTX_get_ex_new_index() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_ssl_next_certificate_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (ngx_ssl_next_certificate_index == -1) {
|
||||
ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_ssl_certificate_name_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
|
||||
NULL);
|
||||
|
||||
@@ -281,13 +269,6 @@ ngx_ssl_init(ngx_log_t *log)
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_ssl_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (ngx_ssl_stapling_index == -1) {
|
||||
ngx_ssl_error(NGX_LOG_ALERT, log, 0, "X509_get_ex_new_index() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
@@ -308,12 +289,15 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, NULL) == 0) {
|
||||
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_index, ssl) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_set_ex_data() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_rbtree_init(&ssl->staple_rbtree, &ssl->staple_sentinel,
|
||||
ngx_rbtree_insert_value);
|
||||
|
||||
ssl->buffer_size = NGX_SSL_BUFSIZE;
|
||||
|
||||
/* client side options */
|
||||
@@ -458,12 +442,12 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_str_t *key, ngx_array_t *passwords)
|
||||
{
|
||||
char *err;
|
||||
X509 *x509;
|
||||
X509 *x509, **elm;
|
||||
EVP_PKEY *pkey;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain);
|
||||
if (x509 == NULL) {
|
||||
chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CERT, &err, cert, NULL);
|
||||
if (chain == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
@@ -473,6 +457,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
x509 = sk_X509_shift(chain);
|
||||
|
||||
if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_certificate(\"%s\") failed", cert->data);
|
||||
@@ -490,29 +476,29 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
|
||||
SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
|
||||
if (ssl->certs.elts == NULL) {
|
||||
if (ngx_array_init(&ssl->certs, cf->pool, 1, sizeof(X509 *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
elm = ngx_array_push(&ssl->certs);
|
||||
if (elm == NULL) {
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_set_ex_data() failed");
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
*elm = x509;
|
||||
|
||||
/*
|
||||
* Note that x509 is not freed here, but will be instead freed in
|
||||
* ngx_ssl_cleanup_ctx(). This is because we need to preserve all
|
||||
* certificates to be able to iterate all of them through exdata
|
||||
* (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index),
|
||||
* certificates to be able to iterate all of them through ssl->certs,
|
||||
* while OpenSSL can free a certificate if it is replaced with another
|
||||
* certificate of the same type.
|
||||
*/
|
||||
@@ -550,7 +536,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
}
|
||||
#endif
|
||||
|
||||
pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords);
|
||||
pkey = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_PKEY, &err, key, passwords);
|
||||
if (pkey == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
@@ -583,8 +569,9 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
EVP_PKEY *pkey;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain);
|
||||
if (x509 == NULL) {
|
||||
chain = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_CERT, &err,
|
||||
cert, NULL);
|
||||
if (chain == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
@@ -594,6 +581,8 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
x509 = sk_X509_shift(chain);
|
||||
|
||||
if (SSL_use_certificate(c->ssl->connection, x509) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
"SSL_use_certificate(\"%s\") failed", cert->data);
|
||||
@@ -621,7 +610,8 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
|
||||
#endif
|
||||
|
||||
pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords);
|
||||
pkey = ngx_ssl_cache_connection_fetch(pool, NGX_SSL_CACHE_PKEY, &err,
|
||||
key, passwords);
|
||||
if (pkey == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
|
||||
@@ -645,241 +635,6 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
|
||||
}
|
||||
|
||||
|
||||
static X509 *
|
||||
ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert,
|
||||
STACK_OF(X509) **chain)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x509, *temp;
|
||||
u_long n;
|
||||
|
||||
if (ngx_strncmp(cert->data, "data:", sizeof("data:") - 1) == 0) {
|
||||
|
||||
bio = BIO_new_mem_buf(cert->data + sizeof("data:") - 1,
|
||||
cert->len - (sizeof("data:") - 1));
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_mem_buf() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert)
|
||||
!= NGX_OK)
|
||||
{
|
||||
*err = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio = BIO_new_file((char *) cert->data, "r");
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_file() failed";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* certificate itself */
|
||||
|
||||
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
|
||||
if (x509 == NULL) {
|
||||
*err = "PEM_read_bio_X509_AUX() failed";
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* rest of the chain */
|
||||
|
||||
*chain = sk_X509_new_null();
|
||||
if (*chain == NULL) {
|
||||
*err = "sk_X509_new_null() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
temp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
if (temp == NULL) {
|
||||
n = ERR_peek_last_error();
|
||||
|
||||
if (ERR_GET_LIB(n) == ERR_LIB_PEM
|
||||
&& ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
|
||||
{
|
||||
/* end of file */
|
||||
ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
/* some real error */
|
||||
|
||||
*err = "PEM_read_bio_X509() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(*chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sk_X509_push(*chain, temp) == 0) {
|
||||
*err = "sk_X509_push() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(*chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return x509;
|
||||
}
|
||||
|
||||
|
||||
static EVP_PKEY *
|
||||
ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
|
||||
ngx_str_t *key, ngx_array_t *passwords)
|
||||
{
|
||||
BIO *bio;
|
||||
EVP_PKEY *pkey;
|
||||
ngx_str_t *pwd;
|
||||
ngx_uint_t tries;
|
||||
pem_password_cb *cb;
|
||||
|
||||
if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
|
||||
u_char *p, *last;
|
||||
ENGINE *engine;
|
||||
|
||||
p = key->data + sizeof("engine:") - 1;
|
||||
last = (u_char *) ngx_strchr(p, ':');
|
||||
|
||||
if (last == NULL) {
|
||||
*err = "invalid syntax";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last = '\0';
|
||||
|
||||
engine = ENGINE_by_id((char *) p);
|
||||
|
||||
*last++ = ':';
|
||||
|
||||
if (engine == NULL) {
|
||||
*err = "ENGINE_by_id() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
|
||||
|
||||
if (pkey == NULL) {
|
||||
*err = "ENGINE_load_private_key() failed";
|
||||
ENGINE_free(engine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ENGINE_free(engine);
|
||||
|
||||
return pkey;
|
||||
|
||||
#else
|
||||
|
||||
*err = "loading \"engine:...\" certificate keys is not supported";
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ngx_strncmp(key->data, "data:", sizeof("data:") - 1) == 0) {
|
||||
|
||||
bio = BIO_new_mem_buf(key->data + sizeof("data:") - 1,
|
||||
key->len - (sizeof("data:") - 1));
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_mem_buf() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, key)
|
||||
!= NGX_OK)
|
||||
{
|
||||
*err = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio = BIO_new_file((char *) key->data, "r");
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_file() failed";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (passwords) {
|
||||
tries = passwords->nelts;
|
||||
pwd = passwords->elts;
|
||||
cb = ngx_ssl_password_callback;
|
||||
|
||||
} else {
|
||||
tries = 1;
|
||||
pwd = NULL;
|
||||
cb = NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
|
||||
if (pkey != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tries-- > 1) {
|
||||
ERR_clear_error();
|
||||
(void) BIO_reset(bio);
|
||||
pwd++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*err = "PEM_read_bio_PrivateKey() failed";
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata)
|
||||
{
|
||||
ngx_str_t *pwd = userdata;
|
||||
|
||||
if (rwflag) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"ngx_ssl_password_callback() is called for encryption");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwd->len > (size_t) size) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"password is truncated to %d bytes", size);
|
||||
} else {
|
||||
size = pwd->len;
|
||||
}
|
||||
|
||||
ngx_memcpy(buf, pwd->data, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
|
||||
ngx_uint_t prefer_server_ciphers)
|
||||
@@ -903,6 +658,12 @@ ngx_int_t
|
||||
ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_int_t depth)
|
||||
{
|
||||
int n, i;
|
||||
char *err;
|
||||
X509 *x509;
|
||||
X509_NAME *name;
|
||||
X509_STORE *store;
|
||||
STACK_OF(X509) *chain;
|
||||
STACK_OF(X509_NAME) *list;
|
||||
|
||||
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
|
||||
@@ -913,88 +674,8 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_load_verify_locations(\"%s\") failed",
|
||||
cert->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSL_CTX_load_verify_locations() may leave errors in the error queue
|
||||
* while returning success
|
||||
*/
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
list = SSL_load_client_CA_file((char *) cert->data);
|
||||
|
||||
list = sk_X509_NAME_new(ngx_ssl_cmp_x509_name);
|
||||
if (list == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_load_client_CA_file(\"%s\") failed", cert->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
SSL_CTX_set_client_CA_list(ssl->ctx, list);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_int_t depth)
|
||||
{
|
||||
SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
|
||||
ngx_ssl_verify_callback);
|
||||
|
||||
SSL_CTX_set_verify_depth(ssl->ctx, depth);
|
||||
|
||||
if (cert->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_load_verify_locations(\"%s\") failed",
|
||||
cert->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSL_CTX_load_verify_locations() may leave errors in the error queue
|
||||
* while returning success
|
||||
*/
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
|
||||
{
|
||||
X509_STORE *store;
|
||||
X509_LOOKUP *lookup;
|
||||
|
||||
if (crl->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
@@ -1006,22 +687,190 @@ 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_CA, &err, cert, NULL);
|
||||
if (chain == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
cert->data, err);
|
||||
}
|
||||
|
||||
if (lookup == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_STORE_add_lookup() failed");
|
||||
sk_X509_NAME_pop_free(list, X509_NAME_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
|
||||
== 0)
|
||||
{
|
||||
n = sk_X509_num(chain);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
x509 = sk_X509_value(chain, i);
|
||||
|
||||
if (X509_STORE_add_cert(store, x509) != 1) {
|
||||
|
||||
if (ngx_ssl_cert_already_in_hash()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_STORE_add_cert(\"%s\") failed", cert->data);
|
||||
sk_X509_NAME_pop_free(list, X509_NAME_free);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
name = X509_get_subject_name(x509);
|
||||
if (name == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_get_subject_name(\"%s\") failed", cert->data);
|
||||
sk_X509_NAME_pop_free(list, X509_NAME_free);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
name = X509_NAME_dup(name);
|
||||
if (name == NULL) {
|
||||
sk_X509_NAME_pop_free(list, X509_NAME_free);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
if (sk_X509_NAME_find(list, NULL, name) > 0) {
|
||||
#else
|
||||
if (sk_X509_NAME_find(list, name) >= 0) {
|
||||
#endif
|
||||
X509_NAME_free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sk_X509_NAME_push(list, name) == 0) {
|
||||
sk_X509_NAME_pop_free(list, X509_NAME_free);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
X509_NAME_free(name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
|
||||
SSL_CTX_set_client_CA_list(ssl->ctx, list);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_int_t depth)
|
||||
{
|
||||
int i, n;
|
||||
char *err;
|
||||
X509 *x509;
|
||||
X509_STORE *store;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
|
||||
ngx_ssl_verify_callback);
|
||||
|
||||
SSL_CTX_set_verify_depth(ssl->ctx, depth);
|
||||
|
||||
if (cert->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
store = SSL_CTX_get_cert_store(ssl->ctx);
|
||||
|
||||
if (store == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_LOOKUP_load_file(\"%s\") failed", crl->data);
|
||||
"SSL_CTX_get_cert_store() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
chain = ngx_ssl_cache_fetch(cf, NGX_SSL_CACHE_CA, &err, cert, NULL);
|
||||
if (chain == NULL) {
|
||||
if (err != NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"cannot load certificate \"%s\": %s",
|
||||
cert->data, err);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = sk_X509_num(chain);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
x509 = sk_X509_value(chain, i);
|
||||
|
||||
if (X509_STORE_add_cert(store, x509) != 1) {
|
||||
|
||||
if (ngx_ssl_cert_already_in_hash()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_STORE_add_cert(\"%s\") failed", cert->data);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
|
||||
{
|
||||
int n, i;
|
||||
char *err;
|
||||
X509_CRL *x509;
|
||||
X509_STORE *store;
|
||||
STACK_OF(X509_CRL) *chain;
|
||||
|
||||
if (crl->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
store = SSL_CTX_get_cert_store(ssl->ctx);
|
||||
|
||||
if (store == NULL) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_get_cert_store() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -1029,6 +878,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)
|
||||
{
|
||||
@@ -1195,6 +1070,13 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_ssl_cmp_x509_name(const X509_NAME *const *a, const X509_NAME *const *b)
|
||||
{
|
||||
return (X509_NAME_cmp(*a, *b));
|
||||
}
|
||||
|
||||
|
||||
ngx_array_t *
|
||||
ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file)
|
||||
{
|
||||
@@ -3859,10 +3741,9 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
|
||||
cert;
|
||||
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
|
||||
{
|
||||
for (k = 0; k < ssl->certs.nelts; k++) {
|
||||
cert = ((X509 **) ssl->certs.elts)[k];
|
||||
|
||||
if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"X509_digest() failed");
|
||||
@@ -3876,9 +3757,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL
|
||||
&& certificates != NULL)
|
||||
{
|
||||
if (ssl->certs.nelts == 0 && certificates != NULL) {
|
||||
/*
|
||||
* If certificates are loaded dynamically, we use certificate
|
||||
* names as specified in the configuration (with variables).
|
||||
@@ -4890,14 +4769,12 @@ ngx_ssl_cleanup_ctx(void *data)
|
||||
{
|
||||
ngx_ssl_t *ssl = data;
|
||||
|
||||
X509 *cert, *next;
|
||||
X509 *cert;
|
||||
ngx_uint_t i;
|
||||
|
||||
cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
|
||||
|
||||
while (cert) {
|
||||
next = X509_get_ex_data(cert, ngx_ssl_next_certificate_index);
|
||||
for (i = 0; i < ssl->certs.nelts; i++) {
|
||||
cert = ((X509 **) ssl->certs.elts)[i];
|
||||
X509_free(cert);
|
||||
cert = next;
|
||||
}
|
||||
|
||||
SSL_CTX_free(ssl->ctx);
|
||||
|
||||
@@ -98,6 +98,12 @@ struct ngx_ssl_s {
|
||||
SSL_CTX *ctx;
|
||||
ngx_log_t *log;
|
||||
size_t buffer_size;
|
||||
|
||||
ngx_array_t certs;
|
||||
|
||||
ngx_rbtree_t staple_rbtree;
|
||||
ngx_rbtree_node_t staple_sentinel;
|
||||
|
||||
ngx_ssl_dyn_rec_t dyn_rec;
|
||||
};
|
||||
|
||||
@@ -201,6 +207,12 @@ typedef struct {
|
||||
#define NGX_SSL_BUFSIZE 16384
|
||||
|
||||
|
||||
#define NGX_SSL_CACHE_CERT 0
|
||||
#define NGX_SSL_CACHE_PKEY 1
|
||||
#define NGX_SSL_CACHE_CRL 2
|
||||
#define NGX_SSL_CACHE_CA 3
|
||||
|
||||
|
||||
ngx_int_t ngx_ssl_init(ngx_log_t *log);
|
||||
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
|
||||
|
||||
@@ -232,6 +244,11 @@ ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
|
||||
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
|
||||
ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data);
|
||||
|
||||
void *ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
|
||||
ngx_str_t *path, void *data);
|
||||
void *ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index,
|
||||
char **err, ngx_str_t *path, void *data);
|
||||
|
||||
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
|
||||
ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
|
||||
ngx_array_t *passwords);
|
||||
@@ -343,10 +360,8 @@ extern int ngx_ssl_server_conf_index;
|
||||
extern int ngx_ssl_session_cache_index;
|
||||
extern int ngx_ssl_ticket_keys_index;
|
||||
extern int ngx_ssl_ocsp_index;
|
||||
extern int ngx_ssl_certificate_index;
|
||||
extern int ngx_ssl_next_certificate_index;
|
||||
extern int ngx_ssl_index;
|
||||
extern int ngx_ssl_certificate_name_index;
|
||||
extern int ngx_ssl_stapling_index;
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
|
||||
@@ -0,0 +1,806 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_SSL_CACHE_PATH 0
|
||||
#define NGX_SSL_CACHE_DATA 1
|
||||
#define NGX_SSL_CACHE_ENGINE 2
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned type:2;
|
||||
unsigned len:30;
|
||||
u_char *data;
|
||||
} ngx_ssl_cache_key_t;
|
||||
|
||||
|
||||
typedef void *(*ngx_ssl_cache_create_pt)(ngx_ssl_cache_key_t *id, char **err,
|
||||
void *data);
|
||||
typedef void (*ngx_ssl_cache_free_pt)(void *data);
|
||||
typedef void *(*ngx_ssl_cache_ref_pt)(char **err, void *data);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_ssl_cache_create_pt create;
|
||||
ngx_ssl_cache_free_pt free;
|
||||
ngx_ssl_cache_ref_pt ref;
|
||||
} ngx_ssl_cache_type_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_node_t node;
|
||||
ngx_ssl_cache_key_t id;
|
||||
ngx_ssl_cache_type_t *type;
|
||||
void *value;
|
||||
} ngx_ssl_cache_node_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
} ngx_ssl_cache_t;
|
||||
|
||||
|
||||
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);
|
||||
static ngx_ssl_cache_node_t *ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache,
|
||||
ngx_ssl_cache_type_t *type, ngx_ssl_cache_key_t *id, uint32_t hash);
|
||||
|
||||
static void *ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err,
|
||||
void *data);
|
||||
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_pkey_create(ngx_ssl_cache_key_t *id, char **err,
|
||||
void *data);
|
||||
static int ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
|
||||
void *userdata);
|
||||
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 void *ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, 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);
|
||||
static void ngx_ssl_cache_cleanup(void *data);
|
||||
static void ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_openssl_cache_module_ctx = {
|
||||
ngx_string("openssl_cache"),
|
||||
ngx_openssl_cache_create_conf,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_openssl_cache_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_openssl_cache_module_ctx, /* module context */
|
||||
NULL, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_ssl_cache_type_t ngx_ssl_cache_types[] = {
|
||||
|
||||
/* NGX_SSL_CACHE_CERT */
|
||||
{ ngx_ssl_cache_cert_create,
|
||||
ngx_ssl_cache_cert_free,
|
||||
ngx_ssl_cache_cert_ref },
|
||||
|
||||
/* NGX_SSL_CACHE_PKEY */
|
||||
{ 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 },
|
||||
|
||||
/* NGX_SSL_CACHE_CA */
|
||||
{ ngx_ssl_cache_ca_create,
|
||||
ngx_ssl_cache_cert_free,
|
||||
ngx_ssl_cache_cert_ref }
|
||||
};
|
||||
|
||||
|
||||
void *
|
||||
ngx_ssl_cache_fetch(ngx_conf_t *cf, ngx_uint_t index, char **err,
|
||||
ngx_str_t *path, void *data)
|
||||
{
|
||||
uint32_t hash;
|
||||
ngx_ssl_cache_t *cache;
|
||||
ngx_ssl_cache_key_t id;
|
||||
ngx_ssl_cache_type_t *type;
|
||||
ngx_ssl_cache_node_t *cn;
|
||||
|
||||
if (ngx_ssl_cache_init_key(cf->pool, index, path, &id) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache = (ngx_ssl_cache_t *) ngx_get_conf(cf->cycle->conf_ctx,
|
||||
ngx_openssl_cache_module);
|
||||
|
||||
type = &ngx_ssl_cache_types[index];
|
||||
hash = ngx_murmur_hash2(id.data, id.len);
|
||||
|
||||
cn = ngx_ssl_cache_lookup(cache, type, &id, hash);
|
||||
if (cn != NULL) {
|
||||
return type->ref(err, cn->value);
|
||||
}
|
||||
|
||||
cn = ngx_palloc(cf->pool, sizeof(ngx_ssl_cache_node_t) + id.len + 1);
|
||||
if (cn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cn->node.key = hash;
|
||||
cn->id.data = (u_char *)(cn + 1);
|
||||
cn->id.len = id.len;
|
||||
cn->id.type = id.type;
|
||||
cn->type = type;
|
||||
|
||||
ngx_cpystrn(cn->id.data, id.data, id.len + 1);
|
||||
|
||||
cn->value = type->create(&id, err, data);
|
||||
if (cn->value == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_rbtree_insert(&cache->rbtree, &cn->node);
|
||||
|
||||
return type->ref(err, cn->value);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_ssl_cache_connection_fetch(ngx_pool_t *pool, ngx_uint_t index, char **err,
|
||||
ngx_str_t *path, void *data)
|
||||
{
|
||||
ngx_ssl_cache_key_t id;
|
||||
|
||||
if (ngx_ssl_cache_init_key(pool, index, path, &id) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ngx_ssl_cache_types[index].create(&id, err, data);
|
||||
}
|
||||
|
||||
|
||||
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 (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
|
||||
&& ngx_strncmp(path->data, "engine:", sizeof("engine:") - 1) == 0)
|
||||
{
|
||||
id->type = NGX_SSL_CACHE_ENGINE;
|
||||
|
||||
} else {
|
||||
if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, path)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
id->type = NGX_SSL_CACHE_PATH;
|
||||
}
|
||||
|
||||
id->len = path->len;
|
||||
id->data = path->data;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_ssl_cache_node_t *
|
||||
ngx_ssl_cache_lookup(ngx_ssl_cache_t *cache, ngx_ssl_cache_type_t *type,
|
||||
ngx_ssl_cache_key_t *id, uint32_t hash)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_rbtree_node_t *node, *sentinel;
|
||||
ngx_ssl_cache_node_t *cn;
|
||||
|
||||
node = cache->rbtree.root;
|
||||
sentinel = cache->rbtree.sentinel;
|
||||
|
||||
while (node != sentinel) {
|
||||
|
||||
if (hash < node->key) {
|
||||
node = node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hash > node->key) {
|
||||
node = node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* hash == node->key */
|
||||
|
||||
cn = (ngx_ssl_cache_node_t *) node;
|
||||
|
||||
if (type < cn->type) {
|
||||
node = node->left;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type > cn->type) {
|
||||
node = node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* type == cn->type */
|
||||
|
||||
rc = ngx_memn2cmp(id->data, cn->id.data, id->len, cn->id.len);
|
||||
|
||||
if (rc == 0) {
|
||||
return cn;
|
||||
}
|
||||
|
||||
node = (rc < 0) ? node->left : node->right;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_ssl_cache_cert_create(ngx_ssl_cache_key_t *id, char **err, void *data)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x509;
|
||||
u_long n;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
chain = sk_X509_new_null();
|
||||
if (chain == NULL) {
|
||||
*err = "sk_X509_new_null() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio = ngx_ssl_cache_create_bio(id, err);
|
||||
if (bio == NULL) {
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* certificate itself */
|
||||
|
||||
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
|
||||
if (x509 == NULL) {
|
||||
*err = "PEM_read_bio_X509_AUX() failed";
|
||||
BIO_free(bio);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sk_X509_push(chain, x509) == 0) {
|
||||
*err = "sk_X509_push() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* rest of the chain */
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
x509 = PEM_read_bio_X509(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)
|
||||
{
|
||||
/* end of file */
|
||||
ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
/* some real error */
|
||||
|
||||
*err = "PEM_read_bio_X509() failed";
|
||||
BIO_free(bio);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sk_X509_push(chain, x509) == 0) {
|
||||
*err = "sk_X509_push() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_cache_cert_free(void *data)
|
||||
{
|
||||
sk_X509_pop_free(data, X509_free);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_ssl_cache_cert_ref(char **err, void *data)
|
||||
{
|
||||
int n, i;
|
||||
X509 *x509;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
chain = sk_X509_dup(data);
|
||||
if (chain == NULL) {
|
||||
*err = "sk_X509_dup() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = sk_X509_num(chain);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
x509 = sk_X509_value(chain, i);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
X509_up_ref(x509);
|
||||
#else
|
||||
CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
|
||||
#endif
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_ssl_cache_pkey_create(ngx_ssl_cache_key_t *id, char **err, void *data)
|
||||
{
|
||||
ngx_array_t *passwords = data;
|
||||
|
||||
BIO *bio;
|
||||
EVP_PKEY *pkey;
|
||||
ngx_str_t *pwd;
|
||||
ngx_uint_t tries;
|
||||
pem_password_cb *cb;
|
||||
|
||||
if (id->type == NGX_SSL_CACHE_ENGINE) {
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
|
||||
u_char *p, *last;
|
||||
ENGINE *engine;
|
||||
|
||||
p = id->data + sizeof("engine:") - 1;
|
||||
last = (u_char *) ngx_strchr(p, ':');
|
||||
|
||||
if (last == NULL) {
|
||||
*err = "invalid syntax";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*last = '\0';
|
||||
|
||||
engine = ENGINE_by_id((char *) p);
|
||||
|
||||
*last++ = ':';
|
||||
|
||||
if (engine == NULL) {
|
||||
*err = "ENGINE_by_id() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
|
||||
|
||||
if (pkey == NULL) {
|
||||
*err = "ENGINE_load_private_key() failed";
|
||||
ENGINE_free(engine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ENGINE_free(engine);
|
||||
|
||||
return pkey;
|
||||
|
||||
#else
|
||||
|
||||
*err = "loading \"engine:...\" certificate keys is not supported";
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bio = ngx_ssl_cache_create_bio(id, err);
|
||||
if (bio == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (passwords) {
|
||||
tries = passwords->nelts;
|
||||
pwd = passwords->elts;
|
||||
cb = ngx_ssl_cache_pkey_password_callback;
|
||||
|
||||
} else {
|
||||
tries = 1;
|
||||
pwd = NULL;
|
||||
cb = NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
|
||||
if (pkey != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tries-- > 1) {
|
||||
ERR_clear_error();
|
||||
(void) BIO_reset(bio);
|
||||
pwd++;
|
||||
continue;
|
||||
}
|
||||
|
||||
*err = "PEM_read_bio_PrivateKey() failed";
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_ssl_cache_pkey_password_callback(char *buf, int size, int rwflag,
|
||||
void *userdata)
|
||||
{
|
||||
ngx_str_t *pwd = userdata;
|
||||
|
||||
if (rwflag) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"ngx_ssl_cache_pkey_password_callback() is called "
|
||||
"for encryption");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwd->len > (size_t) size) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"password is truncated to %d bytes", size);
|
||||
} else {
|
||||
size = pwd->len;
|
||||
}
|
||||
|
||||
ngx_memcpy(buf, pwd->data, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_cache_pkey_free(void *data)
|
||||
{
|
||||
EVP_PKEY_free(data);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_ssl_cache_pkey_ref(char **err, void *data)
|
||||
{
|
||||
EVP_PKEY *pkey = data;
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
EVP_PKEY_up_ref(pkey);
|
||||
#else
|
||||
CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
||||
#endif
|
||||
|
||||
return 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 void *
|
||||
ngx_ssl_cache_ca_create(ngx_ssl_cache_key_t *id, char **err, void *data)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x509;
|
||||
u_long n;
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
chain = sk_X509_new_null();
|
||||
if (chain == NULL) {
|
||||
*err = "sk_X509_new_null() failed";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bio = ngx_ssl_cache_create_bio(id, err);
|
||||
if (bio == NULL) {
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
x509 = PEM_read_bio_X509_AUX(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_num(chain) > 0)
|
||||
{
|
||||
/* end of file */
|
||||
ERR_clear_error();
|
||||
break;
|
||||
}
|
||||
|
||||
/* some real error */
|
||||
|
||||
*err = "PEM_read_bio_X509_AUX() failed";
|
||||
BIO_free(bio);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sk_X509_push(chain, x509) == 0) {
|
||||
*err = "sk_X509_push() failed";
|
||||
BIO_free(bio);
|
||||
X509_free(x509);
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free(bio);
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
static BIO *
|
||||
ngx_ssl_cache_create_bio(ngx_ssl_cache_key_t *id, char **err)
|
||||
{
|
||||
BIO *bio;
|
||||
|
||||
if (id->type == NGX_SSL_CACHE_DATA) {
|
||||
|
||||
bio = BIO_new_mem_buf(id->data + sizeof("data:") - 1,
|
||||
id->len - (sizeof("data:") - 1));
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_mem_buf() failed";
|
||||
}
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
bio = BIO_new_file((char *) id->data, "r");
|
||||
if (bio == NULL) {
|
||||
*err = "BIO_new_file() failed";
|
||||
}
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_openssl_cache_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_ssl_cache_t *cache;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
cache = ngx_pcalloc(cycle->pool, sizeof(ngx_ssl_cache_t));
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln = ngx_pool_cleanup_add(cycle->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln->handler = ngx_ssl_cache_cleanup;
|
||||
cln->data = cache;
|
||||
|
||||
ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
|
||||
ngx_ssl_cache_node_insert);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_cache_cleanup(void *data)
|
||||
{
|
||||
ngx_ssl_cache_t *cache = data;
|
||||
|
||||
ngx_rbtree_t *tree;
|
||||
ngx_rbtree_node_t *node;
|
||||
ngx_ssl_cache_node_t *cn;
|
||||
|
||||
tree = &cache->rbtree;
|
||||
|
||||
if (tree->root == tree->sentinel) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (node = ngx_rbtree_min(tree->root, tree->sentinel);
|
||||
node;
|
||||
node = ngx_rbtree_next(tree, node))
|
||||
{
|
||||
cn = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
|
||||
cn->type->free(cn->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_cache_node_insert(ngx_rbtree_node_t *temp,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
|
||||
{
|
||||
ngx_rbtree_node_t **p;
|
||||
ngx_ssl_cache_node_t *n, *t;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
n = ngx_rbtree_data(node, ngx_ssl_cache_node_t, node);
|
||||
t = ngx_rbtree_data(temp, ngx_ssl_cache_node_t, node);
|
||||
|
||||
if (node->key != temp->key) {
|
||||
|
||||
p = (node->key < temp->key) ? &temp->left : &temp->right;
|
||||
|
||||
} else if (n->type != t->type) {
|
||||
|
||||
p = (n->type < t->type) ? &temp->left : &temp->right;
|
||||
|
||||
} else {
|
||||
|
||||
p = (ngx_memn2cmp(n->id.data, t->id.data, n->id.len, t->id.len)
|
||||
< 0) ? &temp->left : &temp->right;
|
||||
}
|
||||
|
||||
if (*p == sentinel) {
|
||||
break;
|
||||
}
|
||||
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
ngx_rbt_red(node);
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_node_t node;
|
||||
|
||||
ngx_str_t staple;
|
||||
ngx_msec_t timeout;
|
||||
|
||||
@@ -154,6 +156,7 @@ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
|
||||
static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
|
||||
void *data);
|
||||
static ngx_ssl_stapling_t *ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert);
|
||||
static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
|
||||
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
|
||||
|
||||
@@ -195,12 +198,12 @@ ngx_int_t
|
||||
ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
|
||||
ngx_str_t *responder, ngx_uint_t verify)
|
||||
{
|
||||
X509 *cert;
|
||||
X509 *cert;
|
||||
ngx_uint_t k;
|
||||
|
||||
for (k = 0; k < ssl->certs.nelts; k++) {
|
||||
cert = ((X509 **) ssl->certs.elts)[k];
|
||||
|
||||
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
|
||||
cert;
|
||||
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
|
||||
{
|
||||
if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify)
|
||||
!= NGX_OK)
|
||||
{
|
||||
@@ -235,10 +238,9 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert,
|
||||
cln->handler = ngx_ssl_stapling_cleanup;
|
||||
cln->data = staple;
|
||||
|
||||
if (X509_set_ex_data(cert, ngx_ssl_stapling_index, staple) == 0) {
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
staple->node.key = (ngx_rbtree_key_t) cert;
|
||||
|
||||
ngx_rbtree_insert(&ssl->staple_rbtree, &staple->node);
|
||||
|
||||
#ifdef SSL_CTRL_SELECT_CURRENT_CERT
|
||||
/* OpenSSL 1.0.2+ */
|
||||
@@ -545,14 +547,21 @@ ngx_int_t
|
||||
ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
|
||||
{
|
||||
X509 *cert;
|
||||
ngx_rbtree_t *tree;
|
||||
ngx_rbtree_node_t *node;
|
||||
ngx_ssl_stapling_t *staple;
|
||||
|
||||
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
|
||||
cert;
|
||||
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
|
||||
tree = &ssl->staple_rbtree;
|
||||
|
||||
if (tree->root == tree->sentinel) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
for (node = ngx_rbtree_min(tree->root, tree->sentinel);
|
||||
node;
|
||||
node = ngx_rbtree_next(tree, node))
|
||||
{
|
||||
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);
|
||||
staple = ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
|
||||
staple->resolver = resolver;
|
||||
staple->resolver_timeout = resolver_timeout;
|
||||
}
|
||||
@@ -567,6 +576,8 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
|
||||
int rc;
|
||||
X509 *cert;
|
||||
u_char *p;
|
||||
SSL_CTX *ssl_ctx;
|
||||
ngx_ssl_t *ssl;
|
||||
ngx_connection_t *c;
|
||||
ngx_ssl_stapling_t *staple;
|
||||
|
||||
@@ -583,7 +594,10 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
|
||||
return rc;
|
||||
}
|
||||
|
||||
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);
|
||||
ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
|
||||
ssl = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_index);
|
||||
|
||||
staple = ngx_ssl_stapling_lookup(ssl, cert);
|
||||
|
||||
if (staple == NULL) {
|
||||
return rc;
|
||||
@@ -613,6 +627,30 @@ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
|
||||
}
|
||||
|
||||
|
||||
static ngx_ssl_stapling_t *
|
||||
ngx_ssl_stapling_lookup(ngx_ssl_t *ssl, X509 *cert)
|
||||
{
|
||||
ngx_rbtree_key_t key;
|
||||
ngx_rbtree_node_t *node, *sentinel;
|
||||
|
||||
node = ssl->staple_rbtree.root;
|
||||
sentinel = ssl->staple_rbtree.sentinel;
|
||||
key = (ngx_rbtree_key_t) cert;
|
||||
|
||||
while (node != sentinel) {
|
||||
|
||||
if (key != node->key) {
|
||||
node = (key < node->key) ? node->left : node->right;
|
||||
continue;
|
||||
}
|
||||
|
||||
return ngx_rbtree_data(node, ngx_ssl_stapling_t, node);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
|
||||
{
|
||||
@@ -2717,12 +2755,11 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
|
||||
ngx_str_t *responder, ngx_uint_t verify)
|
||||
{
|
||||
X509 *cert;
|
||||
ngx_uint_t k;
|
||||
|
||||
for (cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
|
||||
cert;
|
||||
cert = X509_get_ex_data(cert, ngx_ssl_next_certificate_index))
|
||||
{
|
||||
for (k = 0; k < ssl->certs.nelts; k++) {
|
||||
if (file->len) {
|
||||
cert = ((X509 **) ssl->certs.elts)[k];
|
||||
if (ngx_ssl_stapling_file(cf, ssl, cert, file, responder, verify)
|
||||
!= NGX_OK)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,6 @@ clean:
|
||||
@rm -f $(RESULT) *.o
|
||||
|
||||
debug: $(PROGNAME).o
|
||||
llvm-objdump -S -no-show-raw-insn $<
|
||||
llvm-objdump -S --no-show-raw-insn $<
|
||||
|
||||
.DELETE_ON_ERROR:
|
||||
Reference in New Issue
Block a user