There are still a couple of minor issues in the X.509 leap year handling:

 (1) To avoid doing a modulus-by-400 in addition to a modulus-by-100 when
     determining whether the year is a leap year or not, I divided the year
     by 100 after doing the modulus-by-100, thereby letting the compiler do
     one instruction for both, and then did a modulus-by-4.

     Unfortunately, I then passed the now-modified year value to mktime64()
     to construct a time value.

     Since this isn't a fast path and since mktime64() does a bunch of
     divisions, just condense down to "% 400".  It's also easier to read.

 (2) The default month length for any February where the year doesn't
     divide by four exactly is obtained from the month_length[] array where
     the value is 29, not 28.

     This is fixed by altering the table.

In addition:

 (3) The format of ASN.1 GeneralizedTime seems to be specified by ISO 8601
     [X.680 46.3] and this apparently supports leap seconds (ie. the
     seconds field is 60).  It's not entirely clear that ASN.1 expects it,
     but we can relax the seconds check slightly for GeneralizedTime.

     UTCTime, however, only supports a seconds value in the range 00-59.

Reported-by: Rudolf Polzer <[email protected]>
Signed-off-by: David Howells <[email protected]>
---
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c 
b/crypto/asymmetric_keys/x509_cert_parser.c
index 021d39c0ba75..f57c3c1b5ae7 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -494,10 +494,10 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                     unsigned char tag,
                     const unsigned char *value, size_t vlen)
 {
-       static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30,
+       static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
                                                       31, 31, 30, 31, 30, 31 };
        const unsigned char *p = value;
-       unsigned year, mon, day, hour, min, sec, mon_len;
+       unsigned year, mon, day, hour, min, sec, mon_len, sec_len;
 
 #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto 
invalid_time; x; })
 #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; 
x; })
@@ -511,6 +511,7 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                        year += 1900;
                else
                        year += 2000;
+               max_sec = 59;
        } else if (tag == ASN1_GENTIM) {
                /* GenTime: YYYYMMDDHHMMSSZ */
                if (vlen != 15)
@@ -518,6 +519,7 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                year = DD2bin(p) * 100 + DD2bin(p);
                if (year >= 1950 && year <= 2049)
                        goto invalid_time;
+               max_sec = 60; /* ISO 8601 permits leap seconds [X.680 46.3] */
        } else {
                goto unsupported_time;
        }
@@ -540,9 +542,9 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                if (year % 4 == 0) {
                        mon_len = 29;
                        if (year % 100 == 0) {
-                               year /= 100;
-                               if (year % 4 != 0)
-                                       mon_len = 28;
+                               mon_len = 28;
+                               if (year % 400 == 0)
+                                       mon_len = 29;
                        }
                }
        }
@@ -550,7 +552,7 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
        if (day < 1 || day > mon_len ||
            hour > 23 ||
            min > 59 ||
-           sec > 59)
+           sec > max_sec)
                goto invalid_time;
 
        *_t = mktime64(year, mon, day, hour, min, sec);
--
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to