]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Allow private key to be specified as a TLS connection parameter
authorMichael Brown <mcb30@ipxe.org>
Tue, 15 Dec 2020 16:11:34 +0000 (16:11 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 15 Dec 2020 16:54:06 +0000 (16:54 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/certstore.c
src/crypto/privkey.c
src/include/ipxe/certstore.h
src/include/ipxe/privkey.h
src/include/ipxe/tls.h
src/net/tcp/https.c
src/net/tcp/syslogs.c
src/net/tls.c

index cdf6fb4dd2ff8e7503bd456fc3839ac4e99a10d1..2676c7e1e5e73b24a61cdb2cce7bd7ed5475c0d1 100644 (file)
@@ -116,13 +116,13 @@ struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) {
  * @v key              Private key
  * @ret cert           X.509 certificate, or NULL if not found
  */
-struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) {
+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->data, key->len,
+                                   key->builder.data, key->builder.len,
                                    cert->subject.public_key.raw.data,
                                    cert->subject.public_key.raw.len ) == 0 )
                        return certstore_found ( cert );
index 7ef04880f67d2151c2afd98245ccc00fea7fad96..c15edf1304d9cc89d742026dd717ce3ccb2f141b 100644 (file)
@@ -64,9 +64,12 @@ __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t"
          ".previous\n\t" );
 
 /** Private key */
-struct asn1_cursor private_key = {
-       .data = private_key_data,
-       .len = ( ( size_t ) private_key_len ),
+struct private_key private_key = {
+       .refcnt = REF_INIT ( ref_no_free ),
+       .builder = {
+               .data = private_key_data,
+               .len = ( ( size_t ) private_key_len ),
+       },
 };
 
 /** Default private key */
@@ -83,6 +86,19 @@ static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = {
        .type = &setting_type_hex,
 };
 
+/**
+ * Free private key
+ *
+ * @v refcnt           Reference counter
+ */
+void privkey_free ( struct refcnt *refcnt ) {
+       struct private_key *key =
+               container_of ( refcnt, struct private_key, refcnt );
+
+       free ( key->builder.data );
+       free ( key );
+}
+
 /**
  * Apply private key configuration settings
  *
@@ -98,23 +114,24 @@ static int privkey_apply_settings ( void ) {
        if ( ALLOW_KEY_OVERRIDE ) {
 
                /* Restore default private key */
-               memcpy ( &private_key, &default_private_key,
-                        sizeof ( private_key ) );
+               memcpy ( &private_key.builder, &default_private_key,
+                        sizeof ( private_key.builder ) );
 
                /* Fetch new private key, if any */
                free ( key_data );
                if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting,
                                                      &key_data ) ) >= 0 ) {
-                       private_key.data = key_data;
-                       private_key.len = len;
+                       private_key.builder.data = key_data;
+                       private_key.builder.len = len;
                }
        }
 
        /* Debug */
-       if ( private_key.len ) {
+       if ( private_key.builder.len ) {
                DBGC ( &private_key, "PRIVKEY using %s private key:\n",
                       ( key_data ? "external" : "built-in" ) );
-               DBGC_HDA ( &private_key, 0, private_key.data, private_key.len );
+               DBGC_HDA ( &private_key, 0, private_key.builder.data,
+                          private_key.builder.len );
        } else {
                DBGC ( &private_key, "PRIVKEY has no private key\n" );
        }
index e4c789cfdcf1fc4baa0d5117caf6635417c571e9..ce96666cf9e351bee34b4ce34f199588f7fb4ce2 100644 (file)
@@ -11,11 +11,12 @@ 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 asn1_cursor *key );
+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 81108b6bf3ef0b68e459adc30b76ce890a821166..a65cf61062b24199919a8e9bf8f2fa43796e6210 100644 (file)
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <ipxe/asn1.h>
+#include <ipxe/refcnt.h>
 
-extern struct asn1_cursor private_key;
+/** A private key */
+struct private_key {
+       /** Reference counter */
+       struct refcnt refcnt;
+       /** ASN.1 object builder */
+       struct asn1_builder builder;
+};
+
+/**
+ * Get reference to private key
+ *
+ * @v key              Private key
+ * @ret key            Private key
+ */
+static inline __attribute__ (( always_inline )) struct private_key *
+privkey_get ( struct private_key *key ) {
+       ref_get ( &key->refcnt );
+       return key;
+}
+
+/**
+ * Drop reference to private key
+ *
+ * @v key              Private key
+ */
+static inline __attribute__ (( always_inline )) void
+privkey_put ( struct private_key *key ) {
+       ref_put ( &key->refcnt );
+}
+
+/**
+ * Get private key ASN.1 cursor
+ *
+ * @v key              Private key
+ * @ret cursor         ASN.1 cursor
+ */
+static inline __attribute__ (( always_inline )) struct asn1_cursor *
+privkey_cursor ( struct private_key *key ) {
+       return asn1_built ( &key->builder );
+}
+
+extern void privkey_free ( struct refcnt *refcnt );
+
+/**
+ * Initialise empty private key
+ *
+ */
+static inline __attribute__ (( always_inline )) void
+privkey_init ( struct private_key *key ) {
+       ref_init ( &key->refcnt, privkey_free );
+}
+
+extern struct private_key private_key;
 
 #endif /* _IPXE_PRIVKEY_H */
