aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2020-12-08 14:58:46 +0000
committerMichael Brown <mcb30@ipxe.org>2020-12-08 15:04:28 +0000
commit39f5293492f351a274940d0ba2624ecb242b3c9b (patch)
treeead79747a5ab15d5db6dd4a236acdc9f224c7590
parent6e92d6213d20329d8b84431f00d8cbe7d63bb379 (diff)
downloadipxe-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.c6
-rw-r--r--src/crypto/x509.c23
-rw-r--r--src/include/ipxe/tls.h5
-rw-r--r--src/include/ipxe/validator.h3
-rw-r--r--src/include/ipxe/x509.h21
-rw-r--r--src/net/tcp/https.c2
-rw-r--r--src/net/tcp/syslogs.c2
-rw-r--r--src/net/tls.c8
-rw-r--r--src/net/validator.c11
-rw-r--r--src/tests/ocsp_test.c3
-rw-r--r--src/tests/x509_test.c4
-rw-r--r--src/usr/certmgmt.c2
-rw-r--r--src/usr/imgtrust.c3
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;