From 3d0f1cb9fdd630c6c920bc97bf496538717e7705 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Tue, 11 Jul 2017 03:01:24 +0800 Subject: Add asn1_time_to_tm function and check days in month Based on discussion in PR #3566. Reduce duplicated code in original asn1_utctime_to_tm and asn1_generalizedtime_to_tm, and introduce a new internal function asn1_time_to_tm. This function also checks if the days in the input time string is valid or not for the corresponding month. Test cases are also added. Reviewed-by: Andy Polyakov Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/3905) --- crypto/asn1/a_gentm.c | 152 ++------------------------------------------------ 1 file changed, 4 insertions(+), 148 deletions(-) (limited to 'crypto/asn1/a_gentm.c') diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c index 5cfc3ff15e..8b2b66b964 100644 --- a/crypto/asn1/a_gentm.c +++ b/crypto/asn1/a_gentm.c @@ -19,155 +19,11 @@ int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d) { - static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 }; - static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 }; - char *a; - int n, i, l, o, min_l = 13, strict = 0; - + /* wrapper around asn1_time_to_tm */ if (d->type != V_ASN1_GENERALIZEDTIME) - return (0); - l = d->length; - a = (char *)d->data; - o = 0; - /* - * GENERALIZEDTIME is similar to UTCTIME except the year is represented - * as YYYY. This stuff treats everything as a two digit field so make - * first two fields 00 to 99 - */ - - /* - * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280 - * time string format, in which: - * - * 1. "seconds" is a 'MUST' - * 2. "Zulu" timezone is a 'MUST' - * 3. "+|-" is not allowed to indicate a time zone - * 4. fractional seconds are not allowed in GeneralizedTime - */ - - if (d->flags & ASN1_STRING_FLAG_X509_TIME) { - min_l = 15; - strict = 1; - } - - if (l < min_l) - goto err; - for (i = 0; i < 7; i++) { - if (!strict && (i == 6) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) { - i++; - if (tm) - tm->tm_sec = 0; - break; - } - if ((a[o] < '0') || (a[o] > '9')) - goto err; - n = a[o] - '0'; - /* incomplete 2-digital number */ - if (++o == l) - goto err; - - if ((a[o] < '0') || (a[o] > '9')) - goto err; - n = (n * 10) + a[o] - '0'; - /* no more bytes to read, but we haven't seen time-zone yet */ - if (++o == l) - goto err; - - if ((n < min[i]) || (n > max[i])) - goto err; - if (tm) { - switch (i) { - case 0: - tm->tm_year = n * 100 - 1900; - break; - case 1: - tm->tm_year += n; - break; - case 2: - tm->tm_mon = n - 1; - break; - case 3: - tm->tm_mday = n; - break; - case 4: - tm->tm_hour = n; - break; - case 5: - tm->tm_min = n; - break; - case 6: - tm->tm_sec = n; - break; - } - } - } - /* - * Optional fractional seconds: decimal point followed by one or more - * digits. - */ - if (a[o] == '.') { - if (strict) - /* RFC 5280 forbids fractional seconds */ - goto err; - if (++o == l) - goto err; - i = o; - while ((o < l) && (a[o] >= '0') && (a[o] <= '9')) - o++; - /* Must have at least one digit after decimal point */ - if (i == o) - goto err; - /* no more bytes to read, but we haven't seen time-zone yet */ - if (o == l) - goto err; - } - - /* - * 'o' will never point to '\0' at this point, the only chance - * 'o' can point th '\0' is either the subsequent if or the first - * else if is true. - */ - if (a[o] == 'Z') { - o++; - } else if (!strict && ((a[o] == '+') || (a[o] == '-'))) { - int offsign = a[o] == '-' ? 1 : -1, offset = 0; - o++; - /* - * if not equal, no need to do subsequent checks - * since the following for-loop will add 'o' by 4 - * and the final return statement will check if 'l' - * and 'o' are equal. - */ - if (o + 4 != l) - goto err; - for (i = 7; i < 9; i++) { - if ((a[o] < '0') || (a[o] > '9')) - goto err; - n = a[o] - '0'; - o++; - if ((a[o] < '0') || (a[o] > '9')) - goto err; - n = (n * 10) + a[o] - '0'; - if ((n < min[i]) || (n > max[i])) - goto err; - if (tm) { - if (i == 7) - offset = n * 3600; - else if (i == 8) - offset += n * 60; - } - o++; - } - if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign)) - return 0; - } else if (a[o]) { - /* Missing time zone information. */ - goto err; - } - return (o == l); - err: - return (0); -} + return 0; + return asn1_time_to_tm(tm, d); + } int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d) { -- cgit v1.2.3