]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
app-layer-ssl: add validity dates from certificate
authorMats Klepsland <mats.klepsland@gmail.com>
Mon, 19 Oct 2015 08:54:40 +0000 (10:54 +0200)
committerVictor Julien <victor@inliniac.net>
Sun, 25 Sep 2016 20:35:34 +0000 (22:35 +0200)
Parsing of certificate validity dates to get notBefore and notAfter
fields.

src/app-layer-ssl.h
src/app-layer-tls-handshake.c
src/util-decode-der-get.c
src/util-decode-der-get.h

index 3253ce46d56ebd1d3f4efa7b0ee2942312f2a2a5..31ca913e746718f1b6d6e44299bc7cf53a0e23e3 100644 (file)
@@ -147,6 +147,8 @@ typedef struct SSLStateConnp_ {
 
     char *cert0_subject;
     char *cert0_issuerdn;
+    time_t cert0_not_before;
+    time_t cert0_not_after;
     char *cert0_fingerprint;
 
     /* ssl server name indication extension */
index 663471e8313706a61b09b34e060411eb723be84d..9ae3a1080164fc1565a80cb11ed2dd0ab125e385 100644 (file)
@@ -87,6 +87,7 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input,
     int i;
     Asn1Generic *cert;
     char buffer[256];
+    time_t not_before, not_after;
     int rc;
     int parsed;
     uint8_t *start_data;
@@ -176,6 +177,16 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input,
                 }
             }
 
+            rc = Asn1DerGetValidity(cert, &not_before, &not_after, &errcode);
+            if (rc != 0) {
+                TLSCertificateErrCodeToWarning(ssl_state, errcode);
+            } else {
+                if (i == 0) {
+                    ssl_state->server_connp.cert0_not_before = not_before;
+                    ssl_state->server_connp.cert0_not_after = not_after;
+                }
+            }
+
             DerFree(cert);
 
             if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) {
index 1c556c837d4fb098552be88a4c25e58699bc5f9d..413c43158140b3191dc038350e8867268189387d 100644 (file)
@@ -38,6 +38,7 @@
 #include "util-decode-der-get.h"
 
 static const uint8_t SEQ_IDX_ISSUER[] = { 0, 2 };
+static const uint8_t SEQ_IDX_VALIDITY[] = { 0, 3 };
 static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 };
 
 static const char *Oid2ShortStr(const char *oid)
@@ -72,6 +73,68 @@ static const char *Oid2ShortStr(const char *oid)
     return "unknown";
 }
 
+static time_t GentimeToTime(char *gentime)
+{
+    time_t time;
+    struct tm tm;
+
+    /* GeneralizedTime values MUST be expressed in Greenwich Mean Time
+     * (Zulu) and MUST include seconds (rfc5280 4.1.2.5.2). It MUST NOT
+     * include fractional seconds. It should therefore be on the format
+     * YYYYmmddHHMMSSZ. */
+    if (strlen(gentime) != 15)
+        goto error;
+
+    tm.tm_gmtoff = 0;
+    strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
+    time = SCMkTimeUtc(&tm);
+
+    if (time < 0)
+        goto error;
+
+    return time;
+
+error:
+    return -1;
+}
+
+static time_t UtctimeToTime(char *utctime)
+{
+    time_t time;
+    unsigned int year;
+    char yy[2];
+    char buf[20];
+
+    /* UTCTime values MUST be expressed in Greenwich Mean Time (Zulu)
+     * and MUST include seconds (rfc5280 4.1.2.5.1). It should
+     * therefore be on the format YYmmddHHMMSSZ. */
+    if (strlen(utctime) != 13)
+        goto error;
+
+    /* UTCTime use two digits to represent the year. The year field (YY)
+     * should be interpreted as 19YY when it is greater than or equal to
+     * 50. If it is less than 50 it should be interpreted as 20YY.
+     * Because of this, GeneralizedTime must be used for dates in the
+     * year 2050 or later. */
+    strlcpy(yy, utctime, sizeof(yy));
+    year = strtol(yy, NULL, 10);
+    if (year >= 50)
+        snprintf(buf, sizeof(buf), "%i%s", 19, utctime);
+    else if (year < 50)
+        snprintf(buf, sizeof(buf), "%i%s", 20, utctime);
+    else
+        goto error;
+
+    time = GentimeToTime(buf);
+    if (time == -1)
+        goto error;
+
+    return time;
+
+error:
+    return -1;
+}
+
 /**
  * \brief Iterate through an ASN.1 structure, following the index sequence.
  *        Context specific elements are skipped.
@@ -129,6 +192,57 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index,
     return node;
 }
 
+int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before,
+                       time_t *not_after, uint32_t *errcode)
+{
+    const Asn1Generic *node, *it;
+    int rc = -1;
+
+    if (errcode)
+        *errcode = ERR_DER_MISSING_ELEMENT;
+
+    node = Asn1DerGet(cert, SEQ_IDX_VALIDITY, sizeof(SEQ_IDX_VALIDITY), errcode);
+    if ((node == NULL) || node->type != ASN1_SEQUENCE)
+        goto validity_error;
+
+    it = node->data;
+    if (it == NULL || it->str == NULL)
+        goto validity_error;
+
+    if (it->type == ASN1_UTCTIME)
+        *not_before = UtctimeToTime(it->str);
+    else if (it->type == ASN1_GENERALIZEDTIME)
+        *not_before = GentimeToTime(it->str);
+    else
+        goto validity_error;
+
+    if (*not_before == -1)
+        goto validity_error;
+
+    if (node->next == NULL)
+        goto validity_error;
+
+    it = node->next->data;
+
+    if (it == NULL || it->str == NULL)
+        goto validity_error;
+
+    if (it->type == ASN1_UTCTIME)
+        *not_after = UtctimeToTime(it->str);
+    else if (it->type == ASN1_GENERALIZEDTIME)
+        *not_after = GentimeToTime(it->str);
+    else
+        goto validity_error;
+
+    if (*not_after == -1)
+        goto validity_error;
+
+    rc = 0;
+
+validity_error:
+    return rc;
+}
+
 int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length,
                        uint32_t *errcode)
 {
index 79ecd7879c84c7d93431d0191cd7c36be5945532..2d2168aeb3f3be28b9539d22c5ab31a34c72b7a5 100644 (file)
@@ -38,6 +38,7 @@
 const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode);
 
 int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode);
+int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, time_t *not_after, uint32_t *errcode);
 int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode);
 
 #endif /* __UTIL_DECODE_DER_GET_H__ */