]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: ssl: Fix to not serve expired OCSP responses.
authorEmeric Brun <ebrun@haproxy.com>
Fri, 20 Jun 2014 13:46:13 +0000 (15:46 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 23 Jun 2014 10:14:47 +0000 (12:14 +0200)
For some browsers (firefox), an expired OCSP Response causes unwanted behavior.

Haproxy stops serving OCSP response if nextupdate date minus
the supported time skew (#define OCSP_MAX_RESPONSE_TIME_SKEW) is
in the past.

src/ssl_sock.c

index 278af8bbaf87ec2a6368637c65818c36cf6d4111..9eacf9f942b81a78e5a526d88bb63a96a9ac8770 100644 (file)
@@ -110,9 +110,91 @@ struct certificate_ocsp {
        struct ebmb_node key;
        unsigned char key_data[OCSP_MAX_CERTID_ASN1_LENGTH];
        struct chunk response;
-
+       long expire;
 };
 
+/*
+ *  This function returns the number of seconds  elapsed
+ *  since the Epoch, 1970-01-01 00:00:00 +0000 (UTC) and the
+ *  date presented un ASN1_GENERALIZEDTIME.
+ *
+ *  In parsing error case, it returns -1.
+ */
+static long asn1_generalizedtime_to_epoch(ASN1_GENERALIZEDTIME *d)
+{
+       long epoch;
+       char *p, *end;
+       const unsigned short month_offset[12] = {
+               0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+       };
+       int year, month;
+
+       if (!d || (d->type != V_ASN1_GENERALIZEDTIME)) return -1;
+
+       p = (char *)d->data;
+       end = p + d->length;
+
+       if (end - p < 4) return -1;
+       year = 1000 * (p[0] - '0') + 100 * (p[1] - '0') + 10 * (p[2] - '0') + p[3] - '0';
+       p += 4;
+       if (end - p < 2) return -1;
+       month = 10 * (p[0] - '0') + p[1] - '0';
+       if (month < 1 || month > 12) return -1;
+       /* Compute the number of seconds since 1 jan 1970 and the beginning of current month
+          We consider leap years and the current month (<marsh or not) */
+       epoch = (  ((year - 1970) * 365)
+                + ((year - (month < 3)) / 4 - (year - (month < 3)) / 100 + (year - (month < 3)) / 400)
+                - ((1970 - 1) / 4 - (1970 - 1) / 100 + (1970 - 1) / 400)
+                + month_offset[month-1]
+               ) * 24 * 60 * 60;
+       p += 2;
+       if (end - p < 2) return -1;
+       /* Add the number of seconds of completed days of current month */
+       epoch += (10 * (p[0] - '0') + p[1] - '0' - 1) * 24 * 60 * 60;
+       p += 2;
+       if (end - p < 2) return -1;
+       /* Add the completed hours of the current day */
+       epoch += (10 * (p[0] - '0') + p[1] - '0') * 60 * 60;
+       p += 2;
+       if (end - p < 2) return -1;
+       /* Add the completed minutes of the current hour */
+       epoch += (10 * (p[0] - '0') + p[1] - '0') * 60;
+       p += 2;
+       if (p == end) return -1;
+       /* Test if there is available seconds */
+       if (p[0] < '0' || p[0] > '9')
+               goto nosec;
+       if (end - p < 2) return -1;
+       /* Add the seconds of the current minute */
+       epoch += 10 * (p[0] - '0') + p[1] - '0';
+       p += 2;
+       if (p == end) return -1;
+       /* Ignore seconds float part if present */
+       if (p[0] == '.') {
+               do {
+                       if (++p == end) return -1;
+               } while (p[0] >= '0' && p[0] <= '9');
+       }
+
+nosec:
+       if (p[0] == 'Z') {
+               if (end - p != 1) return -1;
+               return epoch;
+       }
+       else if (p[0] == '+') {
+               if (end - p != 5) return -1;
+               /* Apply timezone offset */
+               return epoch - ((10 * (p[1] - '0') + p[2] - '0') * 60 + (10 * (p[3] - '0') + p[4] - '0')) * 60;
+       }
+       else if (p[0] == '-') {
+               if (end - p != 5) return -1;
+               /* Apply timezone offset */
+               return epoch + ((10 * (p[1] - '0') + p[2] - '0') * 60 + (10 * (p[3] - '0') + p[4] - '0')) * 60;
+       }
+
+       return -1;
+}
+
 static struct eb_root cert_ocsp_tree;
 
 /* This function starts to check if the OCSP response (in DER format) contained
@@ -229,6 +311,8 @@ static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certi
                goto out;
        }
 
+       ocsp->expire = asn1_generalizedtime_to_epoch(nextupd) - OCSP_MAX_RESPONSE_TIME_SKEW;
+
        ret = 0;
 out:
        if (bs)
@@ -306,7 +390,8 @@ int ssl_sock_ocsp_stapling_cbk(SSL *ssl, void *arg)
 
        if (!ocsp ||
            !ocsp->response.str ||
-            !ocsp->response.len)
+           !ocsp->response.len ||
+           (ocsp->expire < now.tv_sec))
                return SSL_TLSEXT_ERR_NOACK;
 
        ssl_buf = OPENSSL_malloc(ocsp->response.len);