]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add more ASN.1 functions for X.509 certificate parsing
authorMichael Brown <mcb30@ipxe.org>
Sun, 18 Mar 2012 13:24:20 +0000 (13:24 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 18 Mar 2012 13:34:47 +0000 (13:34 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/asn1.c
src/crypto/x509.c
src/include/ipxe/asn1.h

index d988aab4b0b0fdec9ec5f842e0caa27f027f93a2..f075b66ddd2019dd32018466c7ca929ce10fbc8e 100644 (file)
@@ -43,6 +43,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
        __einfo_error ( EINFO_EINVAL_ASN1_LEN )
 #define EINFO_EINVAL_ASN1_LEN \
        __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
+#define EINVAL_ASN1_BOOLEAN \
+       __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
+#define EINFO_EINVAL_ASN1_BOOLEAN \
+       __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
+#define EINVAL_ASN1_INTEGER \
+       __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
+#define EINFO_EINVAL_ASN1_INTEGER \
+       __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
 
 /**
  * Invalidate ASN.1 object cursor
@@ -191,7 +199,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
        int rc;
 
-       if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
+       if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
                asn1_invalidate_cursor ( cursor );
                return rc;
        }
@@ -199,6 +207,32 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
        return 0;
 }
 
+/**
+ * Shrink ASN.1 cursor to fit object
+ *
+ * @v cursor           ASN.1 object cursor
+ * @v type             Expected type, or ASN1_ANY
+ * @ret rc             Return status code
+ *
+ * The object cursor will be shrunk to contain only the current ASN.1
+ * object.  If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
+       struct asn1_cursor next;
+       int rc;
+
+       /* Skip to next object */
+       memcpy ( &next, cursor, sizeof ( next ) );
+       if ( ( rc = asn1_skip ( &next, type ) ) != 0 )
+               return rc;
+
+       /* Shrink original cursor to contain only its first object */
+       cursor->len = ( next.data - cursor->data );
+
+       return 0;
+}
+
 /**
  * Enter ASN.1 object of any type
  *
@@ -219,6 +253,76 @@ int asn1_skip_any ( struct asn1_cursor *cursor ) {
        return asn1_skip ( cursor, ASN1_ANY );
 }
 
+/**
+ * Shrink ASN.1 object of any type
+ *
+ * @v cursor           ASN.1 object cursor
+ * @ret rc             Return status code
+ */
+int asn1_shrink_any ( struct asn1_cursor *cursor ) {
+       return asn1_shrink ( cursor, ASN1_ANY );
+}
+
+/**
+ * Parse value of ASN.1 boolean
+ *
+ * @v cursor           ASN.1 object cursor
+ * @ret value          Value, or negative error
+ */
+int asn1_boolean ( const struct asn1_cursor *cursor ) {
+       struct asn1_cursor contents;
+       const struct asn1_boolean *boolean;
+
+       /* Enter boolean */
+       memcpy ( &contents, cursor, sizeof ( contents ) );
+       asn1_enter ( &contents, ASN1_BOOLEAN );
+       if ( contents.len != sizeof ( *boolean ) )
+               return -EINVAL_ASN1_BOOLEAN;
+
+       /* Extract value */
+       boolean = contents.data;
+       return boolean->value;
+}
+
+/**
+ * Parse value of ASN.1 integer
+ *
+ * @v cursor           ASN.1 object cursor
+ * @v value            Value to fill in
+ * @ret rc             Return status code
+ */
+int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
+       struct asn1_cursor contents;
+       uint8_t high_byte;
+       int rc;
+
+       /* Enter integer */
+       memcpy ( &contents, cursor, sizeof ( contents ) );
+       if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
+               return rc;
+       if ( contents.len < 1 )
+               return -EINVAL_ASN1_INTEGER;
+
+       /* Initialise value according to sign byte */
+       *value = *( ( int8_t * ) contents.data );
+       contents.data++;
+       contents.len--;
+
+       /* Process value */
+       while ( contents.len ) {
+               high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
+               if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
+                       DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
+                       return -EINVAL_ASN1_INTEGER;
+               }
+               *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
+               contents.data++;
+               contents.len--;
+       }
+
+       return 0;
+}
+
 /**
  * Compare two ASN.1 objects
  *
index 50593bc6dbe9371f6c538b98c59f173de0272c36..c09c5ebd5267aa887508625f341181f7ee6d318f 100644 (file)
@@ -55,7 +55,7 @@ static int x509_public_key ( const struct asn1_cursor *certificate,
        memcpy ( &cursor, certificate, sizeof ( cursor ) );
        rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
               asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
-              asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
+              asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
               asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
               asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
               asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
index 7d8f667046ad6196532e65287df58ac1033d5a6a..be344c9cbf26f4295fb3577cbb7d9f77aba045f1 100644 (file)
@@ -20,6 +20,9 @@ struct asn1_cursor {
 /** ASN.1 end */
 #define ASN1_END 0x00
 
+/** ASN.1 boolean */
+#define ASN1_BOOLEAN 0x01
+
 /** ASN.1 integer */
 #define ASN1_INTEGER 0x02
 
@@ -48,7 +51,7 @@ struct asn1_cursor {
 #define ASN1_SET 0x31
 
 /** ASN.1 explicit tag */
-#define ASN1_EXPLICIT_TAG 0xa0
+#define ASN1_EXPLICIT_TAG( number) ( 0xa0 | (number) )
 
 /** ASN.1 "any tag" magic value */
 #define ASN1_ANY -1U
@@ -79,15 +82,14 @@ struct asn1_cursor {
 /** ASN.1 OID for iso(1) member-body(2) */
 #define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 )
 
+/** ASN.1 OID for iso(1) identified-organization(3) */
+#define ASN1_OID_IDENTIFIED_ORGANIZATION ASN1_OID_INITIAL ( 1, 3 )
+
 /** ASN.1 OID for joint-iso-itu-t(2) ds(5) */
 #define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 )
 
-/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */
-#define ASN1_OID_ATTRIBUTE_TYPE \
-       ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 )
-
-/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */
-#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 )
+/** ASN.1 OID for joint-iso-itu-t(2) country(16) */
+#define ASN1_OID_COUNTRY ASN1_OID_INITIAL ( 2, 16 )
 
 /** Define an ASN.1 cursor containing an OID */
 #define ASN1_OID_CURSOR( oid_value ) {                 \
@@ -95,6 +97,12 @@ struct asn1_cursor {
                .len = sizeof ( oid_value ),            \
        }
 
+/** An ASN.1 boolean */
+struct asn1_boolean {
+       /** Value */
+       uint8_t value;
+} __attribute__ (( packed ));
+
 /** An ASN.1 bit string */
 struct asn1_bit_string {
        /** Number of unused bits */
@@ -119,8 +127,12 @@ extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
 extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
                                 unsigned int type );
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type );
 extern int asn1_enter_any ( struct asn1_cursor *cursor );
 extern int asn1_skip_any ( struct asn1_cursor *cursor );
+extern int asn1_shrink_any ( struct asn1_cursor *cursor );
+extern int asn1_boolean ( const struct asn1_cursor *cursor );
+extern int asn1_integer ( const struct asn1_cursor *cursor, int *value );
 extern int asn1_compare ( const struct asn1_cursor *cursor1,
                          const struct asn1_cursor *cursor2 );