Skip to content

Commit

Permalink
ktls: add TLS1.3 support (aws#4314)
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart committed Dec 12, 2023
1 parent 72aa95d commit 0fb3769
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 80 deletions.
123 changes: 100 additions & 23 deletions crypto/s2n_aead_cipher_aes_gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ static int s2n_aead_cipher_aes_gcm_destroy_key(struct s2n_session_key *key)

#endif

static S2N_RESULT s2n_aead_cipher_aes128_gcm_set_ktls_info(struct s2n_ktls_crypto_info_inputs *in,
struct s2n_ktls_crypto_info *out)
static S2N_RESULT s2n_tls12_aead_cipher_aes128_gcm_set_ktls_info(
struct s2n_ktls_crypto_info_inputs *in, struct s2n_ktls_crypto_info *out)
{
RESULT_ENSURE_REF(in);
RESULT_ENSURE_REF(out);
Expand All @@ -389,29 +389,48 @@ static S2N_RESULT s2n_aead_cipher_aes128_gcm_set_ktls_info(struct s2n_ktls_crypt

RESULT_ENSURE_LTE(sizeof(crypto_info->key), in->key.size);
RESULT_CHECKED_MEMCPY(crypto_info->key, in->key.data, sizeof(crypto_info->key));

RESULT_ENSURE_LTE(sizeof(crypto_info->iv), in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->iv.data, sizeof(crypto_info->iv));

RESULT_ENSURE_LTE(sizeof(crypto_info->rec_seq), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->rec_seq, in->seq.data, sizeof(crypto_info->rec_seq));

/* The salt is a prefix of the IV
/* TLS1.2 uses partially explicit nonces. That means that although part of the
* nonce is still fixed and implicit (the salt), the remainder is explicit
* (written into the record) and must be unique per record. The RFC5288 suggests
* using the sequence number as the explicit part.
*
* Therefore, ktls expects the salt to contain the iv derived from the secret
* and should generate the remainder of the nonce per-record.
*
*= https://www.rfc-editor.org/rfc/rfc4106#section-4
*# The salt field is a four-octet value that is assigned at the
*# beginning of the security association, and then remains constant
*# for the life of the security association.
* See the TLS1.2 RFC:
* - https://datatracker.ietf.org/doc/html/rfc5246#section-6.2.3.3
* And RFC5288, which defines the TLS1.2 AES-GCM cipher suites:
* - https://datatracker.ietf.org/doc/html/rfc5288#section-3
*/
RESULT_ENSURE_LTE(sizeof(crypto_info->salt), in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->salt, in->iv.data, sizeof(crypto_info->salt));

/* Because TLS1.2 uses partially explicit nonces, the kernel should not
* use the iv in crypto_info but instead use a unique value for each record.
*
* As of this commit, Openssl has chosen to set the TLS1.2 IV to random
* bytes when sending and all zeroes when receiving:
* https://github.com/openssl/openssl/blob/de8e0851a1c0d22533801f081781a9f0be56c2c2/ssl/record/methods/ktls_meth.c#L197-L204
* And GnuTLS has chosen to set the TLS1.2 IV to the sequence number:
* https://github.com/gnutls/gnutls/blob/3f42ae70a1672673cb8f27c2dd3da1a34d1cbdd7/lib/system/ktls.c#L547-L550
*
* We (fairly arbitrarily) choose to also set it to the current sequence number.
*/
RESULT_ENSURE_LTE(sizeof(crypto_info->iv), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->seq.data, sizeof(crypto_info->iv));

RESULT_GUARD_POSIX(s2n_blob_init(&out->value, (uint8_t *) (void *) crypto_info,
sizeof(s2n_ktls_crypto_info_tls12_aes_gcm_128)));
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_aead_cipher_aes256_gcm_set_ktls_info(
/* TLS1.2 AES256 is configured like TLS1.2 AES128, but with a larger key size.
* See TLS1.2 AES128 for details (particularly a discussion of salt + iv).
*/
static S2N_RESULT s2n_tls12_aead_cipher_aes256_gcm_set_ktls_info(
struct s2n_ktls_crypto_info_inputs *in, struct s2n_ktls_crypto_info *out)
{
RESULT_ENSURE_REF(in);
Expand All @@ -423,22 +442,78 @@ static S2N_RESULT s2n_aead_cipher_aes256_gcm_set_ktls_info(

RESULT_ENSURE_LTE(sizeof(crypto_info->key), in->key.size);
RESULT_CHECKED_MEMCPY(crypto_info->key, in->key.data, sizeof(crypto_info->key));
RESULT_ENSURE_LTE(sizeof(crypto_info->rec_seq), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->rec_seq, in->seq.data, sizeof(crypto_info->rec_seq));
RESULT_ENSURE_LTE(sizeof(crypto_info->salt), in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->salt, in->iv.data, sizeof(crypto_info->salt));
RESULT_ENSURE_LTE(sizeof(crypto_info->iv), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->seq.data, sizeof(crypto_info->iv));

RESULT_ENSURE_LTE(sizeof(crypto_info->iv), in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->iv.data, sizeof(crypto_info->iv));
RESULT_GUARD_POSIX(s2n_blob_init(&out->value, (uint8_t *) (void *) crypto_info,
sizeof(s2n_ktls_crypto_info_tls12_aes_gcm_256)));
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_tls13_aead_cipher_aes128_gcm_set_ktls_info(
struct s2n_ktls_crypto_info_inputs *in, struct s2n_ktls_crypto_info *out)
{
RESULT_ENSURE_REF(in);
RESULT_ENSURE_REF(out);

s2n_ktls_crypto_info_tls12_aes_gcm_128 *crypto_info = &out->ciphers.aes_gcm_128;
crypto_info->info.version = TLS_1_3_VERSION;
crypto_info->info.cipher_type = TLS_CIPHER_AES_GCM_128;

RESULT_ENSURE_LTE(sizeof(crypto_info->key), in->key.size);
RESULT_CHECKED_MEMCPY(crypto_info->key, in->key.data, sizeof(crypto_info->key));
RESULT_ENSURE_LTE(sizeof(crypto_info->rec_seq), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->rec_seq, in->seq.data, sizeof(crypto_info->rec_seq));

/* The salt is a prefix of the IV
/* TLS1.3 uses fully implicit nonces. The fixed, implicit IV value derived from
* the secret is xored with the sequence number to produce a unique per-record nonce.
*
*= https://www.rfc-editor.org/rfc/rfc4106#section-4
*# The salt field is a four-octet value that is assigned at the
*# beginning of the security association, and then remains constant
*# for the life of the security association.
* See the TLS1.3 RFC:
* - https://www.rfc-editor.org/rfc/rfc8446.html#section-5.3
*
* ktls handles this with the same structure as TLS1.2 uses for its partially
* explicit nonces by splitting the implicit IV between the salt and iv fields.
*/
RESULT_ENSURE_LTE(sizeof(crypto_info->salt), in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->salt, in->iv.data, sizeof(crypto_info->salt));
size_t salt_size = sizeof(crypto_info->salt);
RESULT_ENSURE_LTE(salt_size, in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->salt, in->iv.data, salt_size);
size_t iv_remainder = in->iv.size - salt_size;
RESULT_ENSURE_LTE(sizeof(crypto_info->iv), iv_remainder);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->iv.data + salt_size, sizeof(crypto_info->iv));

RESULT_GUARD_POSIX(s2n_blob_init(&out->value, (uint8_t *) (void *) crypto_info,
sizeof(s2n_ktls_crypto_info_tls12_aes_gcm_128)));
return S2N_RESULT_OK;
}

/* TLS1.3 AES256 is configured like TLS1.3 AES128, but with a larger key size.
* See TLS1.3 AES128 for details (particularly a discussion of salt + iv).
*/
static S2N_RESULT s2n_tls13_aead_cipher_aes256_gcm_set_ktls_info(
struct s2n_ktls_crypto_info_inputs *in, struct s2n_ktls_crypto_info *out)
{
RESULT_ENSURE_REF(in);
RESULT_ENSURE_REF(out);

s2n_ktls_crypto_info_tls12_aes_gcm_256 *crypto_info = &out->ciphers.aes_gcm_256;
crypto_info->info.version = TLS_1_3_VERSION;
crypto_info->info.cipher_type = TLS_CIPHER_AES_GCM_256;

RESULT_ENSURE_LTE(sizeof(crypto_info->key), in->key.size);
RESULT_CHECKED_MEMCPY(crypto_info->key, in->key.data, sizeof(crypto_info->key));
RESULT_ENSURE_LTE(sizeof(crypto_info->rec_seq), in->seq.size);
RESULT_CHECKED_MEMCPY(crypto_info->rec_seq, in->seq.data, sizeof(crypto_info->rec_seq));

size_t salt_size = sizeof(crypto_info->salt);
RESULT_ENSURE_LTE(salt_size, in->iv.size);
RESULT_CHECKED_MEMCPY(crypto_info->salt, in->iv.data, salt_size);
size_t iv_remainder = in->iv.size - salt_size;
RESULT_ENSURE_LTE(sizeof(crypto_info->iv), iv_remainder);
RESULT_CHECKED_MEMCPY(crypto_info->iv, in->iv.data + salt_size, sizeof(crypto_info->iv));

RESULT_GUARD_POSIX(s2n_blob_init(&out->value, (uint8_t *) (void *) crypto_info,
sizeof(s2n_ktls_crypto_info_tls12_aes_gcm_256)));
Expand All @@ -459,7 +534,7 @@ const struct s2n_cipher s2n_aes128_gcm = {
.set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key,
.set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key,
.destroy_key = s2n_aead_cipher_aes_gcm_destroy_key,
.set_ktls_info = s2n_aead_cipher_aes128_gcm_set_ktls_info,
.set_ktls_info = s2n_tls12_aead_cipher_aes128_gcm_set_ktls_info,
};

const struct s2n_cipher s2n_aes256_gcm = {
Expand All @@ -476,7 +551,7 @@ const struct s2n_cipher s2n_aes256_gcm = {
.set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key,
.set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key,
.destroy_key = s2n_aead_cipher_aes_gcm_destroy_key,
.set_ktls_info = s2n_aead_cipher_aes256_gcm_set_ktls_info,
.set_ktls_info = s2n_tls12_aead_cipher_aes256_gcm_set_ktls_info,
};

/* TLS 1.3 GCM ciphers */
Expand All @@ -494,6 +569,7 @@ const struct s2n_cipher s2n_tls13_aes128_gcm = {
.set_encryption_key = s2n_aead_cipher_aes128_gcm_set_encryption_key_tls13,
.set_decryption_key = s2n_aead_cipher_aes128_gcm_set_decryption_key_tls13,
.destroy_key = s2n_aead_cipher_aes_gcm_destroy_key,
.set_ktls_info = s2n_tls13_aead_cipher_aes128_gcm_set_ktls_info,
};

const struct s2n_cipher s2n_tls13_aes256_gcm = {
Expand All @@ -510,4 +586,5 @@ const struct s2n_cipher s2n_tls13_aes256_gcm = {
.set_encryption_key = s2n_aead_cipher_aes256_gcm_set_encryption_key_tls13,
.set_decryption_key = s2n_aead_cipher_aes256_gcm_set_decryption_key_tls13,
.destroy_key = s2n_aead_cipher_aes_gcm_destroy_key,
.set_ktls_info = s2n_tls13_aead_cipher_aes256_gcm_set_ktls_info,
};
1 change: 1 addition & 0 deletions crypto/s2n_ktls_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
typedef struct tls12_crypto_info_aes_gcm_256 s2n_ktls_crypto_info_tls12_aes_gcm_256;
#else
#define TLS_1_2_VERSION 0
#define TLS_1_3_VERSION 0

#define TLS_CIPHER_AES_GCM_128 0
typedef struct s2n_ktls_crypto_info_stub s2n_ktls_crypto_info_tls12_aes_gcm_128;
Expand Down
17 changes: 9 additions & 8 deletions tests/features/S2N_KTLS_SUPPORTED.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@

int main()
{
/* Struct defined when kTLS support was added to linux
/* Initially ktls only supported AES-128 and TLS1.2:
* https://github.com/torvalds/linux/blob/3c4d7559159bfe1e3b94df3a657b2cda3a34e218/include/uapi/linux/tls.h
*
* However, for simplicity our ktls probe will also require AES-256 and TLS1.3.
* If this prevents some customers from using ktls, we can split our single ktls
* feature probe into more fine-grained feature probes.
*/
int versions[] = { TLS_1_2_VERSION, TLS_1_3_VERSION };
int cipher_types[] = { TLS_CIPHER_AES_GCM_128, TLS_CIPHER_AES_GCM_256 };

struct tls12_crypto_info_aes_gcm_128 aes_crypto_info_128 = { 0 };
int aes_gcm_128_cipher_type = TLS_CIPHER_AES_GCM_128;
struct tls12_crypto_info_aes_gcm_256 aes_crypto_info_256 = { 0 };
int aes_gcm_256_cipher_type = TLS_CIPHER_AES_GCM_256;
struct tls_crypto_info crypto_info = { 0 };

int get_record_type = TLS_GET_RECORD_TYPE;
int set_record_type = TLS_SET_RECORD_TYPE;

int operations[] = { TLS_GET_RECORD_TYPE, TLS_SET_RECORD_TYPE };
return 0;
}
18 changes: 9 additions & 9 deletions tests/unit/s2n_ktls_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,14 @@ int main(int argc, char **argv)
EXPECT_EQUAL(test_key.size, sizeof(value->key));
EXPECT_BYTEARRAY_EQUAL(test_key.data, value->key, sizeof(value->key));

EXPECT_TRUE(test_iv.size >= sizeof(value->iv));
EXPECT_BYTEARRAY_EQUAL(test_iv.data, value->iv, sizeof(value->iv));
EXPECT_TRUE(test_seq.size >= sizeof(value->rec_seq));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->rec_seq, sizeof(value->rec_seq));

EXPECT_TRUE(test_iv.size >= sizeof(value->salt));
EXPECT_BYTEARRAY_EQUAL(test_iv.data, value->salt, sizeof(value->salt));

EXPECT_TRUE(test_seq.size >= sizeof(value->rec_seq));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->rec_seq, sizeof(value->rec_seq));
EXPECT_TRUE(test_iv.size >= sizeof(value->iv));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->iv, sizeof(value->iv));
};

/* s2n_aes256_gcm */
Expand All @@ -221,14 +221,14 @@ int main(int argc, char **argv)
EXPECT_EQUAL(test_key.size, sizeof(value->key));
EXPECT_BYTEARRAY_EQUAL(test_key.data, value->key, sizeof(value->key));

EXPECT_TRUE(test_iv.size >= sizeof(value->iv));
EXPECT_BYTEARRAY_EQUAL(test_iv.data, value->iv, sizeof(value->iv));
EXPECT_TRUE(test_seq.size >= sizeof(value->rec_seq));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->rec_seq, sizeof(value->rec_seq));

EXPECT_TRUE(test_iv.size >= sizeof(value->salt));
EXPECT_BYTEARRAY_EQUAL(test_iv.data, value->salt, sizeof(value->salt));

EXPECT_TRUE(test_seq.size >= sizeof(value->rec_seq));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->rec_seq, sizeof(value->rec_seq));
EXPECT_TRUE(test_iv.size >= sizeof(value->iv));
EXPECT_BYTEARRAY_EQUAL(test_seq.data, value->iv, sizeof(value->iv));
};
};

Expand Down Expand Up @@ -309,7 +309,7 @@ int main(int argc, char **argv)
s2n_connection_ptr_free);
EXPECT_OK(s2n_test_configure_connection_for_ktls(server_conn));

server_conn->actual_protocol_version = S2N_TLS13;
server_conn->actual_protocol_version = S2N_TLS13 + 1;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_UNSUPPORTED_CONN);

server_conn->actual_protocol_version = S2N_TLS11;
Expand Down
Loading

0 comments on commit 0fb3769

Please sign in to comment.