]> granicus.if.org Git - p11-kit/commitdiff
Don't respect timezones for CKA_START_DATE or CKA_END_DATE
authorStef Walter <stefw@gnome.org>
Fri, 29 Mar 2013 12:17:29 +0000 (13:17 +0100)
committerStef Walter <stefw@gnome.org>
Wed, 3 Apr 2013 13:45:38 +0000 (15:45 +0200)
The PKCS#11 specification does not note what timezone these dates
are in. In addition the time values are not represented in PKCS#11.

So don't reinterpret certificate dates, other than filling in the
century for dates that have a two digit year.

Lastly, these are low resolution optional fields so not being all
strict about timezones here is appropriate.

https://bugs.freedesktop.org/show_bug.cgi?id=62825

common/asn1.c
common/asn1.h
trust/builder.c
trust/tests/test-builder.c

index c98d95990b0ada614b38fce29822895960a58c0c..45d91abe4bc1075dc34607f66fdc3876f8a32f74 100644 (file)
@@ -192,338 +192,6 @@ p11_asn1_encode (node_asn *asn,
        return der;
 }
 
-static int
-atoin (const char *p,
-       int digits)
-{
-       int ret = 0, base = 1;
-       while(--digits >= 0) {
-               if (p[digits] < '0' || p[digits] > '9')
-                       return -1;
-               ret += (p[digits] - '0') * base;
-               base *= 10;
-       }
-       return ret;
-}
-
-static int
-two_to_four_digit_year (int year)
-{
-       time_t now;
-       struct tm tm;
-       int century, current;
-
-       return_val_if_fail (year >= 0 && year <= 99, -1);
-
-       /* Get the current year */
-       now = time (NULL);
-       return_val_if_fail (now >= 0, -1);
-       if (!gmtime_r (&now, &tm))
-               return_val_if_reached (-1);
-
-       current = (tm.tm_year % 100);
-       century = (tm.tm_year + 1900) - current;
-
-       /*
-        * Check if it's within 40 years before the
-        * current date.
-        */
-       if (current < 40) {
-               if (year < current)
-                       return century + year;
-               if (year > 100 - (40 - current))
-                       return (century - 100) + year;
-       } else {
-               if (year < current && year > (current - 40))
-                       return century + year;
-       }
-
-       /*
-        * If it's after then adjust for overflows to
-        * the next century.
-        */
-       if (year < current)
-               return century + 100 + year;
-       else
-               return century + year;
-}
-
-static int
-parse_utc_time (const char *time,
-                size_t n_time,
-                struct tm *when,
-                int *offset)
-{
-       const char *p, *e;
-       int year;
-
-       assert (when != NULL);
-       assert (time != NULL);
-       assert (offset != NULL);
-
-       /* YYMMDDhhmmss.ffff Z | +0000 */
-       if (n_time < 6 || n_time >= 28)
-               return 0;
-
-       /* Reset everything to default legal values */
-       memset (when, 0, sizeof (*when));
-       *offset = 0;
-       when->tm_mday = 1;
-
-       /* Select the digits part of it */
-       p = time;
-       for (e = p; *e >= '0' && *e <= '9'; ++e);
-
-       if (p + 2 <= e) {
-               year = atoin (p, 2);
-               p += 2;
-
-               /*
-                * 40 years in the past is our century. 60 years
-                * in the future is the next century.
-                */
-               when->tm_year = two_to_four_digit_year (year) - 1900;
-       }
-       if (p + 2 <= e) {
-               when->tm_mon = atoin (p, 2) - 1;
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_mday = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_hour = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_min = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_sec = atoin (p, 2);
-               p += 2;
-       }
-
-       if (when->tm_year < 0 || when->tm_year > 9999 ||
-           when->tm_mon < 0 || when->tm_mon > 11 ||
-           when->tm_mday < 1 || when->tm_mday > 31 ||
-           when->tm_hour < 0 || when->tm_hour > 23 ||
-           when->tm_min < 0 || when->tm_min > 59 ||
-           when->tm_sec < 0 || when->tm_sec > 59)
-               return 0;
-
-       /* Make sure all that got parsed */
-       if (p != e)
-               return 0;
-
-       /* Now the remaining optional stuff */
-       e = time + n_time;
-
-       /* See if there's a fraction, and discard it if so */
-       if (p < e && *p == '.' && p + 5 <= e)
-               p += 5;
-
-       /* See if it's UTC */
-       if (p < e && *p == 'Z') {
-               p += 1;
-
-       /* See if it has a timezone */
-       } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
-               int off, neg;
-
-               neg = *p == '-';
-               ++p;
-
-               off = atoin (p, 2) * 3600;
-               if (off < 0 || off > 86400)
-                       return 0;
-               p += 2;
-
-               if (p + 2 <= e) {
-                       off += atoin (p, 2) * 60;
-                       p += 2;
-               }
-
-               /* Use TZ offset */
-               if (neg)
-                       *offset = 0 - off;
-               else
-                       *offset = off;
-       }
-
-       /* Make sure everything got parsed */
-       if (p != e)
-               return 0;
-
-       return 1;
-}
-
-static int
-parse_general_time (const char *time,
-                    size_t n_time,
-                    struct tm *when,
-                    int *offset)
-{
-       const char *p, *e;
-
-       assert (time != NULL);
-       assert (when != NULL);
-       assert (offset != NULL);
-
-       /* YYYYMMDDhhmmss.ffff Z | +0000 */
-       if (n_time < 8 || n_time >= 30)
-               return 0;
-
-       /* Reset everything to default legal values */
-       memset (when, 0, sizeof (*when));
-       *offset = 0;
-       when->tm_mday = 1;
-
-       /* Select the digits part of it */
-       p = time;
-       for (e = p; *e >= '0' && *e <= '9'; ++e);
-
-       if (p + 4 <= e) {
-               when->tm_year = atoin (p, 4) - 1900;
-               p += 4;
-       }
-       if (p + 2 <= e) {
-               when->tm_mon = atoin (p, 2) - 1;
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_mday = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_hour = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_min = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_sec = atoin (p, 2);
-               p += 2;
-       }
-
-       if (when->tm_year < 0 || when->tm_year > 9999 ||
-           when->tm_mon < 0 || when->tm_mon > 11 ||
-           when->tm_mday < 1 || when->tm_mday > 31 ||
-           when->tm_hour < 0 || when->tm_hour > 23 ||
-           when->tm_min < 0 || when->tm_min > 59 ||
-           when->tm_sec < 0 || when->tm_sec > 59)
-               return 0;
-
-       /* Make sure all that got parsed */
-       if (p != e)
-               return 0;
-
-       /* Now the remaining optional stuff */
-       e = time + n_time;
-
-       /* See if there's a fraction, and discard it if so */
-       if (p < e && *p == '.' && p + 5 <= e)
-               p += 5;
-
-       /* See if it's UTC */
-       if (p < e && *p == 'Z') {
-               p += 1;
-
-       /* See if it has a timezone */
-       } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
-               int off, neg;
-
-               neg = *p == '-';
-               ++p;
-
-               off = atoin (p, 2) * 3600;
-               if (off < 0 || off > 86400)
-                       return 0;
-               p += 2;
-
-               if (p + 2 <= e) {
-                       off += atoin (p, 2) * 60;
-                       p += 2;
-               }
-
-               /* Use TZ offset */
-               if (neg)
-                       *offset = 0 - off;
-               else
-                       *offset = off;
-       }
-
-       /* Make sure everything got parsed */
-       if (p != e)
-               return 0;
-
-       return 1;
-}
-
-static time_t
-when_and_offset_to_time_t (struct tm *when,
-                           int tz_offset)
-{
-       time_t timet;
-
-       /* A 32-bit time, cannot represent this time */
-       if (sizeof (time_t) <= 4 && when->tm_year >= 138) {
-               return -1;
-
-       /* Convert to seconds since epoch */
-       } else {
-               timet = timegm (when);
-               return_val_if_fail (timet >= 0, -1);
-               timet += tz_offset;
-       }
-
-       if (!gmtime_r (&timet, when))
-               return_val_if_reached (-1);
-
-       return timet;
-}
-
-time_t
-p11_asn1_parse_utc (const char *time_str,
-                    struct tm *when)
-{
-       struct tm dummy;
-       int tz_offset;
-       int ret;
-
-       if (!when)
-               when = &dummy;
-
-       ret = parse_utc_time (time_str, strlen (time_str),
-                             when, &tz_offset);
-       if (!ret)
-               return -1;
-
-       return when_and_offset_to_time_t (when, tz_offset);
-}
-
-time_t
-p11_asn1_parse_general (const char *time_str,
-                        struct tm *when)
-{
-       struct tm dummy;
-       int tz_offset;
-       int ret;
-
-       if (!when)
-               when = &dummy;
-
-       ret = parse_general_time (time_str, strlen (time_str),
-                                 when, &tz_offset);
-       if (!ret)
-               return -1;
-
-       return when_and_offset_to_time_t (when, tz_offset);
-}
-
 ssize_t
 p11_asn1_tlv_length (const unsigned char *data,
                      size_t length)
