Skip to content

Commit

Permalink
SSL: made it possible to iterate though all certificates.
Browse files Browse the repository at this point in the history
A pointer to a previously configured certificate now stored in a certificate.
This makes it possible to iterate though all certificates configured in
the SSL context.  This is now used to configure OCSP stapling for all
certificates, and in ngx_ssl_session_id_context().

As SSL_CTX_use_certificate() frees previously loaded certificate of the same
type, and we have no way to find out if it's the case, X509_free() calls
are now posponed till ngx_ssl_cleanup_ctx().

Note that in OpenSSL 1.0.2+ this can be done without storing things in exdata
using the SSL_CTX_set_current_cert() and SSL_CTX_get0_certificate() functions.
These are not yet available in all supported versions though, so it's easier
to continue to use exdata for now.
  • Loading branch information
mdounin committed May 19, 2016
1 parent 503b356 commit e844475
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 24 deletions.
63 changes: 49 additions & 14 deletions src/event/ngx_event_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index;
int ngx_ssl_session_ticket_keys_index;
int ngx_ssl_certificate_index;
int ngx_ssl_next_certificate_index;
int ngx_ssl_stapling_index;


Expand Down Expand Up @@ -187,6 +188,13 @@ ngx_ssl_init(ngx_log_t *log)
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_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL, NULL);

if (ngx_ssl_stapling_index == -1) {
Expand Down Expand Up @@ -214,6 +222,12 @@ 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) {
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 */
Expand Down Expand Up @@ -350,6 +364,16 @@ 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");
X509_free(x509);
BIO_free(bio);
return NGX_ERROR;
}

if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
== 0)
{
Expand All @@ -360,8 +384,6 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR;
}

X509_free(x509);

/* read rest of the chain */

for ( ;; ) {
Expand Down Expand Up @@ -2163,7 +2185,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)

/*
* Session ID context is set based on the string provided,
* the server certificate, and the client CA list.
* the server certificates, and the client CA list.
*/

md = EVP_MD_CTX_create();
Expand All @@ -2183,18 +2205,21 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
goto failed;
}

cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);

if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_digest() failed");
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))
{
if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_digest() failed");
goto failed;
}

if (EVP_DigestUpdate(md, buf, len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"EVP_DigestUpdate() failed");
goto failed;
if (EVP_DigestUpdate(md, buf, len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"EVP_DigestUpdate() failed");
goto failed;
}
}

list = SSL_CTX_get_client_CA_list(ssl->ctx);
Expand Down Expand Up @@ -2950,6 +2975,16 @@ ngx_ssl_cleanup_ctx(void *data)
{
ngx_ssl_t *ssl = data;

X509 *cert, *next;

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);
X509_free(cert);
cert = next;
}

SSL_CTX_free(ssl->ctx);
}

Expand Down
1 change: 1 addition & 0 deletions src/event/ngx_event_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index;
extern int ngx_ssl_session_ticket_keys_index;
extern int ngx_ssl_certificate_index;
extern int ngx_ssl_next_certificate_index;
extern int ngx_ssl_stapling_index;


Expand Down
26 changes: 16 additions & 10 deletions src/event/ngx_event_openssl_stapling.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,15 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
{
X509 *cert;

cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);

if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify)
!= NGX_OK)
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))
{
return NGX_ERROR;
if (ngx_ssl_stapling_certificate(cf, ssl, cert, file, responder, verify)
!= NGX_OK)
{
return NGX_ERROR;
}
}

SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback);
Expand Down Expand Up @@ -455,11 +458,14 @@ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
X509 *cert;
ngx_ssl_stapling_t *staple;

cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);

staple->resolver = resolver;
staple->resolver_timeout = resolver_timeout;
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))
{
staple = X509_get_ex_data(cert, ngx_ssl_stapling_index);
staple->resolver = resolver;
staple->resolver_timeout = resolver_timeout;
}

return NGX_OK;
}
Expand Down

0 comments on commit e844475

Please sign in to comment.