]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Generalise x509_parse_time() to asn1_generalized_time()
authorMichael Brown <mcb30@ipxe.org>
Sun, 13 May 2012 22:38:56 +0000 (23:38 +0100)
committerMichael Brown <mcb30@ipxe.org>
Sun, 13 May 2012 23:20:25 +0000 (00:20 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/asn1.c
src/crypto/x509.c
src/include/ipxe/asn1.h

index 2eab34223c03b6d4813306e98eb8004197f0b734..55860558d10debac6752db07c29c12f3579a45f3 100644 (file)
@@ -21,7 +21,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdint.h>
 #include <stddef.h>
 #include <string.h>
+#include <ctype.h>
 #include <errno.h>
+#include <time.h>
 #include <ipxe/tables.h>
 #include <ipxe/asn1.h>
 
@@ -52,6 +54,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
        __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
 #define EINFO_EINVAL_ASN1_INTEGER \
        __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
+#define EINVAL_ASN1_TIME \
+       __einfo_error ( EINFO_EINVAL_ASN1_TIME )
+#define EINFO_EINVAL_ASN1_TIME \
+       __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
 
 /**
  * Invalidate ASN.1 object cursor
@@ -400,3 +406,110 @@ struct asn1_algorithm * asn1_algorithm ( const struct asn1_cursor *cursor ) {
 
        return algorithm;
 }
+
+/**
+ * Parse ASN.1 GeneralizedTime
+ *
+ * @v cursor           ASN.1 cursor
+ * @v time             Time to fill in
+ * @ret rc             Return status code
+ *
+ * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
+ * formats for UTCTime and GeneralizedTime, and mandates the
+ * interpretation of centuryless year values.
+ */
+int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
+       struct asn1_cursor contents;
+       unsigned int have_century;
+       unsigned int type;
+       union {
+               struct {
+                       uint8_t century;
+                       uint8_t year;
+                       uint8_t month;
+                       uint8_t day;
+                       uint8_t hour;
+                       uint8_t minute;
+                       uint8_t second;
+               } __attribute__ (( packed )) named;
+               uint8_t raw[7];
+       } pairs;
+       struct tm tm;
+       const uint8_t *data;
+       size_t remaining;
+       unsigned int tens;
+       unsigned int units;
+       unsigned int i;
+       int rc;
+
+       /* Determine time format utcTime/generalizedTime */
+       memcpy ( &contents, cursor, sizeof ( contents ) );
+       type = asn1_type ( &contents );
+       switch ( type ) {
+       case ASN1_UTC_TIME:
+               have_century = 0;
+               break;
+       case ASN1_GENERALIZED_TIME:
+               have_century = 1;
+               break;
+       default:
+               DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
+                      cursor, type );
+               DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+               return -EINVAL_ASN1_TIME;
+       }
+
+       /* Enter utcTime/generalizedTime */
+       if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
+               DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
+                      ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
+               DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+               return rc;
+       }
+
+       /* Parse digit string a pair at a time */
+       data = contents.data;
+       remaining = contents.len;
+       for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
+               if ( remaining < 2 ) {
+                       DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+                       DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+                       return -EINVAL_ASN1_TIME;
+               }
+               tens = data[0];
+               units = data[1];
+               if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
+                       DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+                       DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+                       return -EINVAL_ASN1_TIME;
+               }
+               pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
+               data += 2;
+               remaining -= 2;
+       }
+
+       /* Determine century if applicable */
+       if ( ! have_century )
+               pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
+
+       /* Check for trailing "Z" */
+       if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
+               DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+               DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+               return -EINVAL_ASN1_TIME;
+       }
+
+       /* Fill in time */
+       tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
+                      pairs.named.year );
+       tm.tm_mon = ( pairs.named.month - 1 );
+       tm.tm_mday = pairs.named.day;
+       tm.tm_hour = pairs.named.hour;
+       tm.tm_min = pairs.named.minute;
+       tm.tm_sec = pairs.named.second;
+
+       /* Convert to seconds since the Epoch */
+       *time = mktime ( &tm );
+
+       return 0;
+}
index cfecfde35181c27d9fce5c37f294c54d890aa6e2..1cb46a1de9a59d27f25b4b3c2ef2bdbc4e0648cd 100644 (file)
@@ -20,8 +20,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
-#include <time.h>
 #include <errno.h>
 #include <assert.h>
 #include <ipxe/list.h>
@@ -60,10 +58,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
        __einfo_error ( EINFO_EINVAL_BIT_STRING )
 #define EINFO_EINVAL_BIT_STRING \
        __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid bit string" )
-#define EINVAL_TIME \
-       __einfo_error ( EINFO_EINVAL_TIME )
-#define EINFO_EINVAL_TIME \
-       __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid time" )
 #define EINVAL_ALGORITHM_MISMATCH \
        __einfo_error ( EINFO_EINVAL_ALGORITHM_MISMATCH )
 #define EINFO_EINVAL_ALGORITHM_MISMATCH \
@@ -301,114 +295,6 @@ static int x509_parse_integral_bit_string ( struct x509_certificate *cert,
        return 0;
 }
 
