diff options
author | Michael Brown <mcb30@ipxe.org> | 2020-12-08 14:58:46 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2020-12-08 15:04:28 +0000 |
commit | 39f5293492f351a274940d0ba2624ecb242b3c9b (patch) | |
tree | ead79747a5ab15d5db6dd4a236acdc9f224c7590 | |
parent | 6e92d6213d20329d8b84431f00d8cbe7d63bb379 (diff) | |
download | ipxe-39f5293492f351a274940d0ba2624ecb242b3c9b.zip ipxe-39f5293492f351a274940d0ba2624ecb242b3c9b.tar.gz ipxe-39f5293492f351a274940d0ba2624ecb242b3c9b.tar.bz2 |
[x509] Record root of trust used when validating a certificate
Record the root of trust used at the point that a certificate is
validated, redefine validation as checking a certificate against a
specific root of trust, and pass an explicit root of trust when
creating a TLS connection.
This allows a custom TLS connection to be used with a custom root of
trust, without causing any validated certificates to be treated as
valid for normal purposes.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/crypto/ocsp.c | 6 | ||||
-rw-r--r-- | src/crypto/x509.c | 23 | ||||
-rw-r--r-- | src/include/ipxe/tls.h | 5 | ||||
-rw-r--r-- | src/include/ipxe/validator.h | 3 | ||||
-rw-r--r-- | src/include/ipxe/x509.h | 21 | ||||
-rw-r--r-- | src/net/tcp/https.c | 2 | ||||
-rw-r--r-- | src/net/tcp/syslogs.c | 2 | ||||
-rw-r--r-- | src/net/tls.c | 8 | ||||
-rw-r--r-- | src/net/validator.c | 11 | ||||
-rw-r--r-- | src/tests/ocsp_test.c | 3 | ||||
-rw-r--r-- | src/tests/x509_test.c | 4 | ||||
-rw-r--r-- | src/usr/certmgmt.c | 2 | ||||
-rw-r--r-- | src/usr/imgtrust.c | 3 |
13 files changed, 60 insertions, 33 deletions
diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index 998a0ce..cc957b4 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -284,7 +284,7 @@ int ocsp_check ( struct x509_certificate *cert, /* Sanity checks */ assert ( cert != NULL ); assert ( issuer != NULL ); - assert ( x509_is_valid ( issuer ) ); + assert ( issuer->root != NULL ); /* Allocate and initialise check */ *ocsp = zalloc ( sizeof ( **ocsp ) ); @@ -915,7 +915,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { */ x509_invalidate ( signer ); if ( ( rc = x509_validate ( signer, ocsp->issuer, time, - NULL ) ) != 0 ) { + ocsp->issuer->root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate ", ocsp, x509_name ( ocsp->cert ) ); DBGC ( ocsp, "signer \"%s\": %s\n", @@ -961,7 +961,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { /* Validate certificate against issuer */ if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time, - NULL ) ) != 0 ) { + ocsp->issuer->root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index da0a858..fe514e2 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1296,6 +1296,21 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) { } /** + * Check if X.509 certificate is valid + * + * @v cert X.509 certificate + * @v root Root certificate list, or NULL to use default + */ +int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { + + /* Use default root certificate store if none specified */ + if ( ! root ) + root = &root_certificates; + + return ( cert->root == root ); +} + +/** * Validate X.509 certificate * * @v cert X.509 certificate @@ -1321,7 +1336,7 @@ int x509_validate ( struct x509_certificate *cert, root = &root_certificates; /* Return success if certificate has already been validated */ - if ( x509_is_valid ( cert ) ) + if ( x509_is_valid ( cert, root ) ) return 0; /* Fail if certificate is invalid at specified time */ @@ -1330,7 +1345,7 @@ int x509_validate ( struct x509_certificate *cert, /* Succeed if certificate is a trusted root certificate */ if ( x509_check_root ( cert, root ) == 0 ) { - cert->flags |= X509_FL_VALIDATED; + cert->root = root; cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); return 0; } @@ -1343,7 +1358,7 @@ int x509_validate ( struct x509_certificate *cert, } /* Fail unless issuer has already been validated */ - if ( ! x509_is_valid ( issuer ) ) { + if ( ! x509_is_valid ( issuer, root ) ) { DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n", issuer, x509_name ( issuer ) ); @@ -1376,7 +1391,7 @@ int x509_validate ( struct x509_certificate *cert, cert->path_remaining = max_path_remaining; /* Mark certificate as valid */ - cert->flags |= X509_FL_VALIDATED; + cert->root = root; DBGC ( cert, "X509 %p \"%s\" successfully validated using ", cert, x509_name ( cert ) ); diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index a2d4f47..1e1093f 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -326,6 +326,8 @@ struct tls_connection { /** Verification data */ struct tls_verify_data verify; + /** Root of trust (or NULL to use default) */ + struct x509_root *root; /** Server certificate chain */ struct x509_chain *chain; /** Certificate validator */ @@ -378,6 +380,7 @@ struct tls_connection { /** RX I/O buffer alignment */ #define TLS_RX_ALIGN 16 -extern int add_tls ( struct interface *xfer, const char *name ); +extern int add_tls ( struct interface *xfer, const char *name, + struct x509_root *root ); #endif /* _IPXE_TLS_H */ diff --git a/src/include/ipxe/validator.h b/src/include/ipxe/validator.h index 0aee56e..367e404 100644 --- a/src/include/ipxe/validator.h +++ b/src/include/ipxe/validator.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/interface.h> #include <ipxe/x509.h> -extern int create_validator ( struct interface *job, struct x509_chain *chain ); +extern int create_validator ( struct interface *job, struct x509_chain *chain, + struct x509_root *root ); #endif /* _IPXE_VALIDATOR_H */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 78eeafb..cac2f19 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -191,6 +191,8 @@ struct x509_certificate { /** Flags */ unsigned int flags; + /** Root against which certificate has been validated (if any) */ + struct x509_root *root; /** Maximum number of subsequent certificates in chain */ unsigned int path_remaining; @@ -218,12 +220,10 @@ struct x509_certificate { /** X.509 certificate flags */ enum x509_flags { - /** Certificate has been validated */ - X509_FL_VALIDATED = 0x0001, /** Certificate was added at build time */ - X509_FL_PERMANENT = 0x0002, + X509_FL_PERMANENT = 0x0001, /** Certificate was added explicitly at run time */ - X509_FL_EXPLICIT = 0x0004, + X509_FL_EXPLICIT = 0x0002, }; /** @@ -355,6 +355,8 @@ extern int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ); extern int x509_certificate ( const void *data, size_t len, struct x509_certificate **cert ); +extern int x509_is_valid ( struct x509_certificate *cert, + struct x509_root *root ); extern int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ); @@ -384,21 +386,12 @@ extern int x509_check_root ( struct x509_certificate *cert, extern int x509_check_time ( struct x509_certificate *cert, time_t time ); /** - * Check if X.509 certificate is valid - * - * @v cert X.509 certificate - */ -static inline int x509_is_valid ( struct x509_certificate *cert ) { - return ( cert->flags & X509_FL_VALIDATED ); -} - -/** * Invalidate X.509 certificate * * @v cert X.509 certificate */ static inline void x509_invalidate ( struct x509_certificate *cert ) { - cert->flags &= ~X509_FL_VALIDATED; + cert->root = NULL; cert->path_remaining = 0; } diff --git a/src/net/tcp/https.c b/src/net/tcp/https.c index 5a44bde..eae8ae5 100644 --- a/src/net/tcp/https.c +++ b/src/net/tcp/https.c @@ -46,7 +46,7 @@ FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 ); */ static int https_filter ( struct http_connection *conn ) { - return add_tls ( &conn->socket, conn->uri->host ); + return add_tls ( &conn->socket, conn->uri->host, NULL ); } /** HTTPS URI opener */ diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index b376052..f91864a 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) { } /* Add TLS filter */ - if ( ( rc = add_tls ( &syslogs, server ) ) != 0 ) { + if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) { DBG ( "SYSLOGS cannot create TLS filter: %s\n", strerror ( rc ) ); goto err_add_tls; diff --git a/src/net/tls.c b/src/net/tls.c index c42b4dd..c04f0d5 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1938,7 +1938,8 @@ static int tls_new_server_hello_done ( struct tls_connection *tls, } /* Begin certificate validation */ - if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) { + if ( ( rc = create_validator ( &tls->validator, tls->chain, + tls->root ) ) != 0 ) { DBGC ( tls, "TLS %p could not start certificate validation: " "%s\n", tls, strerror ( rc ) ); return rc; @@ -3140,9 +3141,11 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { * * @v xfer Data transfer interface * @v name Host name + * @v root Root of trust (or NULL to use default) * @ret rc Return status code */ -int add_tls ( struct interface *xfer, const char *name ) { +int add_tls ( struct interface *xfer, const char *name, + struct x509_root *root ) { struct tls_connection *tls; int rc; @@ -3160,6 +3163,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->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 f6b03ff..c407a09 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -73,6 +73,8 @@ struct validator { /** Process */ struct process process; + /** Root of trust (or NULL to use default) */ + struct x509_root *root; /** X.509 certificate chain */ struct x509_chain *chain; /** OCSP check */ @@ -554,7 +556,7 @@ static void validator_step ( struct validator *validator ) { */ now = time ( NULL ); if ( ( rc = x509_validate_chain ( validator->chain, now, NULL, - NULL ) ) == 0 ) { + validator->root ) ) == 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" validated\n", validator, validator_name ( validator ) ); validator_finished ( validator, 0 ); @@ -569,7 +571,7 @@ static void validator_step ( struct validator *validator ) { issuer = link->cert; if ( ! cert ) continue; - if ( ! x509_is_valid ( issuer ) ) + if ( ! x509_is_valid ( issuer, validator->root ) ) continue; /* The issuer is valid, but this certificate is not * yet valid. If OCSP is applicable, start it. @@ -621,9 +623,11 @@ static struct process_descriptor validator_process_desc = * * @v job Job control interface * @v chain X.509 certificate chain + * @v root Root of trust, or NULL to use default * @ret rc Return status code */ -int create_validator ( struct interface *job, struct x509_chain *chain ) { +int create_validator ( struct interface *job, struct x509_chain *chain, + struct x509_root *root ) { struct validator *validator; int rc; @@ -646,6 +650,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->chain = x509_chain_get ( chain ); xferbuf_malloc_init ( &validator->buffer ); diff --git a/src/tests/ocsp_test.c b/src/tests/ocsp_test.c index a334934..3d2f556 100644 --- a/src/tests/ocsp_test.c +++ b/src/tests/ocsp_test.c @@ -42,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdlib.h> #include <string.h> #include <ipxe/x509.h> +#include <ipxe/rootcert.h> #include <ipxe/ocsp.h> #include <ipxe/test.h> @@ -110,7 +111,7 @@ static void ocsp_prepare_test ( struct ocsp_test *test ) { x509_invalidate ( cert ); /* Force-validate issuer certificate */ - issuer->flags |= X509_FL_VALIDATED; + issuer->root = &root_certificates; issuer->path_remaining = ( issuer->extensions.basic.path_len + 1 ); } diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 658d524..2915b90 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -943,6 +943,10 @@ static void x509_validate_chain_okx ( struct x509_test_chain *chn, time_t time, x509_invalidate_chain ( chn->chain ); okx ( x509_validate_chain ( chn->chain, time, store, root ) == 0, file, line ); + okx ( x509_is_valid ( chn->certs[0]->cert, root ), + file, line ); + okx ( ! x509_is_valid ( chn->certs[0]->cert, &dummy_root ), + file, line ); } #define x509_validate_chain_ok( chn, time, store, root ) \ x509_validate_chain_okx ( chn, time, store, root, __FILE__, __LINE__ ) diff --git a/src/usr/certmgmt.c b/src/usr/certmgmt.c index 2f233fe..e6bf51f 100644 --- a/src/usr/certmgmt.c +++ b/src/usr/certmgmt.c @@ -57,7 +57,7 @@ void certstat ( struct x509_certificate *cert ) { printf ( " [PERMANENT]" ); if ( cert->flags & X509_FL_EXPLICIT ) printf ( " [EXPLICIT]" ); - if ( x509_is_valid ( cert ) ) + if ( x509_is_valid ( cert, NULL ) ) printf ( " [VALIDATED]" ); printf ( "\n" ); } diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index 595ea6b..e7c2067 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -77,7 +77,8 @@ int imgverify ( struct image *image, struct image *signature, /* Complete all certificate chains */ list_for_each_entry ( info, &sig->info, list ) { - if ( ( rc = create_validator ( &monojob, info->chain ) ) != 0 ) + if ( ( rc = create_validator ( &monojob, info->chain, + NULL ) ) != 0 ) goto err_create_validator; if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) goto err_validator_wait; |