[PATCH 1 of 2] OCSP stapling: refactor OCSP response verification

Alessandro Ghedini alessandro at cloudflare.com
Fri Jan 22 17:37:56 UTC 2016


# HG changeset patch
# User Alessandro Ghedini <alessandro at cloudflare.com>
# Date 1453481195 0
#      Fri Jan 22 16:46:35 2016 +0000
# Node ID a8c4f65236ad90138863d5295ca059a3d37da37e
# Parent  02abce4764b7c964e7ee6e10b1a7abf1fee95f79
OCSP stapling: refactor OCSP response verification

Move the OCSP response verification and the certificate issuer code to
stand-alone functions, so that it can be reused by other code.

Signed-off-by: Alessandro Ghedini <alessandro at cloudflare.com>

diff -r 02abce4764b7 -r a8c4f65236ad src/event/ngx_event_openssl_stapling.c
--- a/src/event/ngx_event_openssl_stapling.c	Tue Jan 12 19:19:07 2016 +0300
+++ b/src/event/ngx_event_openssl_stapling.c	Fri Jan 22 16:46:35 2016 +0000
@@ -85,10 +85,15 @@
 
 static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_str_t *file);
+static ngx_int_t ngx_ssl_stapling_find_issuer(ngx_ssl_stapling_t *staple,
+    ngx_log_t *log, SSL_CTX *ssl_ctx, X509 *cert, STACK_OF(X509) *chain);
 static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
 static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_str_t *responder);
 
+static ngx_int_t ngx_ssl_stapling_verify_response(ngx_log_t *log,
+    ngx_str_t *resp, ngx_ssl_stapling_t *staple, STACK_OF(X509) *chain,
+    ngx_int_t flags, time_t *valid);
 static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
     void *data);
 static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
@@ -259,12 +264,87 @@
 
 
 static ngx_int_t
+ngx_ssl_stapling_find_issuer(ngx_ssl_stapling_t *staple, ngx_log_t *log,
+    SSL_CTX *ssl_ctx, X509 *cert, STACK_OF(X509) *chain)
+{
+    int                  i, n, rc;
+    X509                *issuer;
+    X509_STORE          *store;
+    X509_STORE_CTX      *store_ctx;
+
+    n = sk_X509_num(chain);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+                   "SSL get issuer: %d extra certs", n);
+
+    for (i = 0; i < n; i++) {
+        issuer = sk_X509_value(chain, i);
+        if (X509_check_issued(issuer, cert) == X509_V_OK) {
+            CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
+
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+                           "SSL get issuer: found %p in extra certs", issuer);
+
+            staple->cert = cert;
+            staple->issuer = issuer;
+
+            return NGX_OK;
+        }
+    }
+
+    store = SSL_CTX_get_cert_store(ssl_ctx);
+    if (store == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, log, 0,
+                      "SSL_CTX_get_cert_store() failed");
+        return NGX_ERROR;
+    }
+
+    store_ctx = X509_STORE_CTX_new();
+    if (store_ctx == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, log, 0,
+                      "X509_STORE_CTX_new() failed");
+        return NGX_ERROR;
+    }
+
+    if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) {
+        ngx_ssl_error(NGX_LOG_EMERG, log, 0,
+                      "X509_STORE_CTX_init() failed");
+        X509_STORE_CTX_free(store_ctx);
+        return NGX_ERROR;
+    }
+
+    rc = X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert);
+
+    if (rc == -1) {
+        ngx_ssl_error(NGX_LOG_EMERG, log, 0,
+                      "X509_STORE_CTX_get1_issuer() failed");
+        X509_STORE_CTX_free(store_ctx);
+        return NGX_ERROR;
+    }
+
+    if (rc == 0) {
+        ngx_log_error(NGX_LOG_WARN, log, 0,
+                      "\"ssl_stapling\" ignored, issuer certificate not found");
+        X509_STORE_CTX_free(store_ctx);
+        return NGX_DECLINED;
+    }
+
+    X509_STORE_CTX_free(store_ctx);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+                   "SSL get issuer: found %p in cert store", issuer);
+
+    staple->cert = cert;
+    staple->issuer = issuer;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
 {
-    int                  i, n, rc;
-    X509                *cert, *issuer;
-    X509_STORE          *store;
-    X509_STORE_CTX      *store_ctx;
+    X509                *cert;
     STACK_OF(X509)      *chain;
     ngx_ssl_stapling_t  *staple;
 
@@ -277,72 +357,8 @@
     chain = ssl->ctx->extra_certs;
 #endif
 
-    n = sk_X509_num(chain);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
-                   "SSL get issuer: %d extra certs", n);
-
-    for (i = 0; i < n; i++) {
-        issuer = sk_X509_value(chain, i);
-        if (X509_check_issued(issuer, cert) == X509_V_OK) {
-            CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
-
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
-                           "SSL get issuer: found %p in extra certs", issuer);
-
-            staple->cert = cert;
-            staple->issuer = issuer;
-
-            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;
-    }
-
-    store_ctx = X509_STORE_CTX_new();
-    if (store_ctx == NULL) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "X509_STORE_CTX_new() failed");
-        return NGX_ERROR;
-    }
-
-    if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "X509_STORE_CTX_init() failed");
-        X509_STORE_CTX_free(store_ctx);
-        return NGX_ERROR;
-    }
-
-    rc = X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert);
-
-    if (rc == -1) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "X509_STORE_CTX_get1_issuer() failed");
-        X509_STORE_CTX_free(store_ctx);
-        return NGX_ERROR;
-    }
-
-    if (rc == 0) {
-        ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
-                      "\"ssl_stapling\" ignored, issuer certificate not found");
-        X509_STORE_CTX_free(store_ctx);
-        return NGX_DECLINED;
-    }
-
-    X509_STORE_CTX_free(store_ctx);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
-                   "SSL get issuer: found %p in cert store", issuer);
-
-    staple->cert = cert;
-    staple->issuer = issuer;
-
-    return NGX_OK;
+    return ngx_ssl_stapling_find_issuer(staple, ssl->log, ssl->ctx,
+                                        cert, chain);
 }
 
 
