diff options
author | Michael Brown <mcb30@ipxe.org> | 2024-02-13 16:27:31 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2024-02-14 16:40:05 +0000 |
commit | 3e721e0c0836588b64deb6e1c1befd08f0f02e71 (patch) | |
tree | 417c4347622771d4fb5183cf292a69e621826519 | |
parent | e10dfe5dc7a5985333c85d6b196196b5cce9303a (diff) | |
download | ipxe-3e721e0c0836588b64deb6e1c1befd08f0f02e71.zip ipxe-3e721e0c0836588b64deb6e1c1befd08f0f02e71.tar.gz ipxe-3e721e0c0836588b64deb6e1c1befd08f0f02e71.tar.bz2 |
[crypto] Add x509_truncate() to truncate a certificate chain
Downloading a cross-signed certificate chain to partially replace
(rather than simply extend) an existing chain will require the ability
to discard all certificates after a specified link in the chain.
Extract the relevant logic from x509_free_chain() and expose it
separately as x509_truncate().
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/crypto/x509.c | 32 | ||||
-rw-r--r-- | src/include/ipxe/x509.h | 1 | ||||
-rw-r--r-- | src/tests/x509_test.c | 13 |
3 files changed, 37 insertions, 9 deletions
diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 1f017eb..9231809 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1603,19 +1603,12 @@ int x509_check_name ( struct x509_certificate *cert, const char *name ) { static void x509_free_chain ( struct refcnt *refcnt ) { struct x509_chain *chain = container_of ( refcnt, struct x509_chain, refcnt ); - struct x509_link *link; - struct x509_link *tmp; DBGC2 ( chain, "X509 chain %p freed\n", chain ); - /* Free each link in the chain */ - list_for_each_entry_safe ( link, tmp, &chain->links, list ) { - x509_put ( link->cert ); - list_del ( &link->list ); - free ( link ); - } - /* Free chain */ + x509_truncate ( chain, NULL ); + assert ( list_empty ( &chain->links ) ); free ( chain ); } @@ -1697,6 +1690,27 @@ int x509_append_raw ( struct x509_chain *chain, const void *data, } /** + * Truncate X.509 certificate chain + * + * @v chain X.509 certificate chain + * @v link Link after which to truncate chain, or NULL + */ +void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { + struct x509_link *tmp; + + /* Truncate entire chain if no link is specified */ + if ( ! link ) + link = list_entry ( &chain->links, struct x509_link, list ); + + /* Free each link in the chain */ + list_for_each_entry_safe_continue ( link, tmp, &chain->links, list ) { + x509_put ( link->cert ); + list_del ( &link->list ); + free ( link ); + } +} + +/** * Identify X.509 certificate by subject * * @v certs X.509 certificate list diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index c703c8f..5cad459 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -391,6 +391,7 @@ extern int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ); 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 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/tests/x509_test.c b/src/tests/x509_test.c index b6cba57..bc90320 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -984,6 +984,7 @@ static void x509_validate_chain_fail_okx ( struct x509_test_chain *chn, * */ static void x509_test_exec ( void ) { + struct x509_link *link; /* Parse all certificates */ x509_certificate_ok ( &root_crt ); @@ -1089,6 +1090,18 @@ static void x509_test_exec ( void ) { x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired, &empty_store, &test_root ); + /* Check chain truncation */ + link = list_last_entry ( &server_chain.chain->links, + struct x509_link, list ); + ok ( link->cert == root_crt.cert ); + link = list_prev_entry ( link, &server_chain.chain->links, list ); + ok ( link->cert == intermediate_crt.cert ); + x509_validate_chain_ok ( &server_chain, test_time, + &empty_store, &test_root ); + x509_truncate ( server_chain.chain, link ); + x509_validate_chain_fail_ok ( &server_chain, test_time, + &empty_store, &test_root ); + /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); |