diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index 47c735c5..9b3864ed 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -62,6 +62,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM ) #define EINFO_EINVAL_ASN1_ALGORITHM \ __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" ) +#define EINVAL_BIT_STRING \ + __einfo_error ( EINFO_EINVAL_BIT_STRING ) +#define EINFO_EINVAL_BIT_STRING \ + __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" ) #define ENOTSUP_ALGORITHM \ __einfo_error ( EINFO_ENOTSUP_ALGORITHM ) #define EINFO_ENOTSUP_ALGORITHM \ @@ -295,7 +299,9 @@ int asn1_shrink_any ( struct asn1_cursor *cursor ) { */ int asn1_boolean ( const struct asn1_cursor *cursor ) { struct asn1_cursor contents; - const struct asn1_boolean *boolean; + const struct { + uint8_t value; + } __attribute__ (( packed )) *boolean; /* Enter boolean */ memcpy ( &contents, cursor, sizeof ( contents ) ); @@ -347,6 +353,87 @@ int asn1_integer ( const struct asn1_cursor *cursor, int *value ) { return 0; } +/** + * Parse ASN.1 bit string + * + * @v cursor ASN.1 cursor + * @v bits Bit string to fill in + * @ret rc Return status code + */ +int asn1_bit_string ( const struct asn1_cursor *cursor, + struct asn1_bit_string *bits ) { + struct asn1_cursor contents; + const struct { + uint8_t unused; + uint8_t data[0]; + } __attribute__ (( packed )) *bit_string; + size_t len; + unsigned int unused; + uint8_t unused_mask; + const uint8_t *last; + int rc; + + /* Enter bit string */ + memcpy ( &contents, cursor, sizeof ( contents ) ); + if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) { + DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return rc; + } + + /* Validity checks */ + if ( contents.len < sizeof ( *bit_string ) ) { + DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return -EINVAL_BIT_STRING; + } + bit_string = contents.data; + len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) ); + unused = bit_string->unused; + unused_mask = ( 0xff >> ( 8 - unused ) ); + last = ( bit_string->data + len - 1 ); + if ( ( unused >= 8 ) || + ( ( unused > 0 ) && ( len == 0 ) ) || + ( ( *last & unused_mask ) != 0 ) ) { + DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return -EINVAL_BIT_STRING; + } + + /* Populate bit string */ + bits->data = &bit_string->data; + bits->len = len; + bits->unused = unused; + + return 0; +} + +/** + * Parse ASN.1 bit string that must be an integral number of bytes + * + * @v cursor ASN.1 cursor + * @v bits Bit string to fill in + * @ret rc Return status code + */ +int asn1_integral_bit_string ( const struct asn1_cursor *cursor, + struct asn1_bit_string *bits ) { + int rc; + + /* Parse bit string */ + if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 ) + return rc; + + /* Check that there are no unused bits at end of string */ + if ( bits->unused ) { + DBGC ( cursor, "ASN1 %p invalid integral bit string:\n", + cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return -EINVAL_BIT_STRING; + } + + return 0; +} + /** * Compare two ASN.1 objects * diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index be2696ba..563d6b9b 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -241,7 +241,7 @@ static int rsa_parse_integer ( struct rsa_context *context, */ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { struct rsa_context *context = ctx; - const struct asn1_bit_string *bit_string; + struct asn1_bit_string bits; struct asn1_cursor modulus; struct asn1_cursor exponent; struct asn1_cursor cursor; @@ -274,17 +274,10 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { asn1_skip ( &cursor, ASN1_SEQUENCE ); /* Enter subjectPublicKey */ - asn1_enter ( &cursor, ASN1_BIT_STRING ); - - /* Check and skip unused-bits byte of bit string */ - bit_string = cursor.data; - if ( ( cursor.len < sizeof ( *bit_string ) ) || - ( bit_string->unused != 0 ) ) { - rc = -EINVAL; + if ( ( rc = asn1_integral_bit_string ( &cursor, &bits ) ) != 0 ) goto err_parse; - } - cursor.data = &bit_string->data; - cursor.len -= offsetof ( typeof ( *bit_string ), data ); + cursor.data = bits.data; + cursor.len = bits.len; /* Enter RSAPublicKey */ asn1_enter ( &cursor, ASN1_SEQUENCE ); diff --git a/src/crypto/x509.c b/src/crypto/x509.c index f25424a1..dc8745dc 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -54,10 +54,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EINVAL_ALGORITHM ) #define EINFO_EINVAL_ALGORITHM \ __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid algorithm type" ) -#define EINVAL_BIT_STRING \ - __einfo_error ( EINFO_EINVAL_BIT_STRING ) -#define EINFO_EINVAL_BIT_STRING \ - __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid bit string" ) #define EINVAL_ALGORITHM_MISMATCH \ __einfo_error ( EINFO_EINVAL_ALGORITHM_MISMATCH ) #define EINFO_EINVAL_ALGORITHM_MISMATCH \ @@ -154,88 +150,6 @@ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; static struct asn1_cursor oid_common_name_cursor = ASN1_OID_CURSOR ( oid_common_name ); -/** - * Parse X.509 certificate bit string - * - * @v cert X.509 certificate - * @v bits Bit string to fill in - * @v raw ASN.1 cursor - * @ret rc Return status code - */ -static int x509_parse_bit_string ( struct x509_certificate *cert, - struct x509_bit_string *bits, - const struct asn1_cursor *raw ) { - struct asn1_cursor cursor; - const struct asn1_bit_string *bit_string; - size_t len; - unsigned int unused; - uint8_t unused_mask; - const uint8_t *last; - int rc; - - /* Enter bit string */ - memcpy ( &cursor, raw, sizeof ( cursor ) ); - if ( ( rc = asn1_enter ( &cursor, ASN1_BIT_STRING ) ) != 0 ) { - DBGC ( cert, "X509 %p cannot locate bit string:\n", cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return rc; - } - - /* Validity checks */ - if ( cursor.len < sizeof ( *bit_string ) ) { - DBGC ( cert, "X509 %p invalid bit string:\n", cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return -EINVAL_BIT_STRING; - } - bit_string = cursor.data; - len = ( cursor.len - offsetof ( typeof ( *bit_string ), data ) ); - unused = bit_string->unused; - unused_mask = ( 0xff >> ( 8 - unused ) ); - last = ( bit_string->data + len - 1 ); - if ( ( unused >= 8 ) || - ( ( unused > 0 ) && ( len == 0 ) ) || - ( ( *last & unused_mask ) != 0 ) ) { - DBGC ( cert, "X509 %p invalid bit string:\n", cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return -EINVAL_BIT_STRING; - } - - /* Populate bit string */ - bits->data = &bit_string->data; - bits->len = len; - bits->unused = unused; - - return 0; -} - -/** - * Parse X.509 certificate bit string that must be an integral number of bytes - * - * @v cert X.509 certificate - * @v bits Bit string to fill in - * @v raw ASN.1 cursor - * @ret rc Return status code - */ -static int x509_parse_integral_bit_string ( struct x509_certificate *cert, - struct x509_bit_string *bits, - const struct asn1_cursor *raw ) { - int rc; - - /* Parse bit string */ - if ( ( rc = x509_parse_bit_string ( cert, bits, raw ) ) != 0 ) - return rc; - - /* Check that there are no unused bits at end of string */ - if ( bits->unused ) { - DBGC ( cert, "X509 %p invalid integral bit string:\n", cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return -EINVAL_BIT_STRING; - } - - return 0; -} - - /** * Parse X.509 certificate version * @@ -466,7 +380,7 @@ static int x509_parse_public_key ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_public_key *public_key = &cert->subject.public_key; struct asn1_algorithm **algorithm = &public_key->algorithm; - struct x509_bit_string *raw_bits = &public_key->raw_bits; + struct asn1_bit_string *raw_bits = &public_key->raw_bits; struct asn1_cursor cursor; int rc; @@ -491,8 +405,11 @@ static int x509_parse_public_key ( struct x509_certificate *cert, asn1_skip_any ( &cursor ); /* Parse bit string */ - if ( ( rc = x509_parse_bit_string ( cert, raw_bits, &cursor ) ) != 0 ) + if ( ( rc = asn1_bit_string ( &cursor, raw_bits ) ) != 0 ) { + DBGC ( cert, "X509 %p could not parse public key bits: %s\n", + cert, strerror ( rc ) ); return rc; + } return 0; } @@ -569,7 +486,7 @@ static int x509_parse_basic_constraints ( struct x509_certificate *cert, static int x509_parse_key_usage ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_key_usage *usage = &cert->extensions.usage; - struct x509_bit_string bit_string; + struct asn1_bit_string bit_string; const uint8_t *bytes; size_t len; unsigned int i; @@ -579,8 +496,11 @@ static int x509_parse_key_usage ( struct x509_certificate *cert, usage->present = 1; /* Parse bit string */ - if ( ( rc = x509_parse_bit_string ( cert, &bit_string, raw ) ) != 0 ) + if ( ( rc = asn1_bit_string ( raw, &bit_string ) ) != 0 ) { + DBGC ( cert, "X509 %p could not parse key usage: %s\n", + cert, strerror ( rc ) ); return rc; + } /* Parse key usage bits */ bytes = bit_string.data; @@ -1034,7 +954,7 @@ static int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_signature *signature = &cert->signature; struct asn1_algorithm **signature_algorithm = &signature->algorithm; - struct x509_bit_string *signature_value = &signature->value; + struct asn1_bit_string *signature_value = &signature->value; struct asn1_cursor cursor; int rc; @@ -1062,9 +982,12 @@ static int x509_parse ( struct x509_certificate *cert, asn1_skip_any ( &cursor ); /* Parse signatureValue */ - if ( ( rc = x509_parse_integral_bit_string ( cert, signature_value, - &cursor ) ) != 0 ) + if ( ( rc = asn1_integral_bit_string ( &cursor, + signature_value ) ) != 0 ) { + DBGC ( cert, "X509 %p could not parse signature value: %s\n", + cert, strerror ( rc ) ); return rc; + } DBGC2 ( cert, "X509 %p signatureValue is:\n", cert ); DBGC2_HDA ( cert, 0, signature_value->data, signature_value->len ); diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index cd0d5342..222e32ec 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -200,18 +200,14 @@ struct asn1_algorithm { /** Declare an ASN.1 OID-identified algorithm */ #define __asn1_algorithm __table_entry ( ASN1_ALGORITHMS, 01 ) -/** 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 */ - uint8_t unused; /** Data */ - uint8_t data[0]; + const void *data; + /** Length */ + size_t len; + /** Unused bits at end of data */ + unsigned int unused; } __attribute__ (( packed )); /** @@ -236,6 +232,10 @@ 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_bit_string ( const struct asn1_cursor *cursor, + struct asn1_bit_string *bits ); +extern int asn1_integral_bit_string ( const struct asn1_cursor *cursor, + struct asn1_bit_string *bits ); extern int asn1_compare ( const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2 ); extern int asn1_algorithm ( const struct asn1_cursor *cursor, diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index a55511b8..8b1dda25 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -16,16 +16,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** An X.509 bit string */ -struct x509_bit_string { - /** Data */ - const void *data; - /** Length */ - size_t len; - /** Unused bits at end of data */ - unsigned int unused; -}; - /** An X.509 serial number */ struct x509_serial { /** Raw serial number */ @@ -59,7 +49,7 @@ struct x509_public_key { /** Public key algorithm */ struct asn1_algorithm *algorithm; /** Raw public key bit string */ - struct x509_bit_string raw_bits; + struct asn1_bit_string raw_bits; }; /** An X.509 certificate subject */ @@ -77,7 +67,7 @@ struct x509_signature { /** Signature algorithm */ struct asn1_algorithm *algorithm; /** Signature value */ - struct x509_bit_string value; + struct asn1_bit_string value; }; /** An X.509 certificate basic constraints set */