@@ -529,8 +545,10 @@
 }
 
 
-static void
-ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
+static ngx_int_t
+ngx_ssl_stapling_verify_response(ngx_log_t *log, ngx_str_t *resp,
+    ngx_ssl_stapling_t *staple, STACK_OF(X509) *chain, ngx_int_t flags,
+    time_t *valid)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
     const
@@ -538,34 +556,24 @@
     u_char                *p;
     int                    n;
     size_t                 len;
-    time_t                 now, valid;
-    ngx_str_t              response;
     X509_STORE            *store;
-    STACK_OF(X509)        *chain;
     OCSP_CERTID           *id;
     OCSP_RESPONSE         *ocsp;
     OCSP_BASICRESP        *basic;
-    ngx_ssl_stapling_t    *staple;
     ASN1_GENERALIZEDTIME  *thisupdate, *nextupdate;
 
-    staple = ctx->data;
-    now = ngx_time();
     ocsp = NULL;
     basic = NULL;
     id = NULL;
 
-    if (ctx->code != 200) {
-        goto error;
-    }
-
     /* check the response */
 
-    len = ctx->response->last - ctx->response->pos;
-    p = ctx->response->pos;
+    len = resp->len;
+    p = resp->data;
 
     ocsp = d2i_OCSP_RESPONSE(NULL, &p, len);
     if (ocsp == NULL) {
-        ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_ssl_error(NGX_LOG_ERR, log, 0,
                       "d2i_OCSP_RESPONSE() failed");
         goto error;
     }
@@ -573,7 +581,7 @@
     n = OCSP_response_status(ocsp);
 
     if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
-        ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_log_error(NGX_LOG_ERR, log, 0,
                       "OCSP response not successful (%d: %s)",
                       n, OCSP_response_status_str(n));
         goto error;
