Commit 665cf634 authored by David S. Miller's avatar David S. Miller

Merge branch 'tls-1.3-support'

Dave Watson says:

====================
net: tls: TLS 1.3 support

This patchset adds 256bit keys and TLS1.3 support to the kernel TLS
socket.

TLS 1.3 is requested by passing TLS_1_3_VERSION in the setsockopt
call, which changes the framing as required for TLS1.3.

256bit keys are requested by passing TLS_CIPHER_AES_GCM_256 in the
sockopt.  This is a fairly straightforward passthrough to the crypto
framework.

256bit keys work with both TLS 1.2 and TLS 1.3

TLS 1.3 requires a different AAD layout, necessitating some minor
refactoring.  It also moves the message type byte to the encrypted
portion of the message, instead of the cleartext header as it was in
TLS1.2.  This requires moving the control message handling to after
decryption, but is otherwise similar.

V1 -> V2

The first two patches were dropped, and sent separately, one as a
bugfix to the net tree.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d3a5fd3c 8debd67e
......@@ -119,6 +119,9 @@ struct tls_rec {
/* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */
struct scatterlist sg_aead_out[2];
char content_type;
struct scatterlist sg_content_type;
char aad_space[TLS_AAD_SPACE_SIZE];
u8 iv_data[TLS_CIPHER_AES_GCM_128_IV_SIZE +
TLS_CIPHER_AES_GCM_128_SALT_SIZE];
......@@ -202,11 +205,16 @@ struct cipher_context {
char *iv;
u16 rec_seq_size;
char *rec_seq;
u16 aad_size;
u16 tail_size;
};
union tls_crypto_context {
struct tls_crypto_info info;
struct tls12_crypto_info_aes_gcm_128 aes_gcm_128;
union {
struct tls12_crypto_info_aes_gcm_128 aes_gcm_128;
struct tls12_crypto_info_aes_gcm_256 aes_gcm_256;
};
};
struct tls_context {
......@@ -393,49 +401,77 @@ static inline bool tls_bigint_increment(unsigned char *seq, int len)
}
static inline void tls_advance_record_sn(struct sock *sk,
struct cipher_context *ctx)
struct cipher_context *ctx,
int version)
{
if (tls_bigint_increment(ctx->rec_seq, ctx->rec_seq_size))
tls_err_abort(sk, EBADMSG);
tls_bigint_increment(ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
ctx->iv_size);
if (version != TLS_1_3_VERSION) {
tls_bigint_increment(ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
ctx->iv_size);
}
}
static inline void tls_fill_prepend(struct tls_context *ctx,
char *buf,
size_t plaintext_len,
unsigned char record_type)
unsigned char record_type,
int version)
{
size_t pkt_len, iv_size = ctx->tx.iv_size;
pkt_len = plaintext_len + iv_size + ctx->tx.tag_size;
pkt_len = plaintext_len + ctx->tx.tag_size;
if (version != TLS_1_3_VERSION) {
pkt_len += iv_size;
memcpy(buf + TLS_NONCE_OFFSET,
ctx->tx.iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, iv_size);
}
/* we cover nonce explicit here as well, so buf should be of
* size KTLS_DTLS_HEADER_SIZE + KTLS_DTLS_NONCE_EXPLICIT_SIZE
*/
buf[0] = record_type;
buf[1] = TLS_VERSION_MINOR(ctx->crypto_send.info.version);
buf[2] = TLS_VERSION_MAJOR(ctx->crypto_send.info.version);
buf[0] = version == TLS_1_3_VERSION ?
TLS_RECORD_TYPE_DATA : record_type;
/* Note that VERSION must be TLS_1_2 for both TLS1.2 and TLS1.3 */
buf[1] = TLS_1_2_VERSION_MINOR;
buf[2] = TLS_1_2_VERSION_MAJOR;
/* we can use IV for nonce explicit according to spec */
buf[3] = pkt_len >> 8;
buf[4] = pkt_len & 0xFF;
memcpy(buf + TLS_NONCE_OFFSET,
ctx->tx.iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, iv_size);
}
static inline void tls_make_aad(char *buf,
size_t size,
char *record_sequence,
int record_sequence_size,
unsigned char record_type)
unsigned char record_type,
int version)
{
if (version != TLS_1_3_VERSION) {
memcpy(buf, record_sequence, record_sequence_size);
buf += 8;
} else {
size += TLS_CIPHER_AES_GCM_128_TAG_SIZE;
}
buf[0] = version == TLS_1_3_VERSION ?
TLS_RECORD_TYPE_DATA : record_type;
buf[1] = TLS_1_2_VERSION_MAJOR;
buf[2] = TLS_1_2_VERSION_MINOR;
buf[3] = size >> 8;
buf[4] = size & 0xFF;
}
static inline void xor_iv_with_seq(int version, char *iv, char *seq)
{
memcpy(buf, record_sequence, record_sequence_size);
int i;
buf[8] = record_type;
buf[9] = TLS_1_2_VERSION_MAJOR;
buf[10] = TLS_1_2_VERSION_MINOR;
buf[11] = size >> 8;
buf[12] = size & 0xFF;
if (version == TLS_1_3_VERSION) {
for (i = 0; i < 8; i++)
iv[i + 4] ^= seq[i];
}
}
static inline struct tls_context *tls_get_ctx(const struct sock *sk)
......
......@@ -51,6 +51,10 @@
#define TLS_1_2_VERSION_MINOR 0x3
#define TLS_1_2_VERSION TLS_VERSION_NUMBER(TLS_1_2)
#define TLS_1_3_VERSION_MAJOR 0x3
#define TLS_1_3_VERSION_MINOR 0x4
#define TLS_1_3_VERSION TLS_VERSION_NUMBER(TLS_1_3)
/* Supported ciphers */
#define TLS_CIPHER_AES_GCM_128 51
#define TLS_CIPHER_AES_GCM_128_IV_SIZE 8
......@@ -59,6 +63,13 @@
#define TLS_CIPHER_AES_GCM_128_TAG_SIZE 16
#define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE 8
#define TLS_CIPHER_AES_GCM_256 52
#define TLS_CIPHER_AES_GCM_256_IV_SIZE 8
#define TLS_CIPHER_AES_GCM_256_KEY_SIZE 32
#define TLS_CIPHER_AES_GCM_256_SALT_SIZE 4
#define TLS_CIPHER_AES_GCM_256_TAG_SIZE 16
#define TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE 8
#define TLS_SET_RECORD_TYPE 1
#define TLS_GET_RECORD_TYPE 2
......@@ -75,4 +86,12 @@ struct tls12_crypto_info_aes_gcm_128 {
unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
};
struct tls12_crypto_info_aes_gcm_256 {
struct tls_crypto_info info;
unsigned char iv[TLS_CIPHER_AES_GCM_256_IV_SIZE];
unsigned char key[TLS_CIPHER_AES_GCM_256_KEY_SIZE];
unsigned char salt[TLS_CIPHER_AES_GCM_256_SALT_SIZE];
unsigned char rec_seq[TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE];
};
#endif /* _UAPI_LINUX_TLS_H */
......@@ -257,7 +257,8 @@ static int tls_push_record(struct sock *sk,
tls_fill_prepend(ctx,
skb_frag_address(frag),
record->len - ctx->tx.prepend_size,
record_type);
record_type,
ctx->crypto_send.info.version);
/* HW doesn't care about the data in the tag, because it fills it. */
dummy_tag_frag.page = skb_frag_page(frag);
......@@ -270,7 +271,7 @@ static int tls_push_record(struct sock *sk,
spin_unlock_irq(&offload_ctx->lock);
offload_ctx->open_record = NULL;
set_bit(TLS_PENDING_CLOSED_RECORD, &ctx->flags);
tls_advance_record_sn(sk, &ctx->tx);
tls_advance_record_sn(sk, &ctx->tx, ctx->crypto_send.info.version);
for (i = 0; i < record->num_frags; i++) {
frag = &record->frags[i];
......
......@@ -73,7 +73,8 @@ static int tls_enc_record(struct aead_request *aead_req,
len -= TLS_CIPHER_AES_GCM_128_IV_SIZE;
tls_make_aad(aad, len - TLS_CIPHER_AES_GCM_128_TAG_SIZE,
(char *)&rcd_sn, sizeof(rcd_sn), buf[0]);
(char *)&rcd_sn, sizeof(rcd_sn), buf[0],
TLS_1_2_VERSION);
memcpy(iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, buf + TLS_HEADER_SIZE,
TLS_CIPHER_AES_GCM_128_IV_SIZE);
......
......@@ -372,6 +372,30 @@ static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval,
rc = -EFAULT;
break;
}
case TLS_CIPHER_AES_GCM_256: {
struct tls12_crypto_info_aes_gcm_256 *
crypto_info_aes_gcm_256 =
container_of(crypto_info,
struct tls12_crypto_info_aes_gcm_256,
info);
if (len != sizeof(*crypto_info_aes_gcm_256)) {
rc = -EINVAL;
goto out;
}
lock_sock(sk);
memcpy(crypto_info_aes_gcm_256->iv,
ctx->tx.iv + TLS_CIPHER_AES_GCM_256_SALT_SIZE,
TLS_CIPHER_AES_GCM_256_IV_SIZE);
memcpy(crypto_info_aes_gcm_256->rec_seq, ctx->tx.rec_seq,
TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE);
release_sock(sk);
if (copy_to_user(optval,
crypto_info_aes_gcm_256,
sizeof(*crypto_info_aes_gcm_256)))
rc = -EFAULT;
break;
}
default:
rc = -EINVAL;
}
......@@ -412,6 +436,7 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
{
struct tls_crypto_info *crypto_info;
struct tls_context *ctx = tls_get_ctx(sk);
size_t optsize;
int rc = 0;
int conf;
......@@ -438,14 +463,19 @@ static int do_tls_setsockopt_conf(struct sock *sk, char __user *optval,
}
/* check version */
if (crypto_info->version != TLS_1_2_VERSION) {
if (crypto_info->version != TLS_1_2_VERSION &&
crypto_info->version != TLS_1_3_VERSION) {
rc = -ENOTSUPP;
goto err_crypto_info;
}
switch (crypto_info->cipher_type) {
case TLS_CIPHER_AES_GCM_128: {
if (optlen != sizeof(struct tls12_crypto_info_aes_gcm_128)) {
case TLS_CIPHER_AES_GCM_128:
case TLS_CIPHER_AES_GCM_256: {
optsize = crypto_info->cipher_type == TLS_CIPHER_AES_GCM_128 ?
sizeof(struct tls12_crypto_info_aes_gcm_128) :
sizeof(struct tls12_crypto_info_aes_gcm_256);
if (optlen != optsize) {
rc = -EINVAL;
goto err_crypto_info;
}
......
This diff is collapsed.
......@@ -42,7 +42,7 @@ FIXTURE_SETUP(tls)
len = sizeof(addr);
memset(&tls12, 0, sizeof(tls12));
tls12.info.version = TLS_1_2_VERSION;
tls12.info.version = TLS_1_3_VERSION;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
addr.sin_family = AF_INET;
......@@ -763,4 +763,140 @@ TEST_F(tls, control_msg)
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
}
TEST(keysizes) {
struct tls12_crypto_info_aes_gcm_256 tls12;
struct sockaddr_in addr;
int sfd, ret, fd, cfd;
socklen_t len;
bool notls;
notls = false;
len = sizeof(addr);
memset(&tls12, 0, sizeof(tls12));
tls12.info.version = TLS_1_2_VERSION;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_256;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
fd = socket(AF_INET, SOCK_STREAM, 0);
sfd = socket(AF_INET, SOCK_STREAM, 0);
ret = bind(sfd, &addr, sizeof(addr));
ASSERT_EQ(ret, 0);
ret = listen(sfd, 10);
ASSERT_EQ(ret, 0);
ret = getsockname(sfd, &addr, &len);
ASSERT_EQ(ret, 0);
ret = connect(fd, &addr, sizeof(addr));
ASSERT_EQ(ret, 0);
ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
if (ret != 0) {
notls = true;
printf("Failure setting TCP_ULP, testing without tls\n");
}
if (!notls) {
ret = setsockopt(fd, SOL_TLS, TLS_TX, &tls12,
sizeof(tls12));
EXPECT_EQ(ret, 0);
}
cfd = accept(sfd, &addr, &len);
ASSERT_GE(cfd, 0);
if (!notls) {
ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls",
sizeof("tls"));
EXPECT_EQ(ret, 0);
ret = setsockopt(cfd, SOL_TLS, TLS_RX, &tls12,
sizeof(tls12));
EXPECT_EQ(ret, 0);
}
close(sfd);
close(fd);
close(cfd);
}
TEST(tls12) {
int fd, cfd;
bool notls;
struct tls12_crypto_info_aes_gcm_128 tls12;
struct sockaddr_in addr;
socklen_t len;
int sfd, ret;
notls = false;
len = sizeof(addr);
memset(&tls12, 0, sizeof(tls12));
tls12.info.version = TLS_1_2_VERSION;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
fd = socket(AF_INET, SOCK_STREAM, 0);
sfd = socket(AF_INET, SOCK_STREAM, 0);
ret = bind(sfd, &addr, sizeof(addr));
ASSERT_EQ(ret, 0);
ret = listen(sfd, 10);
ASSERT_EQ(ret, 0);
ret = getsockname(sfd, &addr, &len);
ASSERT_EQ(ret, 0);
ret = connect(fd, &addr, sizeof(addr));
ASSERT_EQ(ret, 0);
ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
if (ret != 0) {
notls = true;
printf("Failure setting TCP_ULP, testing without tls\n");
}
if (!notls) {
ret = setsockopt(fd, SOL_TLS, TLS_TX, &tls12,
sizeof(tls12));
ASSERT_EQ(ret, 0);
}
cfd = accept(sfd, &addr, &len);
ASSERT_GE(cfd, 0);
if (!notls) {
ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls",
sizeof("tls"));
ASSERT_EQ(ret, 0);
ret = setsockopt(cfd, SOL_TLS, TLS_RX, &tls12,
sizeof(tls12));
ASSERT_EQ(ret, 0);
}
close(sfd);
char const *test_str = "test_read";
int send_len = 10;
char buf[10];
send_len = strlen(test_str) + 1;
EXPECT_EQ(send(fd, test_str, send_len, 0), send_len);
EXPECT_NE(recv(cfd, buf, send_len, 0), -1);
EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
close(fd);
close(cfd);
}
TEST_HARNESS_MAIN
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment