[nginx] SSL: made it possible to iterate though all certificates.

Maxim Dounin mdounin at mdounin.ru
Thu May 19 17:30:22 UTC 2016


details:   http://hg.nginx.org/nginx/rev/8a34e92d8ab5
branches:  
changeset: 6548:8a34e92d8ab5
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Thu May 19 14:46:32 2016 +0300
description:
SSL: made it possible to iterate though all certificates.

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.

diffstat:

 src/event/ngx_event_openssl.c          |  65 ++++++++++++++++++++++++++-------
 src/event/ngx_event_openssl.h          |   1 +
 src/event/ngx_event_openssl_stapling.c |  26 ++++++++-----
 3 files changed, 67 insertions(+), 25 deletions(-)

diffs (179 lines):

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
@@ -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;
 
 
@@ -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) {
@@ -214,6 +222,12 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
         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 */
@@ -350,6 +364,16 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
         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)
     {
@@ -360,8 +384,6 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
         return NGX_ERROR;
     }
 
-    X509_free(x509);
-
     /* read rest of the chain */
 
     for ( ;; ) {
@@ -2163,7 +2185,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ss
 
     /*
      * 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();
@@ -2183,18 +2205,21 @@ ngx_ssl_session_id_context(ngx_ssl_t *ss
         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;
-    }
-
-    if (EVP_DigestUpdate(md, buf, len) == 0) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "EVP_DigestUpdate() 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;
+        }
     }
 
     list = SSL_CTX_get_client_CA_list(ssl->ctx);
@@ -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);
 }
 
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
@@ -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;
 
 
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -126,12 +126,15 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl
 {
     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);
@@ -455,11 +458,14 @@ ngx_ssl_stapling_resolver(ngx_conf_t *cf
     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;
 }



More information about the nginx-devel mailing list