[tls] Add support for AEAD ciphers

Allow for AEAD cipher suites where the MAC length may be zero and the
authentication is instead provided by an authenticating cipher, with
the plaintext authentication tag appended to the ciphertext.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/801/head
Michael Brown 2022-11-08 14:29:08 +00:00
parent 186306d619
commit 54d83e92f0
1 changed files with 39 additions and 2 deletions

View File

@ -101,7 +101,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINVAL_MAC __einfo_error ( EINFO_EINVAL_MAC )
#define EINFO_EINVAL_MAC \
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
"Invalid MAC" )
"Invalid MAC or authentication tag" )
#define EINVAL_TICKET __einfo_error ( EINFO_EINVAL_TICKET )
#define EINFO_EINVAL_TICKET \
__einfo_uniqify ( EINFO_EINVAL, 0x0e, \
@ -2675,9 +2675,15 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
/* Set initialisation vector */
cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, sizeof ( iv ) );
/* Process authentication data, if applicable */
if ( is_auth_cipher ( cipher ) ) {
cipher_encrypt ( cipher, cipherspec->cipher_ctx, &authhdr,
NULL, sizeof ( authhdr ) );
}
/* Allocate ciphertext */
ciphertext_len = ( sizeof ( *tlshdr ) + sizeof ( iv.record ) +
plaintext_len );
plaintext_len + cipher->authsize );
ciphertext = xfer_alloc_iob ( &tls->cipherstream, ciphertext_len );
if ( ! ciphertext ) {
DBGC ( tls, "TLS %p could not allocate %zd bytes for "
@ -2695,6 +2701,8 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
sizeof ( iv.record ) );
cipher_encrypt ( cipher, cipherspec->cipher_ctx, plaintext,
iob_put ( ciphertext, plaintext_len ), plaintext_len );
cipher_auth ( cipher, cipherspec->cipher_ctx,
iob_put ( ciphertext, cipher->authsize ) );
assert ( iob_len ( ciphertext ) == ciphertext_len );
/* Free plaintext as soon as possible to conserve memory */
@ -2775,10 +2783,12 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
} __attribute__ (( packed )) iv;
struct tls_auth_header authhdr;
uint8_t verify_mac[digest->digestsize];
uint8_t verify_auth[cipher->authsize];
struct io_buffer *first;
struct io_buffer *last;
struct io_buffer *iobuf;
void *mac;
void *auth;
size_t check_len;
int pad_len;
int rc;
@ -2799,6 +2809,17 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
iob_pull ( first, sizeof ( iv.record ) );
len -= sizeof ( iv.record );
/* Extract unencrypted authentication tag */
if ( iob_len ( last ) < cipher->authsize ) {
DBGC ( tls, "TLS %p received underlength authentication tag\n",
tls );
DBGC_HD ( tls, last->data, iob_len ( last ) );
return -EINVAL_MAC;
}
iob_unput ( last, cipher->authsize );
len -= cipher->authsize;
auth = last->tail;
/* Construct authentication data */
authhdr.seq = cpu_to_be64 ( tls->rx_seq );
authhdr.header.type = tlshdr->type;
@ -2808,6 +2829,12 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
/* Set initialisation vector */
cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, sizeof ( iv ) );
/* Process authentication data, if applicable */
if ( is_auth_cipher ( cipher ) ) {
cipher_decrypt ( cipher, cipherspec->cipher_ctx, &authhdr,
NULL, sizeof ( authhdr ) );
}
/* Decrypt the received data */
check_len = 0;
list_for_each_entry ( iobuf, &tls->rx_data, list ) {
@ -2852,12 +2879,22 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
if ( suite->mac_len )
tls_hmac_list ( cipherspec, &authhdr, rx_data, verify_mac );
/* Generate authentication tag */
cipher_auth ( cipher, cipherspec->cipher_ctx, verify_auth );
/* Verify MAC */
if ( memcmp ( mac, verify_mac, suite->mac_len ) != 0 ) {
DBGC ( tls, "TLS %p failed MAC verification\n", tls );
return -EINVAL_MAC;
}
/* Verify authentication tag */
if ( memcmp ( auth, verify_auth, cipher->authsize ) != 0 ) {
DBGC ( tls, "TLS %p failed authentication tag verification\n",
tls );
return -EINVAL_MAC;
}
/* Process plaintext record */
if ( ( rc = tls_new_record ( tls, tlshdr->type, rx_data ) ) != 0 )
return rc;