[PATCH 1 of 6] SSL: SSL: introduce support of new openssl 1.0.2 features.

Filipe DA SILVA fdasilva at ingima.com
Thu Apr 16 10:10:09 UTC 2015


Hi, 

This is the new version of 'Multiple server certificate support ' patches.

It relies on openssl to maintain a list of server certificates.

Reviews and comments are welcome.

Regards,
Filipe da Silva
Ingima

---
# HG changeset patch
# User Filipe da Silva <fdasilva at ingima.com>
# Date 1429178261 -7200
#      Thu Apr 16 11:57:41 2015 +0200
# Node ID d201e4afd59eaf79419836c1dcdec83e141d3f67
# Parent  8b7f062a3fe60f01d373db6dc87f715d3c4fd214
SSL: introduce support of new openssl 1.0.2 features.
- Split 'ngx_ssl_certificate' in two parts
 to prepare 'Multiple SSL certificate' support.
- introduce 'ngx_ssl_cert_stapling_index'
- add new server certificate retrieval method.
- disable ngx_ssl_certificate_index when openssl 1.0.2.
- derivate ssl_session_id from all certificates.

diff -r 8b7f062a3fe6 -r d201e4afd59e src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c	Thu Apr 16 12:17:41 2015 +0300
+++ b/src/event/ngx_event_openssl.c	Thu Apr 16 11:57:41 2015 +0200
@@ -18,6 +18,10 @@ typedef struct {
 } ngx_openssl_conf_t;
 
 
+static ngx_int_t ngx_ssl_server_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
+    ngx_str_t *cert);
+static ngx_int_t ngx_ssl_private_key(ngx_conf_t *cf, ngx_ssl_t *ssl,
+    ngx_str_t *key, ngx_array_t *passwords);
 static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
     void *userdata);
 static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
@@ -101,8 +105,11 @@ int  ngx_ssl_connection_index;
 int  ngx_ssl_server_conf_index;
 int  ngx_ssl_session_cache_index;
 int  ngx_ssl_session_ticket_keys_index;
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
 int  ngx_ssl_certificate_index;
+#endif
 int  ngx_ssl_stapling_index;
+int  ngx_ssl_cert_stapling_index;
 
 
 ngx_int_t
@@ -168,6 +175,7 @@ ngx_ssl_init(ngx_log_t *log)
         return NGX_ERROR;
     }
 
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
     ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                          NULL);
     if (ngx_ssl_certificate_index == -1) {
@@ -175,6 +183,7 @@ ngx_ssl_init(ngx_log_t *log)
                       "SSL_CTX_get_ex_new_index() failed");
         return NGX_ERROR;
     }
+#endif
 
     ngx_ssl_stapling_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
                                                       NULL);
@@ -184,6 +193,14 @@ ngx_ssl_init(ngx_log_t *log)
         return NGX_ERROR;
     }
 
+    ngx_ssl_cert_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
+                                                        NULL);
+    if (ngx_ssl_cert_stapling_index == -1) {
+        ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+                      "X509_get_ex_new_index() failed");
+        return NGX_ERROR;
+    }
+
     return NGX_OK;
 }
 
@@ -297,15 +314,49 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
 }
 
 
+X509*
+ngx_ssl_get_server_certificate(ngx_ssl_t *ssl, ngx_flag_t first)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+    int     rc;
+    long    op;
+
+    op = first ? SSL_CERT_SET_FIRST : SSL_CERT_SET_NEXT;
+    rc = SSL_CTX_set_current_cert(ssl->ctx, op);
+    if (rc)
+        return (SSL_CTX_get0_certificate(ssl->ctx));
+#else
+    if (first)
+        return (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index));
+#endif
+    return NULL;
+}
+
+
 ngx_int_t
 ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
     ngx_str_t *key, ngx_array_t *passwords)
 {
+    /* load server certificate */
+    if (ngx_ssl_server_certificate(cf, ssl, cert) != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+    /* load private key */
+    if (ngx_ssl_private_key(cf, ssl, key, passwords) != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_server_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert)
+{
     BIO         *bio;
     X509        *x509;
     u_long       n;
-    ngx_str_t   *pwd;
-    ngx_uint_t   tries;
 
     if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
         return NGX_ERROR;
@@ -340,6 +391,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
         return NGX_ERROR;
     }
 
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
     if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
         == 0)
     {
@@ -349,6 +401,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
         BIO_free(bio);
         return NGX_ERROR;
     }
+#endif
 
     X509_free(x509);
 
@@ -376,10 +429,20 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
             return NGX_ERROR;
         }
 
+#ifdef SSL_CTX_add0_chain_cert
+        /* OpenSSL >=1.0.2 allows multiple server certificates in a single
+         * SSL_CTX to each have a different chain
+         */
+        if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) {
+            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                          "SSL_CTX_add0_chain_cert(\"%s\") failed",
+                          cert->data);
+#else
         if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                           "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
                           cert->data);
+#endif
             X509_free(x509);
             BIO_free(bio);
             return NGX_ERROR;
@@ -388,6 +451,17 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
 
     BIO_free(bio);
 
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_ssl_private_key(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *key,
+    ngx_array_t *passwords)
+{
+    ngx_str_t   *pwd;
+    ngx_uint_t   tries;
+
     if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
 
 #ifndef OPENSSL_NO_ENGINE
@@ -2150,8 +2224,10 @@ ngx_ssl_session_id_context(ngx_ssl_t *ss
         goto failed;
     }
 
-    cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
-
+    cert = ngx_ssl_get_server_certificate(ssl, NGX_SSL_FIRST_CERT);
+    while (cert) {
+
+    /* TODO: fix loop indentation */
     if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                       "X509_digest() failed");
@@ -2164,6 +2240,10 @@ ngx_ssl_session_id_context(ngx_ssl_t *ss
         goto failed;
     }
 
+        /* get next server certificate, if any */
+        cert = ngx_ssl_get_server_certificate(ssl, NGX_SSL_NEXT_CERT);
+    }
+
     list = SSL_CTX_get_client_CA_list(ssl->ctx);
 
     if (list != NULL) {
diff -r 8b7f062a3fe6 -r d201e4afd59e src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h	Thu Apr 16 12:17:41 2015 +0300
+++ b/src/event/ngx_event_openssl.h	Thu Apr 16 11:57:41 2015 +0200
@@ -189,6 +189,10 @@ ngx_int_t ngx_ssl_get_fingerprint(ngx_co
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+	
+#define NGX_SSL_FIRST_CERT       1
+#define NGX_SSL_NEXT_CERT        0
+X509* ngx_ssl_get_server_certificate(ngx_ssl_t *ssl, ngx_flag_t first);
 
 
 ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
@@ -210,6 +214,7 @@ 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_stapling_index;
+extern int  ngx_ssl_cert_stapling_index;
 
 
 #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */



More information about the nginx-devel mailing list