index c79e8f6993a864f94c72e93a01112d8d7519ba41..1bd7dd1d774fe7959ed6f410b688eac1f1bee97e 100644 (file)
@@ -55,12 +55,6 @@ node_asn *       p11_asn1_create                    (p11_dict *asn1_defs,
 unsigned char *  p11_asn1_encode                    (node_asn *asn,
                                                      size_t *der_len);
 
-time_t           p11_asn1_parse_utc                 (const char *time_str,
-                                                     struct tm *when);
-
-time_t           p11_asn1_parse_general             (const char *time_str,
-                                                     struct tm *when);
-
 ssize_t          p11_asn1_tlv_length                (const unsigned char *data,
                                                      size_t length);
 
index e41d73f8d0cba2264ee13c96deab7abfd36373af..15999bba5eb45e9b29919a50882c047ce75fd729 100644 (file)
@@ -227,16 +227,72 @@ calc_check_value (const unsigned char *data,
        memcpy (check_value, checksum, 3);
 }
 
+static int
+atoin (const char *p,
+       int digits)
+{
+       int ret = 0, base = 1;
+       while(--digits >= 0) {
+               if (p[digits] < '0' || p[digits] > '9')
+                       return -1;
+               ret += (p[digits] - '0') * base;
+               base *= 10;
+       }
+       return ret;
+}
+
+static int
+century_for_two_digit_year (int year)
+{
+       time_t now;
+       struct tm tm;
+       int century, current;
+
+       return_val_if_fail (year >= 0 && year <= 99, -1);
+
+       /* Get the current year */
+       now = time (NULL);
+       return_val_if_fail (now >= 0, -1);
+       if (!gmtime_r (&now, &tm))
+               return_val_if_reached (-1);
+
+       current = (tm.tm_year % 100);
+       century = (tm.tm_year + 1900) - current;
+
+       /*
+        * Check if it's within 40 years before the
+        * current date.
+        */
+       if (current < 40) {
+               if (year < current)
+                       return century;
+               if (year > 100 - (40 - current))
+                       return century - 100;
+       } else {
+               if (year < current && year > (current - 40))
+                       return century;
+       }
+
+       /*
+        * If it's after then adjust for overflows to
+        * the next century.
+        */
+       if (year < current)
+               return century + 100;
+       else
+               return century;
+}
+
 static bool
 calc_date (node_asn *node,
            const char *field,
            CK_DATE *date)
 {
        node_asn *choice;
-       struct tm when;
        char buf[64];
-       time_t timet;
+       int century;
        char *sub;
+       int year;
        int len;
        int ret;
 
@@ -252,39 +308,43 @@ calc_date (node_asn *node,
 
        sub = strconcat (field, ".", buf, NULL);
 
+       /*
+        * So here we take a shortcut and just copy the date from the
+        * certificate into the CK_DATE. This doesn't take into account
+        * time zones. However the PKCS#11 spec does not say what timezone
+        * the dates are in. In the PKCS#11 value have a day resolution,
+        * and time zones aren't that critical.
+        */
+
        if (strcmp (buf, "generalTime") == 0) {
                len = sizeof (buf) - 1;
                ret = asn1_read_value (node, sub, buf, &len);
                return_val_if_fail (ret == ASN1_SUCCESS, false);
-               timet = p11_asn1_parse_general (buf, &when);
+               return_val_if_fail (len >= 8, false);
+
+               /* Same as first 8 characters of date */
+               memcpy (date, buf, 8);
 
        } else if (strcmp (buf, "utcTime") == 0) {
                len = sizeof (buf) - 1;
                ret = asn1_read_value (node, sub, buf, &len);
                return_val_if_fail (ret == ASN1_SUCCESS, false);
-               timet = p11_asn1_parse_utc (buf, &when);
+               return_val_if_fail (len >= 6, false);
+
+               year = atoin (buf, 2);
+               return_val_if_fail (year > 0, false);
+
+               century = century_for_two_digit_year (year);
+               return_val_if_fail (century >= 0, false);
+
+               snprintf ((char *)date->year, 3, "%02d", century);
+               memcpy (((char *)date) + 2, buf, 6);
 
        } else {
                return_val_if_reached (false);
        }
 
        free (sub);
-
-       if (timet < 0)
-               return false;
-
-       assert (sizeof (date->year) == 4);
-       snprintf ((char *)buf, 5, "%04d", 1900 + when.tm_year);
-       memcpy (date->year, buf, 4);
-
-       assert (sizeof (date->month) == 2);
-       snprintf ((char *)buf, 3, "%02d", when.tm_mon + 1);
-       memcpy (date->month, buf, 2);
-
-       assert (sizeof (date->day) == 2);
-       snprintf ((char *)buf, 3, "%02d", when.tm_mday);
-       memcpy (date->day, buf, 2);
-
        return true;
 }
 
index 7cab1f642716fd274c5a48d08f16ad4e048095ea..a875b960c17b6cdc73c0f0989bf470c88d7fb897 100644 (file)
@@ -552,7 +552,7 @@ test_build_distant_end_date (CuTest *cu)
        };
 
        CK_ATTRIBUTE expected[] = {
-               { CKA_END_DATE, },
+               { CKA_END_DATE, "20671229", 8 },
                { CKA_START_DATE, "20130327", 8 },
                { CKA_INVALID },
        };
@@ -562,18 +562,6 @@ test_build_distant_end_date (CuTest *cu)
 
        setup (cu);
 
-       /*
-        * On a 32-bit system, the end date will be too big to compute with
-        * libc. So it'll be empty, since this is an optional field.
-        */
-       if (sizeof (time_t) <= 4) {
-               expected[0].pValue = "";
-               expected[0].ulValueLen = 0;
-       } else {
-               expected[0].pValue = "20671229";
-               expected[0].ulValueLen = 8;
-       }
-
        attrs = NULL;
        rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
        CuAssertIntEquals (cu, CKR_OK, rv);