mirror of
https://github.com/ipxe/ipxe
synced 2026-10-07 15:05:42 +03:00
[tls] Allow for sequential cipher initialisation vectors
The CBC ciphers require a fully unpredictable initialisation vector, which we currently generate as a channel ephemeral secret. The GCM ciphers require only a unique initialisation vector: there is no requirement for it also to be unpredictable. The content of the record IV portion of the IV is a free choice of the sender, and we currently use an unpredictable value for both CBC and GCM. TLS version 1.3 removes the record IV portion for GCM ciphers, instead constructing the IV by XORing the sequence number into the end of the fixed IV. Define the concept of a sequential initialisation vector as meaning that the sequence number is XORed into the end of the overall initialisation vector (which may be either the fixed IV or the record IV portion), with no per-record unpredictable value required. This allows us to represent the mechanism required for TLS version 1.3, and avoid the unnecessary cost of generating a channel ephemeral secret for a GCM cipher under TLS version 1.2. On the receive side, the XORed portion may be overwritten by the real record IV, since the sender's choice is always definitive for the contents of the record IV. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -33,9 +33,10 @@ FILE_SECBOOT ( PERMITTED );
|
||||
struct tls_cipher_suite tls_aes_128_gcm_sha256 __tls_cipher_suite ( 31 ) = {
|
||||
.code = htons ( TLS_AES_128_GCM_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.fixed_iv_len = 12,
|
||||
.record_iv_len = 0,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_null_exchange_algorithm,
|
||||
.pubkey = &pubkey_null,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -33,9 +33,10 @@ FILE_SECBOOT ( PERMITTED );
|
||||
struct tls_cipher_suite tls_aes_256_gcm_sha384 __tls_cipher_suite ( 32 ) = {
|
||||
.code = htons ( TLS_AES_256_GCM_SHA384 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.fixed_iv_len = 12,
|
||||
.record_iv_len = 0,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_null_exchange_algorithm,
|
||||
.pubkey = &pubkey_null,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -39,6 +39,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -54,6 +55,7 @@ tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -53,6 +54,7 @@ tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_dhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -39,6 +39,7 @@ tls_ecdhe_ecdsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -54,6 +55,7 @@ tls_ecdhe_ecdsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_ecdsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_ecdsa_with_aes_256_cbc_sha384 __tls_cipher_suite ( 04 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA384_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_ecdsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &ecdsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -39,6 +39,7 @@ tls_ecdhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -54,6 +55,7 @@ tls_ecdhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_rsa_with_aes_256_cbc_sha384 __tls_cipher_suite ( 04 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA384_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_ecdhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_ecdhe_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -39,6 +39,7 @@ tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 25 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -54,6 +55,7 @@ tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 26 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA1_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 23 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
@@ -53,6 +54,7 @@ tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 24 ) = {
|
||||
.fixed_iv_len = 0,
|
||||
.record_iv_len = AES_BLOCKSIZE,
|
||||
.mac_len = SHA256_DIGEST_SIZE,
|
||||
.flags = 0,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 21 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -38,6 +38,7 @@ tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 22 ) = {
|
||||
.fixed_iv_len = 4,
|
||||
.record_iv_len = 8,
|
||||
.mac_len = 0,
|
||||
.flags = TLS_CIPHER_FL_SEQUENTIAL_IV,
|
||||
.exchange = &tls_pubkey_exchange_algorithm,
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_gcm_algorithm,
|
||||
|
||||
@@ -283,8 +283,13 @@ struct tls_cipher_suite {
|
||||
uint8_t record_iv_len;
|
||||
/** MAC length */
|
||||
uint8_t mac_len;
|
||||
/** Flags */
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
/** Cipher XORs sequence number into the initialisation vector */
|
||||
#define TLS_CIPHER_FL_SEQUENTIAL_IV 0x01
|
||||
|
||||
/** TLS cipher suite table */
|
||||
#define TLS_CIPHER_SUITES \
|
||||
__table ( struct tls_cipher_suite, "tls_cipher_suites" )
|
||||
|
||||
+42
-12
@@ -275,6 +275,21 @@ static void tls_set_uint24 ( tls24_t *field24, unsigned long value ) {
|
||||
field24->low = cpu_to_be16 ( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* XOR data block
|
||||
*
|
||||
* @v dst Destination data
|
||||
* @v src Source data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void tls_xor ( void *dst, const void *src, size_t len ) {
|
||||
const uint8_t *src_bytes = src;
|
||||
uint8_t *dst_bytes = dst;
|
||||
|
||||
while ( len-- )
|
||||
*(dst_bytes++) ^= *(src_bytes++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if TLS connection is ready for application data
|
||||
*
|
||||
@@ -3476,7 +3491,7 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type,
|
||||
struct cipher_algorithm *cipher = pipe->cipher;
|
||||
struct {
|
||||
uint8_t fixed[suite->fixed_iv_len];
|
||||
uint8_t rec[suite->record_iv_len];
|
||||
uint8_t record[suite->record_iv_len];
|
||||
} __attribute__ (( packed )) iv;
|
||||
struct tls_auth_header authhdr;
|
||||
struct tls_header *tlshdr;
|
||||
@@ -3520,9 +3535,17 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type,
|
||||
|
||||
/* Construct and set initialisation vector */
|
||||
memcpy ( iv.fixed, cipherspec->fixed_iv, sizeof ( iv.fixed ) );
|
||||
if ( suite->flags & TLS_CIPHER_FL_SEQUENTIAL_IV ) {
|
||||
memset ( iv.record, 0, sizeof ( iv.record ) );
|
||||
assert ( sizeof ( iv ) >= sizeof ( authhdr.seq ) );
|
||||
tls_xor ( ( ( ( void * ) &iv ) + sizeof ( iv )
|
||||
- sizeof ( authhdr.seq ) ),
|
||||
&authhdr.seq, sizeof ( authhdr.seq ) );
|
||||
} else {
|
||||
channel_ephemeral ( &tls->channel, &authhdr,
|
||||
sizeof ( authhdr ), iv.rec,
|
||||
sizeof ( iv.rec ) );
|
||||
sizeof ( authhdr ), iv.record,
|
||||
sizeof ( iv.record ) );
|
||||
}
|
||||
if ( ( rc = cipher_setiv ( cipher, pipe->ctx, &iv,
|
||||
sizeof ( iv ) ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not set TX IV: %s\n",
|
||||
@@ -3554,12 +3577,12 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type,
|
||||
tlshdr = iob_put ( iobuf, sizeof ( *tlshdr ) );
|
||||
tlshdr->type = type;
|
||||
tlshdr->version = htons ( tls->legacy_version );
|
||||
tlshdr->length = htons ( sizeof ( iv.rec ) + encrypt_len +
|
||||
tlshdr->length = htons ( sizeof ( iv.record ) + encrypt_len +
|
||||
cipher->authsize );
|
||||
|
||||
/* Add record initialisation vector, if applicable */
|
||||
memcpy ( iob_put ( iobuf, sizeof ( iv.rec ) ), iv.rec,
|
||||
sizeof ( iv.rec ) );
|
||||
memcpy ( iob_put ( iobuf, sizeof ( iv.record ) ), iv.record,
|
||||
sizeof ( iv.record ) );
|
||||
|
||||
/* Copy plaintext data if necessary */
|
||||
ciphertext = iob_put ( iobuf, record_len );
|
||||
@@ -3712,6 +3735,11 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
|
||||
first = list_first_entry ( rx_data, struct io_buffer, list );
|
||||
last = list_last_entry ( rx_data, struct io_buffer, list );
|
||||
|
||||
/* Construct authentication data (excluding length) */
|
||||
authhdr.seq = cpu_to_be64 ( cipherspec->seq++ );
|
||||
authhdr.header.type = tlshdr->type;
|
||||
authhdr.header.version = tlshdr->version;
|
||||
|
||||
/* Extract initialisation vector */
|
||||
if ( iob_len ( first ) < sizeof ( iv.record ) ) {
|
||||
DBGC ( tls, "TLS %p received underlength IV\n", tls );
|
||||
@@ -3719,6 +3747,13 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
|
||||
return -EINVAL_IV;
|
||||
}
|
||||
memcpy ( iv.fixed, cipherspec->fixed_iv, sizeof ( iv.fixed ) );
|
||||
if ( suite->flags & TLS_CIPHER_FL_SEQUENTIAL_IV ) {
|
||||
memset ( iv.record, 0, sizeof ( iv.record ) );
|
||||
assert ( sizeof ( iv ) >= sizeof ( authhdr.seq ) );
|
||||
tls_xor ( ( ( ( void * ) &iv ) + sizeof ( iv ) -
|
||||
sizeof ( authhdr.seq ) ), &authhdr.seq,
|
||||
sizeof ( authhdr.seq ) );
|
||||
}
|
||||
memcpy ( iv.record, first->data, sizeof ( iv.record ) );
|
||||
iob_pull ( first, sizeof ( iv.record ) );
|
||||
len -= sizeof ( iv.record );
|
||||
@@ -3734,12 +3769,6 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
|
||||
len -= cipher->authsize;
|
||||
auth = last->tail;
|
||||
|
||||
/* Construct authentication data */
|
||||
authhdr.seq = cpu_to_be64 ( cipherspec->seq++ );
|
||||
authhdr.header.type = tlshdr->type;
|
||||
authhdr.header.version = tlshdr->version;
|
||||
authhdr.header.length = htons ( len );
|
||||
|
||||
/* Set initialisation vector */
|
||||
if ( ( rc = cipher_setiv ( cipher, pipe->ctx, &iv,
|
||||
sizeof ( iv ) ) ) != 0 ) {
|
||||
@@ -3749,6 +3778,7 @@ static int tls_new_ciphertext ( struct tls_connection *tls,
|
||||
}
|
||||
|
||||
/* Process authentication data, if applicable */
|
||||
authhdr.header.length = htons ( len );
|
||||
if ( is_auth_cipher ( cipher ) ) {
|
||||
cipher_decrypt ( cipher, pipe->ctx, &authhdr,
|
||||
NULL, sizeof ( authhdr ) );
|
||||
|
||||
Reference in New Issue
Block a user