[nginx] OCSP stapling: avoid sending expired responses (ticket #...

Maxim Dounin mdounin at mdounin.ru
Thu Jun 11 18:56:47 UTC 2015


details:   http://hg.nginx.org/nginx/rev/6893a1007a7c
branches:  
changeset: 6181:6893a1007a7c
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Thu Jun 11 20:42:39 2015 +0300
description:
OCSP stapling: avoid sending expired responses (ticket #425).

diffstat:

 src/event/ngx_event_openssl_stapling.c |  68 +++++++++++++++++++++++++++++++---
 1 files changed, 62 insertions(+), 6 deletions(-)

diffs (154 lines):

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
@@ -32,6 +32,7 @@ typedef struct {
     X509                        *issuer;
 
     time_t                       valid;
+    time_t                       refresh;
 
     unsigned                     verify:1;
     unsigned                     loading:1;
@@ -93,6 +94,8 @@ static int ngx_ssl_certificate_status_ca
 static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
 static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
 
+static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time);
+
 static void ngx_ssl_stapling_cleanup(void *data);
 
 static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void);
@@ -462,7 +465,9 @@ ngx_ssl_certificate_status_callback(ngx_
     staple = data;
     rc = SSL_TLSEXT_ERR_NOACK;
 
-    if (staple->staple.len) {
+    if (staple->staple.len
+        && staple->valid >= ngx_time())
+    {
         /* we have to copy ocsp response as OpenSSL will free it by itself */
 
         p = OPENSSL_malloc(staple->staple.len);
@@ -490,7 +495,7 @@ ngx_ssl_stapling_update(ngx_ssl_stapling
     ngx_ssl_ocsp_ctx_t  *ctx;
 
     if (staple->host.len == 0
-        || staple->loading || staple->valid >= ngx_time())
+        || staple->loading || staple->refresh >= ngx_time())
     {
         return;
     }
@@ -532,6 +537,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_oc
     u_char                *p;
     int                    n;
     size_t                 len;
+    time_t                 now, valid;
     ngx_str_t              response;
     X509_STORE            *store;
     STACK_OF(X509)        *chain;
@@ -542,6 +548,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_oc
     ASN1_GENERALIZEDTIME  *thisupdate, *nextupdate;
 
     staple = ctx->data;
+    now = ngx_time();
     ocsp = NULL;
     basic = NULL;
     id = NULL;
@@ -629,17 +636,28 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_oc
         goto error;
     }
 
+    valid = ngx_ssl_stapling_time(nextupdate);
+    if (valid == (time_t) NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
+                      "invalid nextUpdate time in certificate status");
+        goto error;
+    }
+
     OCSP_CERTID_free(id);
     OCSP_BASICRESP_free(basic);
     OCSP_RESPONSE_free(ocsp);
 
+    id = NULL;
+    basic = NULL;
+    ocsp = NULL;
+
     /* copy the response to memory not in ctx->pool */
 
     response.len = len;
     response.data = ngx_alloc(response.len, ctx->log);
 
     if (response.data == NULL) {
-        goto done;
+        goto error;
     }
 
     ngx_memcpy(response.data, ctx->response->pos, response.len);
@@ -653,11 +671,15 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_oc
     }
 
     staple->staple = response;
+    staple->valid = valid;
 
-done:
+    /*
+     * refresh before the response expires,
+     * but not earlier than in 5 minutes, and at least in an hour
+     */
 
     staple->loading = 0;
-    staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */
+    staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300);
 
     ngx_ssl_ocsp_done(ctx);
     return;
@@ -665,7 +687,7 @@ done:
 error:
 
     staple->loading = 0;
-    staple->valid = ngx_time() + 300; /* ssl_stapling_err_valid */
+    staple->refresh = now + 300;
 
     if (id) {
         OCSP_CERTID_free(id);
@@ -683,6 +705,40 @@ error:
 }
 
 
+static time_t
+ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time)
+{
+    u_char  *value;
+    size_t   len;
+    time_t   time;
+    BIO     *bio;
+
+    /*
+     * OpenSSL doesn't provide a way to convert ASN1_GENERALIZEDTIME
+     * into time_t.  To do this, we use ASN1_GENERALIZEDTIME_print(),
+     * which uses the "MMM DD HH:MM:SS YYYY [GMT]" format (e.g.,
+     * "Feb  3 00:55:52 2015 GMT"), and parse the result.
+     */
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        return NGX_ERROR;
+    }
+
+    /* fake weekday prepended to match C asctime() format */
+
+    BIO_write(bio, "Tue ", sizeof("Tue ") - 1);
+    ASN1_GENERALIZEDTIME_print(bio, asn1time);
+    len = BIO_get_mem_data(bio, &value);
+
+    time = ngx_parse_http_time(value, len);
+
+    BIO_free(bio);
+
+    return time;
+}
+
+
 static void
 ngx_ssl_stapling_cleanup(void *data)
 {



More information about the nginx-devel mailing list