aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/net/tls.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/src/net/tls.c b/src/net/tls.c
index 8a3ac3eed..0e3e68b6b 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;