diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c index 2676c7e1e..f8ddbd3d7 100644 --- a/src/crypto/certstore.c +++ b/src/crypto/certstore.c @@ -69,67 +69,29 @@ static struct asn1_cursor certstore_raw[] = { static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) / sizeof ( certstore_raw[0] ) ]; +/** + * Mark stored certificate as most recently used + * + * @v certs X.509 certificate list + * @v cert X.509 certificate + */ +static void certstore_found ( struct x509_chain *certs, + struct x509_certificate *cert ) { + + /* Mark as most recently used */ + list_del ( &cert->store.list ); + list_add ( &cert->store.list, &certs->links ); + DBGC2 ( certs, "CERTSTORE found certificate %s\n", + x509_name ( cert ) ); +} + /** Certificate store */ struct x509_chain certstore = { .refcnt = REF_INIT ( ref_no_free ), .links = LIST_HEAD_INIT ( certstore.links ), + .found = certstore_found, }; -/** - * Mark stored certificate as most recently used - * - * @v cert X.509 certificate - * @ret cert X.509 certificate - */ -static struct x509_certificate * -certstore_found ( struct x509_certificate *cert ) { - - /* Mark as most recently used */ - list_del ( &cert->store.list ); - list_add ( &cert->store.list, &certstore.links ); - DBGC2 ( &certstore, "CERTSTORE found certificate %s\n", - x509_name ( cert ) ); - - return cert; -} - -/** - * Find certificate in store - * - * @v raw Raw certificate data - * @ret cert X.509 certificate, or NULL if not found - */ -struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) { - struct x509_certificate *cert; - - /* Search for certificate within store */ - list_for_each_entry ( cert, &certstore.links, store.list ) { - if ( asn1_compare ( raw, &cert->raw ) == 0 ) - return certstore_found ( cert ); - } - return NULL; -} - -/** - * Find certificate in store corresponding to a private key - * - * @v key Private key - * @ret cert X.509 certificate, or NULL if not found - */ -struct x509_certificate * certstore_find_key ( struct private_key *key ) { - struct x509_certificate *cert; - - /* Search for certificate within store */ - list_for_each_entry ( cert, &certstore.links, store.list ) { - if ( pubkey_match ( cert->signature_algorithm->pubkey, - key->builder.data, key->builder.len, - cert->subject.public_key.raw.data, - cert->subject.public_key.raw.len ) == 0 ) - return certstore_found ( cert ); - } - return NULL; -} - /** * Add certificate to store * @@ -219,7 +181,7 @@ static void certstore_init ( void ) { /* Skip if certificate already present in store */ raw = &certstore_raw[i]; - if ( ( cert = certstore_find ( raw ) ) != NULL ) { + if ( ( cert = x509_find ( &certstore, raw ) ) != NULL ) { DBGC ( &certstore, "CERTSTORE permanent certificate %d " "is a duplicate of %s\n", i, x509_name ( cert )); continue; diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 9511cec8a..19a0ce7ad 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -143,34 +143,6 @@ static int cms_parse_certificates ( struct cms_signature *sig, return 0; } -/** - * Identify CMS signature certificate by issuer and serial number - * - * @v sig CMS signature - * @v issuer Issuer - * @v serial Serial number - * @ret cert X.509 certificate, or NULL if not found - */ -static struct x509_certificate * -cms_find_issuer_serial ( struct cms_signature *sig, - const struct asn1_cursor *issuer, - const struct asn1_cursor *serial ) { - struct x509_link *link; - struct x509_certificate *cert; - - /* Scan through certificate list */ - list_for_each_entry ( link, &sig->certificates->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 cert; - } - - return NULL; -} - /** * Parse CMS signature signer identifier * @@ -216,7 +188,7 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig, DBGC_HDA ( sig, 0, serial.data, serial.len ); /* Identify certificate */ - cert = cms_find_issuer_serial ( sig, &issuer, &serial ); + cert = x509_find_issuer_serial ( sig->certificates, &issuer, &serial ); if ( ! cert ) { DBGC ( sig, "CMS %p/%p could not identify signer's " "certificate\n", sig, info ); diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 92318093e..341b91449 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -1078,7 +1079,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 ( &certstore, &cursor ) ) != NULL ) { /* Add caller's reference */ x509_get ( *cert ); @@ -1710,6 +1711,47 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { } } +/** + * Mark X.509 certificate as found + * + * @v certs X.509 certificate list + * @v cert X.509 certificate + * @ret cert X.509 certificate + */ +static struct x509_certificate * x509_found ( struct x509_chain *certs, + struct x509_certificate *cert ) { + + /* Mark as found, if applicable */ + if ( certs->found ) + certs->found ( certs, cert ); + + return cert; +} + +/** + * Identify X.509 certificate by raw certificate data + * + * @v certs X.509 certificate list + * @v raw Raw certificate data + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find ( struct x509_chain *certs, + const struct asn1_cursor *raw ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Search for certificate within store */ + list_for_each_entry ( link, &certs->links, list ) { + + /* Check raw certificate data */ + cert = link->cert; + if ( asn1_compare ( raw, &cert->raw ) == 0 ) + return x509_found ( certs, cert ); + } + + return NULL; +} + /** * Identify X.509 certificate by subject * @@ -1717,7 +1759,7 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { * @v subject Subject * @ret cert X.509 certificate, or NULL if not found */ -static struct x509_certificate * +struct x509_certificate * x509_find_subject ( struct x509_chain *certs, const struct asn1_cursor *subject ) { struct x509_link *link; @@ -1729,7 +1771,62 @@ x509_find_subject ( struct x509_chain *certs, /* Check subject */ cert = link->cert; if ( asn1_compare ( subject, &cert->subject.raw ) == 0 ) - return cert; + return x509_found ( certs, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by issuer and serial number + * + * @v certs X.509 certificate list + * @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 *certs, + const struct asn1_cursor *issuer, + const struct asn1_cursor *serial ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Scan through certificate list */ + list_for_each_entry ( link, &certs->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 ( certs, cert ); + } + + return NULL; +} + +/** + * Identify X.509 certificate by corresponding public key + * + * @v certs X.509 certificate list + * @v key Private key + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * x509_find_key ( struct x509_chain *certs, + struct private_key *key ) { + struct x509_link *link; + struct x509_certificate *cert; + + /* Scan through certificate list */ + list_for_each_entry ( link, &certs->links, list ) { + + /* Check public key */ + cert = link->cert; + if ( pubkey_match ( cert->signature_algorithm->pubkey, + key->builder.data, key->builder.len, + cert->subject.public_key.raw.data, + cert->subject.public_key.raw.len ) == 0 ) + return x509_found ( certs, cert ); } return NULL; diff --git a/src/include/ipxe/certstore.h b/src/include/ipxe/certstore.h index ce96666cf..e276d6792 100644 --- a/src/include/ipxe/certstore.h +++ b/src/include/ipxe/certstore.h @@ -9,14 +9,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include #include -#include extern struct x509_chain certstore; -extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw ); -extern struct x509_certificate * certstore_find_key ( struct private_key *key ); extern void certstore_add ( struct x509_certificate *cert ); extern void certstore_del ( struct x509_certificate *cert ); diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 87323cec0..612743a77 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include struct image; +struct private_key; /** An X.509 serial number */ struct x509_serial { @@ -201,6 +202,13 @@ struct x509_chain { struct refcnt refcnt; /** List of links */ struct list_head links; + /** Mark certificate as found + * + * @v certs X.509 certificate list + * @v cert X.509 certificate + */ + void ( * found ) ( struct x509_chain *certs, + struct x509_certificate *cert ); }; /** An X.509 certificate */ @@ -424,6 +432,17 @@ extern int x509_append ( struct x509_chain *chain, extern int x509_append_raw ( struct x509_chain *chain, const void *data, size_t len ); extern void x509_truncate ( struct x509_chain *chain, struct x509_link *link ); +extern struct x509_certificate * x509_find ( struct x509_chain *certs, + const struct asn1_cursor *raw ); +extern struct x509_certificate * +x509_find_subject ( struct x509_chain *certs, + const struct asn1_cursor *subject ); +extern struct x509_certificate * +x509_find_issuer_serial ( struct x509_chain *certs, + const struct asn1_cursor *issuer, + const struct asn1_cursor *serial ); +extern struct x509_certificate * x509_find_key ( struct x509_chain *certs, + struct private_key *key ); extern int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ); extern int x509_validate_chain ( struct x509_chain *chain, time_t time, diff --git a/src/net/tls.c b/src/net/tls.c index 5f89be452..98414e2b1 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -2467,7 +2467,7 @@ static int tls_new_certificate_request ( struct tls_connection *tls, tls->certs = NULL; /* Determine client certificate to be sent */ - cert = certstore_find_key ( tls->key ); + cert = x509_find_key ( &certstore, tls->key ); if ( ! cert ) { DBGC ( tls, "TLS %p could not find certificate corresponding " "to private key\n", tls );