aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2020-12-09 16:19:03 +0000
committerMichael Brown <mcb30@ipxe.org>2020-12-09 16:45:50 +0000
commit3475f9162b84ce21327244ebce20ae29db6d7ac8 (patch)
tree39f7a31165e66cf82d92f5d8d536e9b18b248c76
parente3eedb0be581b7f3df70e8150c7adfcf275506b8 (diff)
downloadipxe-3475f9162b84ce21327244ebce20ae29db6d7ac8.zip
ipxe-3475f9162b84ce21327244ebce20ae29db6d7ac8.tar.gz
ipxe-3475f9162b84ce21327244ebce20ae29db6d7ac8.tar.bz2
[x509] Make root of trust a reference-counted structure
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/crypto/rootcert.c1
-rw-r--r--src/crypto/x509.c56
-rw-r--r--src/include/ipxe/x509.h27
-rw-r--r--src/net/tls.c3
-rw-r--r--src/net/validator.c3
-rw-r--r--src/tests/cms_test.c2
-rw-r--r--src/tests/x509_test.c3
7 files changed, 81 insertions, 14 deletions
diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c
index 867ff50..0835ff0 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 fe514e2..892d8f8 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 cac2f19..c703c8f 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 c04f0d5..f5459a2 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 c407a09..693d446 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 b805a99..f35fa20 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 2915b90..256c3e8 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,