[tls] Abstract out concept of a TLS authentication header

All TLS cipher types use a common structure for the per-record data
that is authenticated in addition to the plaintext itself.  This data
is used as a prefix in the HMAC calculation for stream and block
ciphers, or as additional authenticated data for AEAD ciphers.

Define a "TLS authentication header" structure to hold this data as a
contiguous block, in order to meet the alignment requirement for AEAD
ciphers such as GCM.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2022-11-07 18:34:37 +00:00
parent 6a360ebfde
commit b6eef14858
2 changed files with 27 additions and 21 deletions

View File

@@ -122,6 +122,14 @@ struct tls_header {
/* TLS renegotiation information extension */ /* TLS renegotiation information extension */
#define TLS_RENEGOTIATION_INFO 0xff01 #define TLS_RENEGOTIATION_INFO 0xff01
/** TLS authentication header */
struct tls_auth_header {
/** Sequence number */
uint64_t seq;
/** TLS header */
struct tls_header header;
} __attribute__ (( packed ));
/** TLS verification data */ /** TLS verification data */
struct tls_verify_data { struct tls_verify_data {
/** Client verification data */ /** Client verification data */

View File

@@ -2521,17 +2521,14 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
* *
* @v cipherspec Cipher specification * @v cipherspec Cipher specification
* @v ctx Context * @v ctx Context
* @v seq Sequence number * @v authhdr Authentication header
* @v tlshdr TLS header
*/ */
static void tls_hmac_init ( struct tls_cipherspec *cipherspec, void *ctx, static void tls_hmac_init ( struct tls_cipherspec *cipherspec, void *ctx,
uint64_t seq, struct tls_header *tlshdr ) { struct tls_auth_header *authhdr ) {
struct digest_algorithm *digest = cipherspec->suite->digest; struct digest_algorithm *digest = cipherspec->suite->digest;
hmac_init ( digest, ctx, cipherspec->mac_secret, digest->digestsize ); hmac_init ( digest, ctx, cipherspec->mac_secret, digest->digestsize );
seq = cpu_to_be64 ( seq ); hmac_update ( digest, ctx, authhdr, sizeof ( *authhdr ) );
hmac_update ( digest, ctx, &seq, sizeof ( seq ) );
hmac_update ( digest, ctx, tlshdr, sizeof ( *tlshdr ) );
} }
/** /**
@@ -2567,19 +2564,18 @@ static void tls_hmac_final ( struct tls_cipherspec *cipherspec, void *ctx,
* Calculate HMAC * Calculate HMAC
* *
* @v cipherspec Cipher specification * @v cipherspec Cipher specification
* @v seq Sequence number * @v authhdr Authentication header
* @v tlshdr TLS header
* @v data Data * @v data Data
* @v len Length of data * @v len Length of data
* @v mac HMAC to fill in * @v mac HMAC to fill in
*/ */
static void tls_hmac ( struct tls_cipherspec *cipherspec, static void tls_hmac ( struct tls_cipherspec *cipherspec,
uint64_t seq, struct tls_header *tlshdr, struct tls_auth_header *authhdr,
const void *data, size_t len, void *hmac ) { const void *data, size_t len, void *hmac ) {
struct digest_algorithm *digest = cipherspec->suite->digest; struct digest_algorithm *digest = cipherspec->suite->digest;
uint8_t ctx[ hmac_ctxsize ( digest ) ]; uint8_t ctx[ hmac_ctxsize ( digest ) ];
tls_hmac_init ( cipherspec, ctx, seq, tlshdr ); tls_hmac_init ( cipherspec, ctx, authhdr );
tls_hmac_update ( cipherspec, ctx, data, len ); tls_hmac_update ( cipherspec, ctx, data, len );
tls_hmac_final ( cipherspec, ctx, hmac ); tls_hmac_final ( cipherspec, ctx, hmac );
} }
@@ -2678,10 +2674,10 @@ static void * tls_assemble_block ( struct tls_connection *tls,
*/ */
static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
const void *data, size_t len ) { const void *data, size_t len ) {
struct tls_header plaintext_tlshdr;
struct tls_header *tlshdr;
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec; struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
struct cipher_algorithm *cipher = cipherspec->suite->cipher; struct cipher_algorithm *cipher = cipherspec->suite->cipher;
struct tls_auth_header authhdr;
struct tls_header *tlshdr;
void *plaintext = NULL; void *plaintext = NULL;
size_t plaintext_len; size_t plaintext_len;
struct io_buffer *ciphertext = NULL; struct io_buffer *ciphertext = NULL;
@@ -2691,12 +2687,13 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
int rc; int rc;
/* Construct header */ /* Construct header */
plaintext_tlshdr.type = type; authhdr.seq = cpu_to_be64 ( tls->tx_seq );
plaintext_tlshdr.version = htons ( tls->version ); authhdr.header.type = type;
plaintext_tlshdr.length = htons ( len ); authhdr.header.version = htons ( tls->version );
authhdr.header.length = htons ( len );
/* Calculate MAC */ /* Calculate MAC */
tls_hmac ( cipherspec, tls->tx_seq, &plaintext_tlshdr, data, len, mac ); tls_hmac ( cipherspec, &authhdr, data, len, mac );
/* Allocate and assemble plaintext struct */ /* Allocate and assemble plaintext struct */
if ( is_stream_cipher ( cipher ) ) { if ( is_stream_cipher ( cipher ) ) {
@@ -2852,10 +2849,10 @@ static int tls_split_block ( struct tls_connection *tls,
static int tls_new_ciphertext ( struct tls_connection *tls, static int tls_new_ciphertext ( struct tls_connection *tls,
struct tls_header *tlshdr, struct tls_header *tlshdr,
struct list_head *rx_data ) { struct list_head *rx_data ) {
struct tls_header plaintext_tlshdr;
struct tls_cipherspec *cipherspec = &tls->rx_cipherspec; struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
struct cipher_algorithm *cipher = cipherspec->suite->cipher; struct cipher_algorithm *cipher = cipherspec->suite->cipher;
struct digest_algorithm *digest = cipherspec->suite->digest; struct digest_algorithm *digest = cipherspec->suite->digest;
struct tls_auth_header authhdr;
uint8_t ctx[ hmac_ctxsize ( digest ) ]; uint8_t ctx[ hmac_ctxsize ( digest ) ];
uint8_t verify_mac[digest->digestsize]; uint8_t verify_mac[digest->digestsize];
struct io_buffer *iobuf; struct io_buffer *iobuf;
@@ -2886,10 +2883,11 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
} }
/* Verify MAC */ /* Verify MAC */
plaintext_tlshdr.type = tlshdr->type; authhdr.seq = cpu_to_be64 ( tls->rx_seq );
plaintext_tlshdr.version = tlshdr->version; authhdr.header.type = tlshdr->type;
plaintext_tlshdr.length = htons ( len ); authhdr.header.version = tlshdr->version;
tls_hmac_init ( cipherspec, ctx, tls->rx_seq, &plaintext_tlshdr ); authhdr.header.length = htons ( len );
tls_hmac_init ( cipherspec, ctx, &authhdr );
list_for_each_entry ( iobuf, rx_data, list ) { list_for_each_entry ( iobuf, rx_data, list ) {
tls_hmac_update ( cipherspec, ctx, iobuf->data, tls_hmac_update ( cipherspec, ctx, iobuf->data,
iob_len ( iobuf ) ); iob_len ( iobuf ) );