]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Centralise mechanisms for identifying X.509 certificates
authorMichael Brown <mcb30@ipxe.org>
Mon, 12 Aug 2024 11:26:52 +0000 (12:26 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 12 Aug 2024 11:38:08 +0000 (12:38 +0100)
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>
src/crypto/certstore.c
src/crypto/cms.c
src/crypto/x509.c
src/include/ipxe/certstore.h
src/include/ipxe/x509.h
src/net/tls.c

index 2676c7e1e5e73b24a61cdb2cce7bd7ed5475c0d1..f8ddbd3d7c5f7c6a24905d0a00ba7c179ea044a8 100644 (file)
@@ -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;
index 9511cec8abe87840a67ca10fa9001a7e8847cbeb..19a0ce7ad71dbacd4b6812fe96c94b419b15dde2 100644 (file)
@@ -143,34 +143,6 @@ static int cms_parse_certificates ( struct cms_signature *sig,
        return 0;
 }
 
-/**
- * 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
  *
@@ -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 );
index 92318093e0d3a15370d5685872d923fca00f7812..341b91449fe32a854fd158b7458b047948056998 100644 (file)
@@ -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 );
@@ -1710,6 +1711,47 @@ 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
  *
@@ -1717,7 +1759,7 @@ void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) {
  * @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;
index ce96666cf9e351bee34b4ce34f199588f7fb4ce2..e276d6792e3ffc7aeb6cb0b7f602ca60e0f558e0 100644 (file)
@@ -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 );
 
index 87323cec0538d865907ffe9e882acd187eb29c7f..612743a77584fe54d92c3b8e21c4e8020c1713dc 100644 (file)
@@ -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,
index 5f89be452f6224fe21bcd1842e46cfc4a6fcfc4b..98414e2b19a97f030bb5279eda0888ade9069320 100644 (file)
@@ -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 );