[tls] Separate the concepts of key schedule and secure channel In preparation for delegating the separate but related concepts of a secure channel and a TLS key schedule, split these into separate data structures. Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 682f2e1..a45403c 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h
@@ -378,17 +378,9 @@ /** HKDF algorithm for ephemeral secrets */ #define tls_ephemeral_algorithm sha256_algorithm -/** TLS key schedule */ -struct tls_key_schedule { - /** Digest algorithm - * - * This is the digest algorithm specified by the cipher suite. - * It is used to construct the handshake running transcript - * digest value, and as the HMAC digest algorithm for key - * derivation. - */ - struct digest_algorithm *digest; - /** Schedule holds secret key material +/** TLS secure channel */ +struct tls_secure_channel { + /** Key schedule holds secret key material * * This flag is set when shared secret key material is * introduced into the schedule (e.g. when the TLS pre-master @@ -401,7 +393,7 @@ * reset. */ int keyed; - /** Server identity to which the schedule has been bound (if any) + /** Server identity to which the key schedule has been bound (if any) * * This reference to the server certificate is set when the * shared secret key material has been bound to the identity @@ -463,6 +455,20 @@ * current value. */ struct x509_certificate *bound; + /** Ephemeral master secret */ + uint8_t ephemeral[SHA256_DIGEST_SIZE]; +}; + +/** TLS key schedule */ +struct tls_key_schedule { + /** Digest algorithm + * + * This is the digest algorithm specified by the cipher suite. + * It is used to construct the handshake running transcript + * digest value, and as the HMAC digest algorithm for key + * derivation. + */ + struct digest_algorithm *digest; /** Dynamically-allocated storage */ void *dynamic; /** Handshake running transcript digest context */ @@ -471,8 +477,6 @@ void *kdf; /** Length of key derivation function secret */ size_t kdfsize; - /** Ephemeral master secret */ - uint8_t ephemeral[SHA256_DIGEST_SIZE]; }; /** TLS transmit state */ @@ -567,6 +571,8 @@ /** Verification data */ struct tls_verify_data verify; + /** Secure channel */ + struct tls_secure_channel channel; /** Key schedule */ struct tls_key_schedule key; /** Transmit state */
diff --git a/src/net/tls.c b/src/net/tls.c index e2a1b60..240633f 100644 --- a/src/net/tls.c +++ b/src/net/tls.c
@@ -423,7 +423,7 @@ * @ret rc Return status code */ static int tls_generate_ephemeral_master ( struct tls_connection *tls ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct digest_algorithm *digest = &tls_ephemeral_algorithm; static const char salt[16] = "ephemeral master"; int rc; @@ -431,16 +431,16 @@ /* Generate random bits with no additional input and without * prediction resistance */ - if ( ( rc = rbg_generate ( NULL, 0, 0, key->ephemeral, - sizeof ( key->ephemeral ) ) ) != 0 ) { + if ( ( rc = rbg_generate ( NULL, 0, 0, channel->ephemeral, + sizeof ( channel->ephemeral ) ) ) != 0 ) { DBGC ( tls, "TLS %p could not generate random data: %s\n", tls, strerror ( rc ) ); return rc; } /* Generate ephemeral master secret */ - hkdf_extract ( digest, salt, sizeof ( salt ), key->ephemeral, - sizeof ( key->ephemeral ), key->ephemeral ); + hkdf_extract ( digest, salt, sizeof ( salt ), channel->ephemeral, + sizeof ( channel->ephemeral ), channel->ephemeral ); return 0; } @@ -456,11 +456,11 @@ */ static void tls_ephemeral ( struct tls_connection *tls, const void *info, size_t info_len, void *out, size_t len ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct digest_algorithm *digest = &tls_ephemeral_algorithm; /* Generate from ephemeral master secret and additional information */ - hkdf_expand ( digest, key->ephemeral, info, info_len, out, len ); + hkdf_expand ( digest, channel->ephemeral, info, info_len, out, len ); } /** @@ -486,11 +486,11 @@ * @v tls TLS connection */ static void tls_regenerate_ephemeral_master ( struct tls_connection *tls ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; /* Derive a new ephemeral master secret */ - tls_ephemeral_label ( tls, "key reset", key->ephemeral, - sizeof ( key->ephemeral ) ); + tls_ephemeral_label ( tls, "key reset", channel->ephemeral, + sizeof ( channel->ephemeral ) ); /* (Re)generate client random bytes */ tls_ephemeral_label ( tls, "client random", &tls->client.random.random, @@ -503,11 +503,11 @@ * @v tls TLS connection */ static void tls_clear_binding ( struct tls_connection *tls ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; /* Clear any existing binding */ - x509_put ( key->bound ); - key->bound = NULL; + x509_put ( channel->bound ); + channel->bound = NULL; } /** @@ -518,19 +518,19 @@ */ static void tls_set_binding ( struct tls_connection *tls, struct x509_certificate *cert ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; /* Clear any existing binding */ tls_clear_binding ( tls ); /* Refuse to bind an empty shared secret */ - if ( ! key->keyed ) { + if ( ! channel->keyed ) { DBGC ( tls, "TLS %p refusing empty binding\n", tls ); return; } /* Bind to new identity */ - key->bound = x509_get ( cert ); + channel->bound = x509_get ( cert ); DBGC ( tls, "TLS %p bound to %s\n", tls, x509_name ( cert ) ); } @@ -540,6 +540,7 @@ * @v tls TLS connection */ static void tls_clear_digest ( struct tls_connection *tls ) { + struct tls_secure_channel *channel = &tls->channel; struct tls_key_schedule *key = &tls->key; /* Set null digest algorithm */ @@ -554,7 +555,7 @@ /* Key schedule no longer contains any shared secret */ tls_clear_binding ( tls ); - key->keyed = 0; + channel->keyed = 0; } /** @@ -566,6 +567,7 @@ */ static int tls_set_digest ( struct tls_connection *tls, struct digest_algorithm *digest ) { + struct tls_secure_channel *channel = &tls->channel; struct tls_key_schedule *key = &tls->key; size_t kdfsize; size_t total; @@ -602,8 +604,8 @@ tls_ephemeral_label ( tls, "kdf poison", key->kdf, kdfsize ); /* Sanity checks */ - assert ( ! key->keyed ); - assert ( ! key->bound ); + assert ( ! channel->keyed ); + assert ( ! channel->bound ); return 0; } @@ -804,14 +806,15 @@ * The client and server random values must already be known. */ static int tls_generate_master_secret ( struct tls_connection *tls ) { + struct tls_secure_channel *channel = &tls->channel; struct tls_key_schedule *key = &tls->key; struct digest_algorithm *digest = key->digest; uint8_t digest_out[ digest->digestsize ]; uint8_t master_secret[48]; /* Sanity checks */ - assert ( key->keyed ); - assert ( key->bound ); + assert ( channel->keyed ); + assert ( channel->bound ); /* Generate handshake digest */ tls_verify_handshake ( tls, digest_out ); @@ -868,8 +871,8 @@ int rc; /* Sanity checks */ - assert ( tls->key.keyed ); - assert ( tls->key.bound ); + assert ( tls->channel.keyed ); + assert ( tls->channel.bound ); /* Generate key block */ tls_prf_label ( tls, key_block, sizeof ( key_block ), "key expansion", @@ -939,6 +942,7 @@ */ static void tls_generate_resumption_master ( struct tls_connection *tls ) { struct tls_session *session = tls->session; + struct tls_secure_channel *channel = &tls->channel; struct tls_key_schedule *key = &tls->key; struct digest_algorithm *digest = key->digest; struct md5_sha1_hmac_keys *hkeys; @@ -951,9 +955,9 @@ } *secret; /* Sanity checks */ - assert ( key->keyed ); - assert ( key->bound ); - assert ( x509_is_valid ( key->bound, tls->server.root ) ); + assert ( channel->keyed ); + assert ( channel->bound ); + assert ( x509_is_valid ( channel->bound, tls->server.root ) ); assert ( sizeof ( *secret ) <= sizeof ( session->resumption_master_secret ) ); secret = ( ( void * ) session->resumption_master_secret ); @@ -999,7 +1003,7 @@ */ static void tls_resume_secret ( struct tls_connection *tls ) { struct tls_session *session = tls->session; - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; size_t len = session->resumption_master_secret_len; /* For TLSv1.2 and earlier, the resumption master secret is @@ -1016,7 +1020,7 @@ * schedule no longer contains any shared secret. */ assert ( len ); - key->keyed = len; + channel->keyed = len; tls_set_binding ( tls, session->cert ); } @@ -1540,7 +1544,7 @@ */ static int tls_key_agree ( struct tls_connection *tls, const void *partner, size_t len ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct exchange_algorithm *exchange = tls->exchange; size_t privsize = exchange->privsize; size_t pubsize = exchange->pubsize; @@ -1615,7 +1619,7 @@ tls_clear_binding ( tls ); /* Key schedule now contains shared secret key material */ - key->keyed = 1; + channel->keyed = 1; err_agree: err_pad: @@ -1634,7 +1638,7 @@ */ static int tls_key_encrypt ( struct tls_connection *tls, struct asn1_builder *builder ) { - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct exchange_algorithm *exchange = tls->exchange; size_t privsize = exchange->privsize; size_t sharedsize = exchange->sharedsize; @@ -1694,7 +1698,7 @@ tls_clear_binding ( tls ); /* Key schedule now contains shared secret key material */ - key->keyed = 1; + channel->keyed = 1; /* Encrypt shared secret */ plaintext.data = tmp->shared; @@ -2247,7 +2251,7 @@ */ static int tls_send_finished ( struct tls_connection *tls ) { struct digest_algorithm *digest = tls->key.digest; - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct { uint32_t type_length; uint8_t verify_data[ sizeof ( tls->verify.client ) ]; @@ -2256,8 +2260,8 @@ int rc; /* Fail unless bound identity has been validated */ - if ( ! ( key->bound && - x509_is_valid ( key->bound, tls->server.root ) ) ) { + if ( ! ( channel->bound && + x509_is_valid ( channel->bound, tls->server.root ) ) ) { DBGC ( tls, "TLS %p bound identity is not valid\n", tls ); return -EPERM_BOUND; } @@ -2699,7 +2703,7 @@ /* Certificate has changed and so the key schedule is no * longer bound to the server identity. */ - tls->key.bound = 0; + tls->channel.bound = 0; /* Create certificate chain */ tls->server.chain = x509_alloc_chain(); @@ -3054,7 +3058,7 @@ static int tls_new_finished ( struct tls_connection *tls, const void *data, size_t len ) { struct tls_session *session = tls->session; - struct tls_key_schedule *key = &tls->key; + struct tls_secure_channel *channel = &tls->channel; struct digest_algorithm *digest = tls->key.digest; const struct { uint8_t verify_data[ sizeof ( tls->verify.server ) ]; @@ -3063,7 +3067,7 @@ uint8_t digest_out[ digest->digestsize ]; /* Sanity checks */ - if ( ! ( digest->digestsize && key->keyed && key->bound ) ) { + if ( ! ( digest->digestsize && channel->keyed && channel->bound ) ) { DBGC ( tls, "TLS %p received premature Finished\n", tls ); DBGC_HDA ( tls, 0, data, len ); return -EINVAL_FINISHED; @@ -3097,12 +3101,12 @@ } /* Record session ID, ticket, and master secret, if applicable */ - if ( x509_is_valid ( key->bound, tls->server.root ) && + if ( x509_is_valid ( channel->bound, tls->server.root ) && ( tls->session_id_len || tls->new_session_ticket_len ) ) { tls_generate_resumption_master ( tls ); session->extended_master_secret = tls->extended_master_secret; x509_put ( session->cert ); - session->cert = x509_get ( key->bound ); + session->cert = x509_get ( channel->bound ); if ( tls->session_id_len ) { session->id_len = tls->session_id_len; memcpy ( session->id, tls->session_id,