-/**
- * Parse X.509 certificate time
- *
- * @v cert             X.509 certificate
- * @v time             Time to fill in
- * @v raw              ASN.1 cursor
- * @ret rc             Return status code
- *
- * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
- * formats for UTCTime and GeneralizedTime, and mandates the
- * interpretation of centuryless year values.
- */
-static int x509_parse_time ( struct x509_certificate *cert,
-                            struct x509_time *time,
-                            const struct asn1_cursor *raw ) {
-       struct asn1_cursor cursor;
-       unsigned int have_century;
-       unsigned int type;
-       union {
-               struct {
-                       uint8_t century;
-                       uint8_t year;
-                       uint8_t month;
-                       uint8_t day;
-                       uint8_t hour;
-                       uint8_t minute;
-                       uint8_t second;
-               } __attribute__ (( packed )) named;
-               uint8_t raw[7];
-       } pairs;
-       struct tm tm;
-       const uint8_t *data;
-       size_t remaining;
-       unsigned int tens;
-       unsigned int units;
-       unsigned int i;
-       int rc;
-
-       /* Determine time format utcTime/generalizedTime */
-       memcpy ( &cursor, raw, sizeof ( cursor ) );
-       type = asn1_type ( &cursor );
-       switch ( type ) {
-       case ASN1_UTC_TIME:
-               have_century = 0;
-               break;
-       case ASN1_GENERALIZED_TIME:
-               have_century = 1;
-               break;
-       default:
-               DBGC ( cert, "X509 %p invalid time type %02x\n", cert, type );
-               DBGC_HDA ( cert, 0, raw->data, raw->len );
-               return -EINVAL_TIME;
-       }
-
-       /* Enter utcTime/generalizedTime */
-       if ( ( rc = asn1_enter ( &cursor, type ) ) != 0 ) {
-               DBGC ( cert, "X509 %p cannot locate %s time:\n", cert,
-                      ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
-               DBGC_HDA ( cert, 0, raw->data, raw->len );
-               return rc;
-       }
-
-       /* Parse digit string a pair at a time */
-       data = cursor.data;
-       remaining = cursor.len;
-       for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
-               if ( remaining < 2 ) {
-                       DBGC ( cert, "X509 %p invalid time:\n", cert );
-                       DBGC_HDA ( cert, 0, raw->data, raw->len );
-                       return -EINVAL_TIME;
-               }
-               tens = data[0];
-               units = data[1];
-               if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
-                       DBGC ( cert, "X509 %p invalid time:\n", cert );
-                       DBGC_HDA ( cert, 0, raw->data, raw->len );
-                       return -EINVAL_TIME;
-               }
-               pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
-               data += 2;
-               remaining -= 2;
-       }
-
-       /* Determine century if applicable */
-       if ( ! have_century )
-               pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
-
-       /* Check for trailing "Z" */
-       if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
-               DBGC ( cert, "X509 %p invalid time:\n", cert );
-               DBGC_HDA ( cert, 0, raw->data, raw->len );
-               return -EINVAL_TIME;
-       }
-
-       /* Fill in time */
-       tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
-                      pairs.named.year );
-       tm.tm_mon = ( pairs.named.month - 1 );
-       tm.tm_mday = pairs.named.day;
-       tm.tm_hour = pairs.named.hour;
-       tm.tm_min = pairs.named.minute;
-       tm.tm_sec = pairs.named.second;
-
-       /* Convert to seconds since the Epoch */
-       time->time = mktime ( &tm );
-
-       return 0;
-}
 
 /**
  * Parse X.509 certificate version
@@ -520,15 +406,23 @@ static int x509_parse_validity ( struct x509_certificate *cert,
        asn1_enter ( &cursor, ASN1_SEQUENCE );
 
        /* Parse notBefore */
-       if ( ( rc = x509_parse_time ( cert, not_before, &cursor ) ) != 0 )
+       if ( ( rc = asn1_generalized_time ( &cursor,
+                                           &not_before->time ) ) != 0 ) {
+               DBGC ( cert, "X509 %p cannot parse notBefore: %s\n",
+                      cert, strerror ( rc ) );
                return rc;
+       }
        DBGC2 ( cert, "X509 %p valid from time %lld\n",
                cert, not_before->time );
        asn1_skip_any ( &cursor );
 
        /* Parse notAfter */
-       if ( ( rc = x509_parse_time ( cert, not_after, &cursor ) ) != 0 )
+       if ( ( rc = asn1_generalized_time ( &cursor,
+                                           &not_after->time ) ) != 0 ) {
+               DBGC ( cert, "X509 %p cannot parse notAfter: %s\n",
+                      cert, strerror ( rc ) );
                return rc;
+       }
        DBGC2 ( cert, "X509 %p valid until time %lld\n",
                cert, not_after->time );
 
index 1c433c5e7321240e02d87555957f2e0bd5192504..38f0e5b015c7e04af3c6a19cfeb95233dd7d3bde 100644 (file)
@@ -10,6 +10,7 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <time.h>
 #include <ipxe/tables.h>
 
 /** An ASN.1 object cursor */
@@ -239,5 +240,7 @@ extern int asn1_compare ( const struct asn1_cursor *cursor1,
                          const struct asn1_cursor *cursor2 );
 extern struct asn1_algorithm *
 asn1_algorithm ( const struct asn1_cursor *cursor );
+extern int asn1_generalized_time ( const struct asn1_cursor *cursor,
+                                  time_t *time );
 
 #endif /* _IPXE_ASN1_H */