diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 7c6aab5c..a0ed816d 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -487,7 +487,7 @@ static int x509_parse_validity ( struct x509_certificate *cert, * @ret rc Return status code */ static int x509_parse_common_name ( struct x509_certificate *cert, - struct x509_name *name, + struct x509_string *name, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_cursor oid_cursor; @@ -533,7 +533,7 @@ static int x509_parse_common_name ( struct x509_certificate *cert, static int x509_parse_subject ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_subject *subject = &cert->subject; - struct x509_name *name = &subject->name; + struct x509_string *name = &subject->name; int rc; /* Record raw subject */ @@ -750,7 +750,7 @@ static int x509_parse_extended_key_usage ( struct x509_certificate *cert, memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); - /* Parse each extension in turn */ + /* Parse each extended key usage in turn */ while ( cursor.len ) { if ( ( rc = x509_parse_key_purpose ( cert, &cursor ) ) != 0 ) return rc; @@ -760,14 +760,145 @@ static int x509_parse_extended_key_usage ( struct x509_certificate *cert, return 0; } +/** + * Parse X.509 certificate OCSP access method + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_ocsp ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_ocsp_responder *ocsp = &cert->extensions.auth_info.ocsp; + struct asn1_cursor cursor; + int rc; + + /* Enter accessLocation */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter ( &cursor, ASN1_IMPLICIT_TAG ( 6 ) ) ) != 0 ) { + DBGC ( cert, "X509 %p OCSP does not contain " + "uniformResourceIdentifier:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Record URI */ + ocsp->uri.data = cursor.data; + ocsp->uri.len = cursor.len; + DBGC ( cert, "X509 %p OCSP URI is:\n", cert ); + DBGC_HDA ( cert, 0, ocsp->uri.data, ocsp->uri.len ); + + return 0; +} + +/** "id-ad-ocsp" object identifier */ +static uint8_t oid_ad_ocsp[] = { ASN1_OID_OCSP }; + +/** Supported access methods */ +static struct x509_access_method x509_access_methods[] = { + { + .name = "OCSP", + .oid = ASN1_OID_CURSOR ( oid_ad_ocsp ), + .parse = x509_parse_ocsp, + }, +}; + +/** + * Identify X.509 access method by OID + * + * @v oid OID + * @ret method Access method, or NULL + */ +static struct x509_access_method * +x509_find_access_method ( const struct asn1_cursor *oid ) { + struct x509_access_method *method; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( x509_access_methods ) / + sizeof ( x509_access_methods[0] ) ) ; i++ ) { + method = &x509_access_methods[i]; + if ( asn1_compare ( &method->oid, oid ) == 0 ) + return method; + } + + return NULL; +} + +/** + * Parse X.509 certificate access description + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_access_description ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + struct asn1_cursor subcursor; + struct x509_access_method *method; + int rc; + + /* Enter keyPurposeId */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Try to identify access method */ + memcpy ( &subcursor, &cursor, sizeof ( subcursor ) ); + asn1_enter ( &subcursor, ASN1_OID ); + method = x509_find_access_method ( &subcursor ); + asn1_skip_any ( &cursor ); + DBGC ( cert, "X509 %p found access method %s\n", + cert, ( method ? method->name : "" ) ); + + /* Parse access location, if applicable */ + if ( method && ( ( rc = method->parse ( cert, &cursor ) ) != 0 ) ) + return rc; + + return 0; +} + +/** + * Parse X.509 certificate authority information access + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_authority_info_access ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter authorityInfoAccess */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse each access description in turn */ + while ( cursor.len ) { + if ( ( rc = x509_parse_access_description ( cert, + &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + return 0; +} + /** "id-ce-basicConstraints" object identifier */ -static uint8_t oid_ce_basic_constraints[] = { ASN1_OID_BASICCONSTRAINTS }; +static uint8_t oid_ce_basic_constraints[] = + { ASN1_OID_BASICCONSTRAINTS }; /** "id-ce-keyUsage" object identifier */ -static uint8_t oid_ce_key_usage[] = { ASN1_OID_KEYUSAGE }; +static uint8_t oid_ce_key_usage[] = + { ASN1_OID_KEYUSAGE }; /** "id-ce-extKeyUsage" object identifier */ -static uint8_t oid_ce_ext_key_usage[] = { ASN1_OID_EXTKEYUSAGE }; +static uint8_t oid_ce_ext_key_usage[] = + { ASN1_OID_EXTKEYUSAGE }; + +/** "id-pe-authorityInfoAccess" object identifier */ +static uint8_t oid_pe_authority_info_access[] = + { ASN1_OID_AUTHORITYINFOACCESS }; /** Supported certificate extensions */ static struct x509_extension x509_extensions[] = { @@ -786,6 +917,11 @@ static struct x509_extension x509_extensions[] = { .oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ), .parse = x509_parse_extended_key_usage, }, + { + .name = "authorityInfoAccess", + .oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ), + .parse = x509_parse_authority_info_access, + }, }; /** diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index d83308a2..1c433c5e 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -53,6 +53,9 @@ struct asn1_cursor { /** ASN.1 set */ #define ASN1_SET 0x31 +/** ASN.1 implicit tag */ +#define ASN1_IMPLICIT_TAG( number) ( 0x80 | (number) ) + /** ASN.1 explicit tag */ #define ASN1_EXPLICIT_TAG( number) ( 0xa0 | (number) ) @@ -158,6 +161,20 @@ struct asn1_cursor { ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 2 ) +/** ASN.1 OID for id-pe-authorityInfoAccess (1.3.6.1.5.5.7.1.1) */ +#define ASN1_OID_AUTHORITYINFOACCESS \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ), \ + ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for id-ad-ocsp (1.3.6.1.5.5.7.48.1) */ +#define ASN1_OID_OCSP \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ), \ + ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ + ASN1_OID_SINGLE ( 48 ), ASN1_OID_SINGLE ( 1 ) + /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ .data = oid_value, \ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 09e18007..271ed2e4 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -50,9 +50,9 @@ struct x509_validity { struct x509_time not_after; }; -/** An X.509 name */ -struct x509_name { - /** Name (not NUL-terminated) */ +/** An X.509 string */ +struct x509_string { + /** String (not NUL-terminated) */ const void *data; /** Length of name */ size_t len; @@ -71,7 +71,7 @@ struct x509_subject { /** Raw subject */ struct asn1_cursor raw; /** Common name */ - struct x509_name name; + struct x509_string name; /** Public key information */ struct x509_public_key public_key; }; @@ -128,6 +128,18 @@ enum x509_extended_key_usage_bits { X509_CODE_SIGNING = 0x0001, }; +/** X.509 certificate OCSP responder */ +struct x509_ocsp_responder { + /** URI */ + struct x509_string uri; +}; + +/** X.509 certificate authority information access */ +struct x509_authority_info_access { + /** OCSP responder */ + struct x509_ocsp_responder ocsp; +}; + /** An X.509 certificate extensions set */ struct x509_extensions { /** Basic constraints */ @@ -136,6 +148,8 @@ struct x509_extensions { struct x509_key_usage usage; /** Extended key usage */ struct x509_extended_key_usage ext_usage; + /** Authority information access */ + struct x509_authority_info_access auth_info; }; /** An X.509 certificate */ @@ -188,6 +202,22 @@ struct x509_key_purpose { unsigned int bits; }; +/** An X.509 access method */ +struct x509_access_method { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Parse access method + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ + int ( * parse ) ( struct x509_certificate *cert, + const struct asn1_cursor *raw ); +}; + /** An X.509 root certificate store */ struct x509_root { /** Fingerprint digest algorithm */ diff --git a/src/net/tls.c b/src/net/tls.c index 0f11fbe2..3d46a2c7 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1347,7 +1347,7 @@ static int tls_new_certificate ( struct tls_session *tls, struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; struct tls_certificate_context context; struct x509_certificate cert; - struct x509_name *name = &cert.subject.name; + struct x509_string *name = &cert.subject.name; struct x509_public_key *key = &cert.subject.public_key; time_t now; int rc;