diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index d988aab4..f075b66d 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -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 * diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 50593bc6..c09c5ebd 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -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 */ diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 7d8f6670..be344c9c 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -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 );