diff options
Diffstat (limited to 'src/crypto/x509.c')
| -rw-r--r-- | src/crypto/x509.c | 202 |
1 files changed, 159 insertions, 43 deletions
diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 92318093e..6a3fe423b 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdlib.h> #include <string.h> @@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/rsa.h> #include <ipxe/rootcert.h> #include <ipxe/certstore.h> +#include <ipxe/privkey.h> #include <ipxe/socket.h> #include <ipxe/in.h> #include <ipxe/image.h> @@ -231,7 +233,7 @@ static int x509_parse_serial ( struct x509_certificate *cert, cert, strerror ( rc ) ); return rc; } - DBGC2 ( cert, "X509 %p issuer is:\n", cert ); + DBGC2 ( cert, "X509 %p serial is:\n", cert ); DBGC2_HDA ( cert, 0, serial->raw.data, serial->raw.len ); return 0; @@ -391,7 +393,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 asn1_bit_string *raw_bits = &public_key->raw_bits; + struct asn1_cursor *value = &public_key->value; struct asn1_cursor cursor; int rc; @@ -415,8 +417,9 @@ static int x509_parse_public_key ( struct x509_certificate *cert, cert, (*algorithm)->name ); asn1_skip_any ( &cursor ); - /* Parse bit string */ - if ( ( rc = asn1_bit_string ( &cursor, raw_bits ) ) != 0 ) { + /* Parse subjectPublicKey */ + memcpy ( value, &cursor, sizeof ( *value ) ); + if ( ( rc = asn1_enter_bits ( value, NULL ) ) != 0 ) { DBGC ( cert, "X509 %p could not parse public key bits: %s\n", cert, strerror ( rc ) ); return rc; @@ -497,8 +500,9 @@ 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 asn1_bit_string bit_string; + struct asn1_cursor cursor; const uint8_t *bytes; + unsigned int unused; size_t len; unsigned int i; int rc; @@ -506,16 +510,17 @@ static int x509_parse_key_usage ( struct x509_certificate *cert, /* Mark extension as present */ usage->present = 1; - /* Parse bit string */ - if ( ( rc = asn1_bit_string ( raw, &bit_string ) ) != 0 ) { + /* Enter bit string */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter_bits ( &cursor, &unused ) ) != 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; - len = bit_string.len; + bytes = cursor.data; + len = cursor.len; if ( len > sizeof ( usage->bits ) ) len = sizeof ( usage->bits ); for ( i = 0 ; i < len ; i++ ) { @@ -1004,7 +1009,7 @@ 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 asn1_bit_string *signature_value = &signature->value; + struct asn1_cursor *signature_value = &signature->value; struct asn1_cursor cursor; int rc; @@ -1032,8 +1037,8 @@ int x509_parse ( struct x509_certificate *cert, asn1_skip_any ( &cursor ); /* Parse signatureValue */ - if ( ( rc = asn1_integral_bit_string ( &cursor, - signature_value ) ) != 0 ) { + memcpy ( signature_value, &cursor, sizeof ( *signature_value ) ); + if ( ( rc = asn1_enter_bits ( signature_value, NULL ) ) != 0 ) { DBGC ( cert, "X509 %p could not parse signature value: %s\n", cert, strerror ( rc ) ); return rc; @@ -1078,7 +1083,7 @@ int x509_certificate ( const void *data, size_t len, asn1_shrink_any ( &cursor ); /* Return stored certificate, if present */ - if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) { + if ( ( *cert = x509_find ( NULL, &cursor ) ) != NULL ) { /* Add caller's reference */ x509_get ( *cert ); @@ -1124,7 +1129,6 @@ static int x509_check_signature ( struct x509_certificate *cert, struct pubkey_algorithm *pubkey = algorithm->pubkey; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; - uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Sanity check */ @@ -1148,15 +1152,8 @@ static int x509_check_signature ( struct x509_certificate *cert, } /* Verify signature using signer's public key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { - DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " - "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); - goto err_pubkey_init; - } - if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, - signature->value.data, - signature->value.len ) ) != 0 ) { + if ( ( rc = pubkey_verify ( pubkey, &public_key->raw, digest, + digest_out, &signature->value ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_verify; @@ -1166,8 +1163,6 @@ static int x509_check_signature ( struct x509_certificate *cert, rc = 0; err_pubkey_verify: - pubkey_final ( pubkey, pubkey_ctx ); - err_pubkey_init: err_mismatch: return rc; } @@ -1331,9 +1326,9 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { * @v issuer Issuing X.509 certificate (or NULL) * @v root Root certificate list */ -static void x509_set_valid ( struct x509_certificate *cert, - struct x509_certificate *issuer, - struct x509_root *root ) { +void x509_set_valid ( struct x509_certificate *cert, + struct x509_certificate *issuer, + struct x509_root *root ) { unsigned int max_path_remaining; /* Sanity checks */ @@ -1642,11 +1637,17 @@ struct x509_chain * x509_alloc_chain ( void ) { */ int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) { struct x509_link *link; + int rc; + + /* Ensure allocation of link cannot invalidate certificate */ + x509_get ( cert ); /* Allocate link */ link = zalloc ( sizeof ( *link ) ); - if ( ! link ) - return -ENOMEM; + if ( ! link ) { + rc = -ENOMEM; + goto err_alloc; + } /* Add link to chain */ link->cert = x509_get ( cert ); @@ -1654,7 +1655,12 @@ int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) { DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n", chain, cert, x509_name ( cert ) ); - return 0; + /* Success */ + rc = 0; + + x509_put ( cert ); + err_alloc: + return rc; } /** @@ -1711,25 +1717,139 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { } /** + * Mark X.509 certificate as found + * + * @v store Certificate store + * @v cert X.509 certificate + * @ret cert X.509 certificate + */ +static struct x509_certificate * x509_found ( struct x509_chain *store, + struct x509_certificate *cert ) { + + /* Sanity check */ + assert ( store != NULL ); + + /* Mark as found, if applicable */ + if ( store->found ) + store->found ( store, cert ); + + return cert; +} + +/** + * Identify X.509 certificate by raw certificate data + * + * @v store Certificate store, or NULL to use default + * @v raw Raw certificate data + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find ( struct x509_chain *store, + const struct asn1_cursor *raw ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Search for certificate within store */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check raw certificate data */ + cert = link->cert; + if ( asn1_compare ( raw, &cert->raw ) == 0 ) + return x509_found ( store, cert ); + } + + return NULL; +} + +/** * Identify X.509 certificate by subject * - * @v certs X.509 certificate list + * @v store Certificate store, or NULL to use default * @v subject Subject * @ret cert X.509 certificate, or NULL if not found */ -static struct x509_certificate * -x509_find_subject ( struct x509_chain *certs, +struct x509_certificate * +x509_find_subject ( struct x509_chain *store, const struct asn1_cursor *subject ) { struct x509_link *link; struct x509_certificate *cert; + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + /* Scan through certificate list */ - list_for_each_entry ( link, &certs->links, list ) { + list_for_each_entry ( link, &store->links, list ) { /* Check subject */ cert = link->cert; if ( asn1_compare ( subject, &cert->subject.raw ) == 0 ) - return cert; + return x509_found ( store, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by issuer and serial number + * + * @v store Certificate store, or NULL to use default + * @v issuer Issuer + * @v serial Serial number + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * +x509_find_issuer_serial ( struct x509_chain *store, + const struct asn1_cursor *issuer, + const struct asn1_cursor *serial ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Scan through certificate list */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check issuer and serial number */ + cert = link->cert; + if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) && + ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) ) + return x509_found ( store, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by corresponding public key + * + * @v store Certificate store, or NULL to use default + * @v key Private key + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find_key ( struct x509_chain *store, + struct private_key *key ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Scan through certificate list */ + list_for_each_entry ( link, &store->links, list ) { + + /* Check public key */ + cert = link->cert; + if ( pubkey_match ( cert->signature_algorithm->pubkey, + privkey_cursor ( key ), + &cert->subject.public_key.raw ) == 0 ) + return x509_found ( store, cert ); } return NULL; @@ -1739,13 +1859,13 @@ x509_find_subject ( struct x509_chain *certs, * Append X.509 certificates to X.509 certificate chain * * @v chain X.509 certificate chain - * @v certs X.509 certificate list + * @v store Certificate store, or NULL to use default * @ret rc Return status code * * Certificates will be automatically appended to the chain based upon * the subject and issuer names. */ -int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { +int x509_auto_append ( struct x509_chain *chain, struct x509_chain *store ) { struct x509_certificate *cert; struct x509_certificate *previous; int rc; @@ -1762,7 +1882,7 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { /* Find issuing certificate */ previous = cert; - cert = x509_find_subject ( certs, &cert->issuer.raw ); + cert = x509_find_subject ( store, &cert->issuer.raw ); if ( ! cert ) break; if ( cert == previous ) @@ -1791,10 +1911,6 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time, struct x509_link *link; int rc; - /* Use default certificate store if none specified */ - if ( ! store ) - store = &certstore; - /* Append any applicable certificates from the certificate store */ if ( ( rc = x509_auto_append ( chain, store ) ) != 0 ) return rc; |
