From fe6e741c62e11655018996b5d281eaeb1af796c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 16:16:37 +0000 Subject: [PATCH] [crypto] Parse X.509 extended key usage extension Signed-off-by: Michael Brown --- src/crypto/x509.c | 85 +++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/asn1.h | 12 ++++++ src/include/ipxe/x509.h | 27 +++++++++++++ 3 files changed, 124 insertions(+) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index cf82fc03..7c6aab5c 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -683,12 +683,92 @@ static int x509_parse_key_usage ( struct x509_certificate *cert, return 0; } +/** "id-kp-codeSigning" object identifier */ +static uint8_t oid_code_signing[] = { ASN1_OID_CODESIGNING }; + +/** Supported key purposes */ +static struct x509_key_purpose x509_key_purposes[] = { + { + .name = "codeSigning", + .bits = X509_CODE_SIGNING, + .oid = ASN1_OID_CURSOR ( oid_code_signing ), + }, +}; + +/** + * Parse X.509 certificate key purpose identifier + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_key_purpose ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_extended_key_usage *ext_usage = &cert->extensions.ext_usage; + struct x509_key_purpose *purpose; + struct asn1_cursor cursor; + unsigned int i; + int rc; + + /* Enter keyPurposeId */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) { + DBGC ( cert, "X509 %p invalid keyPurposeId:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Identify key purpose */ + for ( i = 0 ; i < ( sizeof ( x509_key_purposes ) / + sizeof ( x509_key_purposes[0] ) ) ; i++ ) { + purpose = &x509_key_purposes[i]; + if ( asn1_compare ( &cursor, &purpose->oid ) == 0 ) { + DBGC ( cert, "X509 %p has key purpose %s\n", + cert, purpose->name ); + ext_usage->bits |= purpose->bits; + return 0; + } + } + + /* Ignore unrecognised key purposes */ + return 0; +} + +/** + * Parse X.509 certificate extended key usage + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_extended_key_usage ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter extKeyUsage */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse each extension in turn */ + while ( cursor.len ) { + if ( ( rc = x509_parse_key_purpose ( 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 }; /** "id-ce-keyUsage" object identifier */ 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 }; + /** Supported certificate extensions */ static struct x509_extension x509_extensions[] = { { @@ -701,6 +781,11 @@ static struct x509_extension x509_extensions[] = { .oid = ASN1_OID_CURSOR ( oid_ce_key_usage ), .parse = x509_parse_key_usage, }, + { + .name = "extKeyUsage", + .oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ), + .parse = x509_parse_extended_key_usage, + }, }; /** diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 553a8f3c..393d5dc3 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -140,6 +140,18 @@ struct asn1_cursor { ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ ASN1_OID_SINGLE ( 19 ) +/** ASN.1 OID for id-ce-extKeyUsage (2.5.29.37) */ +#define ASN1_OID_EXTKEYUSAGE \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ + ASN1_OID_SINGLE ( 37 ) + +/** ASN.1 OID for id-kp-codeSigning (1.3.6.1.5.5.7.3.3) */ +#define ASN1_OID_CODESIGNING \ + 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 ( 3 ), ASN1_OID_SINGLE ( 3 ) + /** 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 427f7955..09e18007 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -113,12 +113,29 @@ enum x509_key_usage_bits { X509_DECIPHER_ONLY = 0x8000, }; +/** An X.509 certificate extended key usage */ +struct x509_extended_key_usage { + /** Usage bits */ + unsigned int bits; +}; + +/** X.509 certificate extended key usage bits + * + * Extended key usages are identified by OID; these bits are purely an + * internal definition. + */ +enum x509_extended_key_usage_bits { + X509_CODE_SIGNING = 0x0001, +}; + /** An X.509 certificate extensions set */ struct x509_extensions { /** Basic constraints */ struct x509_basic_constraints basic; /** Key usage */ struct x509_key_usage usage; + /** Extended key usage */ + struct x509_extended_key_usage ext_usage; }; /** An X.509 certificate */ @@ -161,6 +178,16 @@ struct x509_extension { const struct asn1_cursor *raw ); }; +/** An X.509 key purpose */ +struct x509_key_purpose { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Extended key usage bits */ + unsigned int bits; +}; + /** An X.509 root certificate store */ struct x509_root { /** Fingerprint digest algorithm */