diff options
author | Michael Brown <mcb30@ipxe.org> | 2020-12-09 16:19:03 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2020-12-09 16:45:50 +0000 |
commit | 3475f9162b84ce21327244ebce20ae29db6d7ac8 (patch) | |
tree | 39f7a31165e66cf82d92f5d8d536e9b18b248c76 | |
parent | e3eedb0be581b7f3df70e8150c7adfcf275506b8 (diff) | |
download | ipxe-3475f9162b84ce21327244ebce20ae29db6d7ac8.tar.gz |
[x509] Make root of trust a reference-counted structure
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/crypto/rootcert.c | 1 | ||||
-rw-r--r-- | src/crypto/x509.c | 56 | ||||
-rw-r--r-- | src/include/ipxe/x509.h | 27 | ||||
-rw-r--r-- | src/net/tls.c | 3 | ||||
-rw-r--r-- | src/net/validator.c | 3 | ||||
-rw-r--r-- | src/tests/cms_test.c | 2 | ||||
-rw-r--r-- | src/tests/x509_test.c | 3 |
7 files changed, 81 insertions, 14 deletions
diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c index 867ff50e8..0835ff071 100644 --- a/src/crypto/rootcert.c +++ b/src/crypto/rootcert.c @@ -71,6 +71,7 @@ static struct setting trust_setting __setting ( SETTING_CRYPTO, trust ) = { /** Root certificates */ struct x509_root root_certificates = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &sha256_algorithm, .count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ), .fingerprints = fingerprints, diff --git a/src/crypto/x509.c b/src/crypto/x509.c index fe514e269..892d8f8d5 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -123,6 +123,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" ) /** + * Free X.509 certificate + * + * @v refcnt Reference count + */ +static void x509_free ( struct refcnt *refcnt ) { + struct x509_certificate *cert = + container_of ( refcnt, struct x509_certificate, refcnt ); + + x509_root_put ( cert->root ); + free ( cert ); +} + +/** * Get X.509 certificate display name * * @v cert X.509 certificate @@ -1075,7 +1088,7 @@ int x509_certificate ( const void *data, size_t len, *cert = zalloc ( sizeof ( **cert ) + cursor.len ); if ( ! *cert ) return -ENOMEM; - ref_init ( &(*cert)->refcnt, NULL ); + ref_init ( &(*cert)->refcnt, x509_free ); raw = ( *cert + 1 ); /* Copy raw data */ @@ -1311,6 +1324,35 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { } /** + * Set X.509 certificate as validated + * + * @v cert X.509 certificate + * @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 ) { + unsigned int max_path_remaining; + + /* Sanity checks */ + assert ( root != NULL ); + assert ( ( issuer == NULL ) || ( issuer->path_remaining >= 1 ) ); + + /* Record validation root */ + x509_root_put ( cert->root ); + cert->root = x509_root_get ( root ); + + /* Calculate effective path length */ + cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); + if ( issuer ) { + max_path_remaining = ( issuer->path_remaining - 1 ); + if ( cert->path_remaining > max_path_remaining ) + cert->path_remaining = max_path_remaining; + } +} + +/** * Validate X.509 certificate * * @v cert X.509 certificate @@ -1328,7 +1370,6 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ) { - unsigned int max_path_remaining; int rc; /* Use default root certificate store if none specified */ @@ -1345,8 +1386,7 @@ int x509_validate ( struct x509_certificate *cert, /* Succeed if certificate is a trusted root certificate */ if ( x509_check_root ( cert, root ) == 0 ) { - cert->root = root; - cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); + x509_set_valid ( cert, NULL, root ); return 0; } @@ -1384,14 +1424,8 @@ int x509_validate ( struct x509_certificate *cert, return -EACCES_OCSP_REQUIRED; } - /* Calculate effective path length */ - cert->path_remaining = ( issuer->path_remaining - 1 ); - max_path_remaining = ( cert->extensions.basic.path_len + 1 ); - if ( cert->path_remaining > max_path_remaining ) - cert->path_remaining = max_path_remaining; - /* Mark certificate as valid */ - cert->root = root; + x509_set_valid ( cert, issuer, root ); DBGC ( cert, "X509 %p \"%s\" successfully validated using ", cert, x509_name ( cert ) ); diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index cac2f19f0..c703c8f10 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -340,8 +340,10 @@ struct x509_access_method { const struct asn1_cursor *raw ); }; -/** An X.509 root certificate store */ +/** An X.509 root certificate list */ struct x509_root { + /** Reference count */ + struct refcnt refcnt; /** Fingerprint digest algorithm */ struct digest_algorithm *digest; /** Number of certificates */ @@ -350,6 +352,28 @@ struct x509_root { const void *fingerprints; }; +/** + * Get reference to X.509 root certificate list + * + * @v root X.509 root certificate list + * @ret root X.509 root certificate list + */ +static inline __attribute__ (( always_inline )) struct x509_root * +x509_root_get ( struct x509_root *root ) { + ref_get ( &root->refcnt ); + return root; +} + +/** + * Drop reference to X.509 root certificate list + * + * @v root X.509 root certificate list + */ +static inline __attribute__ (( always_inline )) void +x509_root_put ( struct x509_root *root ) { + ref_put ( &root->refcnt ); +} + extern const char * x509_name ( struct x509_certificate *cert ); extern int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ); @@ -391,6 +415,7 @@ extern int x509_check_time ( struct x509_certificate *cert, time_t time ); * @v cert X.509 certificate */ static inline void x509_invalidate ( struct x509_certificate *cert ) { + x509_root_put ( cert->root ); cert->root = NULL; cert->path_remaining = 0; } diff --git a/src/net/tls.c b/src/net/tls.c index c04f0d557..f5459a2af 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -380,6 +380,7 @@ static void free_tls ( struct refcnt *refcnt ) { } x509_chain_put ( tls->certs ); x509_chain_put ( tls->chain ); + x509_root_put ( tls->root ); /* Drop reference to session */ assert ( list_empty ( &tls->list ) ); @@ -3163,7 +3164,7 @@ int add_tls ( struct interface *xfer, const char *name, intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); - tls->root = root; + tls->root = x509_root_get ( root ); tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); diff --git a/src/net/validator.c b/src/net/validator.c index c407a09b7..693d4464b 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -116,6 +116,7 @@ static void validator_free ( struct refcnt *refcnt ) { DBGC2 ( validator, "VALIDATOR %p \"%s\" freed\n", validator, validator_name ( validator ) ); + x509_root_put ( validator->root ); x509_chain_put ( validator->chain ); ocsp_put ( validator->ocsp ); xferbuf_free ( &validator->buffer ); @@ -650,7 +651,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain, &validator->refcnt ); process_init ( &validator->process, &validator_process_desc, &validator->refcnt ); - validator->root = root; + validator->root = x509_root_get ( root ); validator->chain = x509_chain_get ( chain ); xferbuf_malloc_init ( &validator->buffer ); diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index b805a9974..f35fa206d 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -1317,6 +1317,7 @@ static struct x509_chain empty_store = { /** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &cms_test_algorithm, .count = 1, .fingerprints = root_crt_fingerprint, @@ -1331,6 +1332,7 @@ static uint8_t dummy_fingerprint[] = /** Certificate store containing a dummy fingerprint */ static struct x509_root dummy_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &cms_test_algorithm, .count = 1, .fingerprints = dummy_fingerprint, diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 2915b9068..256c3e85e 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -674,6 +674,7 @@ static struct x509_chain empty_store = { /** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = root_crt_fingerprint, @@ -681,6 +682,7 @@ static struct x509_root test_root = { /** Root certificate list containing the iPXE self-test intermediate CA */ static struct x509_root intermediate_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = intermediate_crt_fingerprint, @@ -695,6 +697,7 @@ static uint8_t dummy_fingerprint[] = /** Certificate store containing a dummy fingerprint */ static struct x509_root dummy_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = dummy_fingerprint, |