]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[x509] Record root of trust used when validating a certificate
authorMichael Brown <mcb30@ipxe.org>
Tue, 8 Dec 2020 14:58:46 +0000 (14:58 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 8 Dec 2020 15:04:28 +0000 (15:04 +0000)
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>
13 files changed:
src/crypto/ocsp.c
src/crypto/x509.c
src/include/ipxe/tls.h
src/include/ipxe/validator.h
src/include/ipxe/x509.h
src/net/tcp/https.c
src/net/tcp/syslogs.c
src/net/tls.c
src/net/validator.c
src/tests/ocsp_test.c
src/tests/x509_test.c
src/usr/certmgmt.c
src/usr/imgtrust.c

index 998a0ce2c49ea437e3b576f8863f95f75c46d280..cc957b40cc1b2a7035de75c348fca33ecc673f53 100644 (file)
@@ -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;
index da0a85825e4f2c0e18525e151964136e06ea7dcf..fe514e269afa02229c4e840b7315ce5022c68d4e 100644 (file)
@@ -1295,6 +1295,21 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) {
        return 0;
 }
 
+/**
+ * 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
  *
@@ -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 ) );
index a2d4f475b3faf0354c8a1afd68600d487528fbd3..1e1093fde85731420b0f7caa3fcb776b3c7899d7 100644 (file)
@@ -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 */
index 0aee56eb0c050b21c1fc6660df7c8644e89e7908..367e4045d433715a7f32b91163fd280df2f2a750 100644 (file)
@@ -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 */
index 78eeafbfb5922708e0381922d0437edeb7a3737a..cac2f19f08bb4d5e013ae64bb5fe817cc496fd6b 100644 (file)
@@ -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 );
@@ -383,22 +385,13 @@ extern int x509_check_root ( struct x509_certificate *cert,
                             struct x509_root *root );
 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;
 }
 
index 5a44bdebf36c8c71eab00bd0668d3043158e0504..eae8ae5dc62c1b9803143342e900d1c01eba30e5 100644 (file)
@@ -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 */
index b37605272037d8b8386289853821af02820b4059..f91864a4407926b230f1317bfe0310a309bf9d45 100644 (file)
@@ -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;
index c42b4ddc7f45ecbbe6240ed270680f78d30f65e6..c04f0d55740bd8bafca279ac69f9e4b26782f4da 100644 (file)
@@ -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 );
index f6b03ff41949078bb62306fec9a425ca2b7990ed..c407a09b7427eb88f165b3acfe4eee7233b41886 100644 (file)
@@ -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 );
 
index a3349346a16dd7538b2a38b9c3d1c6b3643382da..3d2f556ed5f55df367dde626c972ceba84418d95 100644 (file)
@@ -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 );
 }
 
index 658d5247c1b8ab5f0b32838a38a43af82302fb26..2915b90689883f9b39ba5acf5fd6b39ef56a3c4a 100644 (file)
@@ -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__ )
index 2f233fe4f0840b001cd32c59aac83173583fcd43..e6bf51fd8dada8c443bccefb7409f693fd205171 100644 (file)
@@ -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" );
 }
index 595ea6b25715b2ec2e81ab4ac533ec2477c2a6a7..e7c2067a0ba817ca33fe1e4e50e4fca5dc3e66b9 100644 (file)
@@ -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;