diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-11-08 14:29:08 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-11-08 15:14:19 +0000 |
commit | 54d83e92f0989ca612c82e1a22d3be205a04ead9 (patch) | |
tree | 215f692e6c21fe7a258ab59b183b35ededa6eafd /src | |
parent | 186306d6199096b7a7c4b4574d4be8cdb8426729 (diff) | |
download | ipxe-54d83e92f0989ca612c82e1a22d3be205a04ead9.zip ipxe-54d83e92f0989ca612c82e1a22d3be205a04ead9.tar.gz ipxe-54d83e92f0989ca612c82e1a22d3be205a04ead9.tar.bz2 |
[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>
Diffstat (limited to 'src')
-rw-r--r-- | src/net/tls.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/src/net/tls.c b/src/net/tls.c index 8a3ac3e..0e3e68b 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -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; |