@@ -581,36 +589,27 @@
 
     basic = OCSP_response_get1_basic(ocsp);
     if (basic == NULL) {
-        ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_ssl_error(NGX_LOG_ERR, log, 0,
                       "OCSP_response_get1_basic() failed");
         goto error;
     }
 
     store = SSL_CTX_get_cert_store(staple->ssl_ctx);
     if (store == NULL) {
-        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
+        ngx_ssl_error(NGX_LOG_CRIT, log, 0,
                       "SSL_CTX_get_cert_store() failed");
         goto error;
     }
 
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-    SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
-#else
-    chain = staple->ssl_ctx->extra_certs;
-#endif
-
-    if (OCSP_basic_verify(basic, chain, store,
-                          staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
-        != 1)
-    {
-        ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+    if (OCSP_basic_verify(basic, chain, store, flags) != 1) {
+        ngx_ssl_error(NGX_LOG_ERR, log, 0,
                       "OCSP_basic_verify() failed");
         goto error;
     }
 
-    id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
+    id = OCSP_cert_to_id(NULL, staple->cert, staple->issuer);
     if (id == NULL) {
-        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
+        ngx_ssl_error(NGX_LOG_CRIT, log, 0,
                       "OCSP_cert_to_id() failed");
         goto error;
     }
@@ -619,34 +618,34 @@
                               &thisupdate, &nextupdate)
         != 1)
     {
-        ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_log_error(NGX_LOG_ERR, log, 0,
                       "certificate status not found in the OCSP response");
         goto error;
     }
 
     if (n != V_OCSP_CERTSTATUS_GOOD) {
-        ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_log_error(NGX_LOG_ERR, log, 0,
                       "certificate status \"%s\" in the OCSP response",
                       OCSP_cert_status_str(n));
         goto error;
     }
 
     if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) {
-        ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+        ngx_ssl_error(NGX_LOG_ERR, log, 0,
                       "OCSP_check_validity() failed");
         goto error;
     }
 
     if (nextupdate) {
-        valid = ngx_ssl_stapling_time(nextupdate);
-        if (valid == (time_t) NGX_ERROR) {
-            ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
+        *valid = ngx_ssl_stapling_time(nextupdate);
+        if (*valid == (time_t) NGX_ERROR) {
+            ngx_log_error(NGX_LOG_ERR, log, 0,
                           "invalid nextUpdate time in certificate status");
             goto error;
         }
 
     } else {
-        valid = NGX_MAX_TIME_T_VALUE;
+        *valid = NGX_MAX_TIME_T_VALUE;
     }
 
     OCSP_CERTID_free(id);
@@ -657,9 +656,54 @@
     basic = NULL;
     ocsp = NULL;
 
+    return NGX_OK;
+
+error:
+
+    if (id) {
+        OCSP_CERTID_free(id);
+    }
+
+    if (basic) {
+        OCSP_BASICRESP_free(basic);
+    }
+
+    if (ocsp) {
+        OCSP_RESPONSE_free(ocsp);
+    }
+
+    return NGX_ERROR;
+}
+
+
+static void
+ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
+{
+    time_t                 now, valid;
+    ngx_int_t              rc, flags;
+    ngx_str_t              response;
+    STACK_OF(X509)        *chain;
+    ngx_ssl_stapling_t    *staple;
+
+    now = ngx_time();
+
+    staple = ctx->data;
+
+    if (ctx->code != 200) {
+        goto error;
+    }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+    SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
+#else
+    chain = staple->ssl_ctx->extra_certs;
+#endif
+
+    flags = staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY;
+
     /* copy the response to memory not in ctx->pool */
 
-    response.len = len;
+    response.len = ctx->response->last - ctx->response->pos;
     response.data = ngx_alloc(response.len, ctx->log);
 
     if (response.data == NULL) {
@@ -668,6 +712,14 @@
 
     ngx_memcpy(response.data, ctx->response->pos, response.len);
 
+    /* check the response */
+
+    rc = ngx_ssl_stapling_verify_response(ctx->log, &response, staple, chain,
+                                          flags, &valid);
+    if (rc != NGX_OK) {
+        goto error;
+    }
+
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    "ssl ocsp response, %s, %uz",
                    OCSP_cert_status_str(n), response.len);
@@ -695,16 +747,8 @@
     staple->loading = 0;
     staple->refresh = now + 300;
 
-    if (id) {
-        OCSP_CERTID_free(id);
-    }
-
-    if (basic) {
-        OCSP_BASICRESP_free(basic);
-    }
-
-    if (ocsp) {
-        OCSP_RESPONSE_free(ocsp);
+    if (response.data != NULL) {
+        ngx_free(response.data);
     }
 
     ngx_ssl_ocsp_done(ctx);



More information about the nginx-devel mailing list