aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2024-08-12 12:26:52 +0100
committerMichael Brown <mcb30@ipxe.org>2024-08-12 12:38:08 +0100
commitd85590b6584499569c19f7ee4a1e0c10d5132f70 (patch)
treefa99029b98f48054c8469998e2e27141c12fca26
parent59e2b03e6ac842d0e69bc4f757bf6da452fca074 (diff)
downloadipxe-d85590b6584499569c19f7ee4a1e0c10d5132f70.tar.gz
[crypto] Centralise mechanisms for identifying X.509 certificates
Centralise all current mechanisms for identifying an X.509 certificate (by raw content, by subject, by issuer and serial number, and by matching public key), and remove the certstore-specific and CMS-specific variants of these functions. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/crypto/certstore.c62
-rw-r--r--src/crypto/cms.c30
-rw-r--r--src/crypto/x509.c103
-rw-r--r--src/include/ipxe/certstore.h4
-rw-r--r--src/include/ipxe/x509.h19
-rw-r--r--src/net/tls.c2
6 files changed, 133 insertions, 87 deletions
diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c
index 2676c7e1e..f8ddbd3d7 100644
--- a/src/crypto/certstore.c
+++ b/src/crypto/certstore.c
@@ -69,66 +69,28 @@ static struct asn1_cursor certstore_raw[] = {
static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) /
sizeof ( certstore_raw[0] ) ];
-/** Certificate store */
-struct x509_chain certstore = {
- .refcnt = REF_INIT ( ref_no_free ),
- .links = LIST_HEAD_INIT ( certstore.links ),
-};
-
/**
* Mark stored certificate as most recently used
*
+ * @v certs X.509 certificate list
* @v cert X.509 certificate
- * @ret cert X.509 certificate
*/
-static struct x509_certificate *
-certstore_found ( struct x509_certificate *cert ) {
+static void certstore_found ( struct x509_chain *certs,
+ struct x509_certificate *cert ) {
/* Mark as most recently used */
list_del ( &cert->store.list );
- list_add ( &cert->store.list, &certstore.links );
- DBGC2 ( &certstore, "CERTSTORE found certificate %s\n",
+ list_add ( &cert->store.list, &certs->links );
+ DBGC2 ( certs, "CERTSTORE found certificate %s\n",
x509_name ( cert ) );
-
- return cert;
-}
-
-/**
- * Find certificate in store
- *
- * @v raw Raw certificate data
- * @ret cert X.509 certificate, or NULL if not found
- */
-struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) {
- struct x509_certificate *cert;
-
- /* Search for certificate within store */
- list_for_each_entry ( cert, &certstore.links, store.list ) {
- if ( asn1_compare ( raw, &cert->raw ) == 0 )
- return certstore_found ( cert );
- }
- return NULL;
}
-/**
- * Find certificate in store corresponding to a private key
- *
- * @v key Private key
- * @ret cert X.509 certificate, or NULL if not found
- */
-struct x509_certificate * certstore_find_key ( struct private_key *key ) {
- struct x509_certificate *cert;
-
- /* Search for certificate within store */
- list_for_each_entry ( cert, &certstore.links, store.list ) {
- if ( pubkey_match ( cert->signature_algorithm->pubkey,
- key->builder.data, key->builder.len,
- cert->subject.public_key.raw.data,
- cert->subject.public_key.raw.len ) == 0 )
- return certstore_found ( cert );
- }
- return NULL;
-}
+/** Certificate store */
+struct x509_chain certstore = {
+ .refcnt = REF_INIT ( ref_no_free ),
+ .links = LIST_HEAD_INIT ( certstore.links ),
+ .found = certstore_found,
+};
/**
* Add certificate to store
@@ -219,7 +181,7 @@ static void certstore_init ( void ) {
/* Skip if certificate already present in store */
raw = &certstore_raw[i];
- if ( ( cert = certstore_find ( raw ) ) != NULL ) {
+ if ( ( cert = x509_find ( &certstore, raw ) ) != NULL ) {
DBGC ( &certstore, "CERTSTORE permanent certificate %d "
"is a duplicate of %s\n", i, x509_name ( cert ));
continue;
diff --git a/src/crypto/cms.c b/src/crypto/cms.c
index 9511cec8a..19a0ce7ad 100644
--- a/src/crypto/cms.c
+++ b/src/crypto/cms.c
@@ -144,34 +144,6 @@ static int cms_parse_certificates ( struct cms_signature *sig,
}
/**
- * Identify CMS signature certificate by issuer and serial number
- *
- * @v sig CMS signature
- * @v issuer Issuer
- * @v serial Serial number
- * @ret cert X.509 certificate, or NULL if not found
- */
-static struct x509_certificate *
-cms_find_issuer_serial ( struct cms_signature *sig,
- const struct asn1_cursor *issuer,
- const struct asn1_cursor *serial ) {
- struct x509_link *link;
- struct x509_certificate *cert;
-
- /* Scan through certificate list */
- list_for_each_entry ( link, &sig->certificates->links, list ) {
-
- /* Check issuer and serial number */
- cert = link->cert;
- if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
- ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
- return cert;
- }
-
- return NULL;
-}
-
-/**
* Parse CMS signature signer identifier
*
* @v sig CMS signature
@@ -216,7 +188,7 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig,
DBGC_HDA ( sig, 0, serial.data, serial.len );
/* Identify certificate */
- cert = cms_find_issuer_serial ( sig, &issuer, &serial );
+ cert = x509_find_issuer_serial ( sig->certificates, &issuer, &serial );
if ( ! cert ) {
DBGC ( sig, "CMS %p/%p could not identify signer's "
"certificate\n", sig, info );
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 92318093e..341b91449 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rsa.h>
#include <ipxe/rootcert.h>
#include <ipxe/certstore.h>
+#include <ipxe/privkey.h>
#include <ipxe/socket.h>
#include <ipxe/in.h>
#include <ipxe/image.h>
@@ -1078,7 +1079,7 @@ int x509_certificate ( const void *data, size_t len,
asn1_shrink_any ( &cursor );
/* Return stored certificate, if present */
- if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) {
+ if ( ( *cert = x509_find ( &certstore, &cursor ) ) != NULL ) {
/* Add caller's reference */
x509_get ( *cert );
@@ -1711,13 +1712,54 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) {
}
/**
+ * Mark X.509 certificate as found
+ *
+ * @v certs X.509 certificate list
+ * @v cert X.509 certificate
+ * @ret cert X.509 certificate
+ */
+static struct x509_certificate * x509_found ( struct x509_chain *certs,
+ struct x509_certificate *cert ) {
+
+ /* Mark as found, if applicable */
+ if ( certs->found )
+ certs->found ( certs, cert );
+
+ return cert;
+}
+
+/**
+ * Identify X.509 certificate by raw certificate data
+ *
+ * @v certs X.509 certificate list
+ * @v raw Raw certificate data
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * x509_find ( struct x509_chain *certs,
+ const struct asn1_cursor *raw ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Search for certificate within store */
+ list_for_each_entry ( link, &certs->links, list ) {
+
+ /* Check raw certificate data */
+ cert = link->cert;
+ if ( asn1_compare ( raw, &cert->raw ) == 0 )
+ return x509_found ( certs, cert );
+ }
+
+ return NULL;
+}
+
+/**
* Identify X.509 certificate by subject
*
* @v certs X.509 certificate list
* @v subject Subject
* @ret cert X.509 certificate, or NULL if not found
*/
-static struct x509_certificate *
+struct x509_certificate *
x509_find_subject ( struct x509_chain *certs,
const struct asn1_cursor *subject ) {
struct x509_link *link;
@@ -1729,7 +1771,62 @@ x509_find_subject ( struct x509_chain *certs,
/* Check subject */
cert = link->cert;
if ( asn1_compare ( subject, &cert->subject.raw ) == 0 )
- return cert;
+ return x509_found ( certs, cert );
+ }
+
+ return NULL;
+}
+
+/**
+ * Identify X.509 certificate by issuer and serial number
+ *
+ * @v certs X.509 certificate list
+ * @v issuer Issuer
+ * @v serial Serial number
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate *
+x509_find_issuer_serial ( struct x509_chain *certs,
+ const struct asn1_cursor *issuer,
+ const struct asn1_cursor *serial ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &certs->links, list ) {
+
+ /* Check issuer and serial number */
+ cert = link->cert;
+ if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
+ ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
+ return x509_found ( certs, cert );
+ }
+
+ return NULL;
+}
+
+/**
+ * Identify X.509 certificate by corresponding public key
+ *
+ * @v certs X.509 certificate list
+ * @v key Private key
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * x509_find_key ( struct x509_chain *certs,
+ struct private_key *key ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &certs->links, list ) {
+
+ /* Check public key */
+ cert = link->cert;
+ if ( pubkey_match ( cert->signature_algorithm->pubkey,
+ key->builder.data, key->builder.len,
+ cert->subject.public_key.raw.data,
+ cert->subject.public_key.raw.len ) == 0 )
+ return x509_found ( certs, cert );
}
return NULL;
diff --git a/src/include/ipxe/certstore.h b/src/include/ipxe/certstore.h
index ce96666cf..e276d6792 100644
--- a/src/include/ipxe/certstore.h
+++ b/src/include/ipxe/certstore.h
@@ -9,14 +9,10 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#include <ipxe/asn1.h>
#include <ipxe/x509.h>
-#include <ipxe/privkey.h>
extern struct x509_chain certstore;
-extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw );
-extern struct x509_certificate * certstore_find_key ( struct private_key *key );
extern void certstore_add ( struct x509_certificate *cert );
extern void certstore_del ( struct x509_certificate *cert );
diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h
index 87323cec0..612743a77 100644
--- a/src/include/ipxe/x509.h
+++ b/src/include/ipxe/x509.h
@@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
struct image;
+struct private_key;
/** An X.509 serial number */
struct x509_serial {
@@ -201,6 +202,13 @@ struct x509_chain {
struct refcnt refcnt;
/** List of links */
struct list_head links;
+ /** Mark certificate as found
+ *
+ * @v certs X.509 certificate list
+ * @v cert X.509 certificate
+ */
+ void ( * found ) ( struct x509_chain *certs,
+ struct x509_certificate *cert );
};
/** An X.509 certificate */
@@ -424,6 +432,17 @@ extern int x509_append ( struct x509_chain *chain,
extern int x509_append_raw ( struct x509_chain *chain, const void *data,
size_t len );
extern void x509_truncate ( struct x509_chain *chain, struct x509_link *link );
+extern struct x509_certificate * x509_find ( struct x509_chain *certs,
+ const struct asn1_cursor *raw );
+extern struct x509_certificate *
+x509_find_subject ( struct x509_chain *certs,
+ const struct asn1_cursor *subject );
+extern struct x509_certificate *
+x509_find_issuer_serial ( struct x509_chain *certs,
+ const struct asn1_cursor *issuer,
+ const struct asn1_cursor *serial );
+extern struct x509_certificate * x509_find_key ( struct x509_chain *certs,
+ struct private_key *key );
extern int x509_auto_append ( struct x509_chain *chain,
struct x509_chain *certs );
extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
diff --git a/src/net/tls.c b/src/net/tls.c
index 5f89be452..98414e2b1 100644
--- a/src/net/tls.c
+++ b/src/net/tls.c
@@ -2467,7 +2467,7 @@ static int tls_new_certificate_request ( struct tls_connection *tls,
tls->certs = NULL;
/* Determine client certificate to be sent */
- cert = certstore_find_key ( tls->key );
+ cert = x509_find_key ( &certstore, tls->key );
if ( ! cert ) {
DBGC ( tls, "TLS %p could not find certificate corresponding "
"to private key\n", tls );