index 8345c9a260ffbbd2eacb83980264e63e08e08269..8b03579cc6c10c4f6e289b2068a7398bcba95c8e 100644 (file)
@@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/sha1.h>
 #include <ipxe/sha256.h>
 #include <ipxe/x509.h>
+#include <ipxe/privkey.h>
 #include <ipxe/pending.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/tables.h>
@@ -257,6 +258,8 @@ struct tls_session {
        const char *name;
        /** Root of trust */
        struct x509_root *root;
+       /** Private key */
+       struct private_key *key;
 
        /** Session ID */
        uint8_t id[32];
@@ -322,6 +325,8 @@ struct tls_connection {
        struct digest_algorithm *handshake_digest;
        /** Digest algorithm context used for handshake verification */
        uint8_t *handshake_ctx;
+       /** Private key */
+       struct private_key *key;
        /** Client certificate chain (if used) */
        struct x509_chain *certs;
        /** Secure renegotiation flag */
@@ -384,6 +389,6 @@ struct tls_connection {
 #define TLS_RX_ALIGN 16
 
 extern int add_tls ( struct interface *xfer, const char *name,
-                    struct x509_root *root );
+                    struct x509_root *root, struct private_key *key );
 
 #endif /* _IPXE_TLS_H */
index eae8ae5dc62c1b9803143342e900d1c01eba30e5..85f1f124ff7d6a1c0d46c7f925b779b9c83e4090 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, NULL );
+       return add_tls ( &conn->socket, conn->uri->host, NULL, NULL );
 }
 
 /** HTTPS URI opener */
index f91864a4407926b230f1317bfe0310a309bf9d45..f1f70d59e85ce8981b84e0882af3b838ff6c0d09 100644 (file)
@@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) {
        }
 
        /* Add TLS filter */
-       if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) {
+       if ( ( rc = add_tls ( &syslogs, server, NULL, NULL ) ) != 0 ) {
                DBG ( "SYSLOGS cannot create TLS filter: %s\n",
                      strerror ( rc ) );
                goto err_add_tls;
index 046378392838855ad5b2169a483716db33f1b350..3c414445086e8a985ed9667c9dea1c7463fd44f6 100644 (file)
@@ -352,6 +352,7 @@ static void free_tls_session ( struct refcnt *refcnt ) {
 
        /* Free dynamically-allocated resources */
        x509_root_put ( session->root );
+       privkey_put ( session->key );
        free ( session->ticket );
 
        /* Free session */
@@ -383,6 +384,7 @@ static void free_tls ( struct refcnt *refcnt ) {
        x509_chain_put ( tls->certs );
        x509_chain_put ( tls->chain );
        x509_root_put ( tls->root );
+       privkey_put ( tls->key );
 
        /* Drop reference to session */
        assert ( list_empty ( &tls->list ) );
@@ -1259,6 +1261,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
        struct digest_algorithm *digest = tls->handshake_digest;
        struct x509_certificate *cert = x509_first ( tls->certs );
        struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
+       struct asn1_cursor *key = privkey_cursor ( tls->key );
        uint8_t digest_out[ digest->digestsize ];
        uint8_t ctx[ pubkey->ctxsize ];
        struct tls_signature_hash_algorithm *sig_hash = NULL;
@@ -1268,8 +1271,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
        tls_verify_handshake ( tls, digest_out );
 
        /* Initialise public-key algorithm */
-       if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data,
-                                 private_key.len ) ) != 0 ) {
+       if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not initialise %s client private "
                       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
                goto err_pubkey_init;
@@ -1876,7 +1878,7 @@ static int tls_new_certificate_request ( struct tls_connection *tls,
        tls->certs = NULL;
 
        /* Determine client certificate to be sent */
-       cert = certstore_find_key ( &private_key );
+       cert = certstore_find_key ( tls->key );
        if ( ! cert ) {
                DBGC ( tls, "TLS %p could not find certificate corresponding "
                       "to private key\n", tls );
@@ -3100,7 +3102,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
        /* Find existing matching session, if any */
        list_for_each_entry ( session, &tls_sessions, list ) {
                if ( ( strcmp ( name, session->name ) == 0 ) &&
-                    ( tls->root == session->root ) ) {
+                    ( tls->root == session->root ) &&
+                    ( tls->key == session->key ) ) {
                        ref_get ( &session->refcnt );
                        tls->session = session;
                        DBGC ( tls, "TLS %p joining session %s\n", tls, name );
@@ -3120,6 +3123,7 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
        strcpy ( name_copy, name );
        session->name = name_copy;
        session->root = x509_root_get ( tls->root );
+       session->key = privkey_get ( tls->key );
        INIT_LIST_HEAD ( &session->conn );
        list_add ( &session->list, &tls_sessions );
 
@@ -3147,10 +3151,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)
+ * @v key              Private key (or NULL to use default)
  * @ret rc             Return status code
  */
 int add_tls ( struct interface *xfer, const char *name,
-             struct x509_root *root ) {
+             struct x509_root *root, struct private_key *key ) {
        struct tls_connection *tls;
        int rc;
 
@@ -3168,6 +3173,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->key = privkey_get ( key ? key : &private_key );
        tls->root = x509_root_get ( root ? root : &root_certificates );
        tls->version = TLS_VERSION_TLS_1_2;
        tls_clear_cipher ( tls, &tls->tx_cipherspec );