Commit fb3158ea authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'add-chacha20-poly1305-cipher-to-kernel-tls'

Vadim Fedorenko says:

====================
Add CHACHA20-POLY1305 cipher to Kernel TLS

RFC 7905 defines usage of ChaCha20-Poly1305 in TLS connections. This
cipher is widely used nowadays and it's good to have a support for it
in TLS connections in kernel.
====================

Link: https://lore.kernel.org/r/1606231490-653-1-git-send-email-vfedorenko@novek.ruSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 594e31bc 4f336e88
...@@ -211,6 +211,7 @@ union tls_crypto_context { ...@@ -211,6 +211,7 @@ union tls_crypto_context {
union { union {
struct tls12_crypto_info_aes_gcm_128 aes_gcm_128; struct tls12_crypto_info_aes_gcm_128 aes_gcm_128;
struct tls12_crypto_info_aes_gcm_256 aes_gcm_256; struct tls12_crypto_info_aes_gcm_256 aes_gcm_256;
struct tls12_crypto_info_chacha20_poly1305 chacha20_poly1305;
}; };
}; };
...@@ -501,32 +502,33 @@ static inline void tls_advance_record_sn(struct sock *sk, ...@@ -501,32 +502,33 @@ static inline void tls_advance_record_sn(struct sock *sk,
if (tls_bigint_increment(ctx->rec_seq, prot->rec_seq_size)) if (tls_bigint_increment(ctx->rec_seq, prot->rec_seq_size))
tls_err_abort(sk, EBADMSG); tls_err_abort(sk, EBADMSG);
if (prot->version != TLS_1_3_VERSION) if (prot->version != TLS_1_3_VERSION &&
tls_bigint_increment(ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305)
tls_bigint_increment(ctx->iv + prot->salt_size,
prot->iv_size); prot->iv_size);
} }
static inline void tls_fill_prepend(struct tls_context *ctx, static inline void tls_fill_prepend(struct tls_context *ctx,
char *buf, char *buf,
size_t plaintext_len, size_t plaintext_len,
unsigned char record_type, unsigned char record_type)
int version)
{ {
struct tls_prot_info *prot = &ctx->prot_info; struct tls_prot_info *prot = &ctx->prot_info;
size_t pkt_len, iv_size = prot->iv_size; size_t pkt_len, iv_size = prot->iv_size;
pkt_len = plaintext_len + prot->tag_size; pkt_len = plaintext_len + prot->tag_size;
if (version != TLS_1_3_VERSION) { if (prot->version != TLS_1_3_VERSION &&
prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305) {
pkt_len += iv_size; pkt_len += iv_size;
memcpy(buf + TLS_NONCE_OFFSET, memcpy(buf + TLS_NONCE_OFFSET,
ctx->tx.iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, iv_size); ctx->tx.iv + prot->salt_size, iv_size);
} }
/* we cover nonce explicit here as well, so buf should be of /* we cover nonce explicit here as well, so buf should be of
* size KTLS_DTLS_HEADER_SIZE + KTLS_DTLS_NONCE_EXPLICIT_SIZE * size KTLS_DTLS_HEADER_SIZE + KTLS_DTLS_NONCE_EXPLICIT_SIZE
*/ */
buf[0] = version == TLS_1_3_VERSION ? buf[0] = prot->version == TLS_1_3_VERSION ?
TLS_RECORD_TYPE_DATA : record_type; TLS_RECORD_TYPE_DATA : record_type;
/* Note that VERSION must be TLS_1_2 for both TLS1.2 and TLS1.3 */ /* Note that VERSION must be TLS_1_2 for both TLS1.2 and TLS1.3 */
buf[1] = TLS_1_2_VERSION_MINOR; buf[1] = TLS_1_2_VERSION_MINOR;
...@@ -539,18 +541,17 @@ static inline void tls_fill_prepend(struct tls_context *ctx, ...@@ -539,18 +541,17 @@ static inline void tls_fill_prepend(struct tls_context *ctx,
static inline void tls_make_aad(char *buf, static inline void tls_make_aad(char *buf,
size_t size, size_t size,
char *record_sequence, char *record_sequence,
int record_sequence_size,
unsigned char record_type, unsigned char record_type,
int version) struct tls_prot_info *prot)
{ {
if (version != TLS_1_3_VERSION) { if (prot->version != TLS_1_3_VERSION) {
memcpy(buf, record_sequence, record_sequence_size); memcpy(buf, record_sequence, prot->rec_seq_size);
buf += 8; buf += 8;
} else { } else {
size += TLS_CIPHER_AES_GCM_128_TAG_SIZE; size += prot->tag_size;
} }
buf[0] = version == TLS_1_3_VERSION ? buf[0] = prot->version == TLS_1_3_VERSION ?
TLS_RECORD_TYPE_DATA : record_type; TLS_RECORD_TYPE_DATA : record_type;
buf[1] = TLS_1_2_VERSION_MAJOR; buf[1] = TLS_1_2_VERSION_MAJOR;
buf[2] = TLS_1_2_VERSION_MINOR; buf[2] = TLS_1_2_VERSION_MINOR;
...@@ -558,11 +559,12 @@ static inline void tls_make_aad(char *buf, ...@@ -558,11 +559,12 @@ static inline void tls_make_aad(char *buf,
buf[4] = size & 0xFF; buf[4] = size & 0xFF;
} }
static inline void xor_iv_with_seq(int version, char *iv, char *seq) static inline void xor_iv_with_seq(struct tls_prot_info *prot, char *iv, char *seq)
{ {
int i; int i;
if (version == TLS_1_3_VERSION) { if (prot->version == TLS_1_3_VERSION ||
prot->cipher_type == TLS_CIPHER_CHACHA20_POLY1305) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
iv[i + 4] ^= seq[i]; iv[i + 4] ^= seq[i];
} }
......
...@@ -77,6 +77,13 @@ ...@@ -77,6 +77,13 @@
#define TLS_CIPHER_AES_CCM_128_TAG_SIZE 16 #define TLS_CIPHER_AES_CCM_128_TAG_SIZE 16
#define TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE 8 #define TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE 8
#define TLS_CIPHER_CHACHA20_POLY1305 54
#define TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE 12
#define TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE 32
#define TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE 0
#define TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE 16
#define TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE 8
#define TLS_SET_RECORD_TYPE 1 #define TLS_SET_RECORD_TYPE 1
#define TLS_GET_RECORD_TYPE 2 #define TLS_GET_RECORD_TYPE 2
...@@ -109,6 +116,14 @@ struct tls12_crypto_info_aes_ccm_128 { ...@@ -109,6 +116,14 @@ struct tls12_crypto_info_aes_ccm_128 {
unsigned char rec_seq[TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE]; unsigned char rec_seq[TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE];
}; };
struct tls12_crypto_info_chacha20_poly1305 {
struct tls_crypto_info info;
unsigned char iv[TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE];
unsigned char key[TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE];
unsigned char salt[TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE];
unsigned char rec_seq[TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE];
};
enum { enum {
TLS_INFO_UNSPEC, TLS_INFO_UNSPEC,
TLS_INFO_VERSION, TLS_INFO_VERSION,
......
...@@ -327,7 +327,7 @@ static int tls_device_record_close(struct sock *sk, ...@@ -327,7 +327,7 @@ static int tls_device_record_close(struct sock *sk,
/* fill prepend */ /* fill prepend */
tls_fill_prepend(ctx, skb_frag_address(&record->frags[0]), tls_fill_prepend(ctx, skb_frag_address(&record->frags[0]),
record->len - prot->overhead_size, record->len - prot->overhead_size,
record_type, prot->version); record_type);
return ret; return ret;
} }
......
...@@ -49,7 +49,8 @@ static int tls_enc_record(struct aead_request *aead_req, ...@@ -49,7 +49,8 @@ static int tls_enc_record(struct aead_request *aead_req,
struct crypto_aead *aead, char *aad, struct crypto_aead *aead, char *aad,
char *iv, __be64 rcd_sn, char *iv, __be64 rcd_sn,
struct scatter_walk *in, struct scatter_walk *in,
struct scatter_walk *out, int *in_len) struct scatter_walk *out, int *in_len,
struct tls_prot_info *prot)
{ {
unsigned char buf[TLS_HEADER_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE]; unsigned char buf[TLS_HEADER_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE];
struct scatterlist sg_in[3]; struct scatterlist sg_in[3];
...@@ -73,8 +74,7 @@ static int tls_enc_record(struct aead_request *aead_req, ...@@ -73,8 +74,7 @@ static int tls_enc_record(struct aead_request *aead_req,
len -= TLS_CIPHER_AES_GCM_128_IV_SIZE; len -= TLS_CIPHER_AES_GCM_128_IV_SIZE;
tls_make_aad(aad, len - TLS_CIPHER_AES_GCM_128_TAG_SIZE, tls_make_aad(aad, len - TLS_CIPHER_AES_GCM_128_TAG_SIZE,
(char *)&rcd_sn, sizeof(rcd_sn), buf[0], (char *)&rcd_sn, buf[0], prot);
TLS_1_2_VERSION);
memcpy(iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, buf + TLS_HEADER_SIZE, memcpy(iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, buf + TLS_HEADER_SIZE,
TLS_CIPHER_AES_GCM_128_IV_SIZE); TLS_CIPHER_AES_GCM_128_IV_SIZE);
...@@ -140,7 +140,7 @@ static struct aead_request *tls_alloc_aead_request(struct crypto_aead *aead, ...@@ -140,7 +140,7 @@ static struct aead_request *tls_alloc_aead_request(struct crypto_aead *aead,
static int tls_enc_records(struct aead_request *aead_req, static int tls_enc_records(struct aead_request *aead_req,
struct crypto_aead *aead, struct scatterlist *sg_in, struct crypto_aead *aead, struct scatterlist *sg_in,
struct scatterlist *sg_out, char *aad, char *iv, struct scatterlist *sg_out, char *aad, char *iv,
u64 rcd_sn, int len) u64 rcd_sn, int len, struct tls_prot_info *prot)
{ {
struct scatter_walk out, in; struct scatter_walk out, in;
int rc; int rc;
...@@ -150,7 +150,7 @@ static int tls_enc_records(struct aead_request *aead_req, ...@@ -150,7 +150,7 @@ static int tls_enc_records(struct aead_request *aead_req,
do { do {
rc = tls_enc_record(aead_req, aead, aad, iv, rc = tls_enc_record(aead_req, aead, aad, iv,
cpu_to_be64(rcd_sn), &in, &out, &len); cpu_to_be64(rcd_sn), &in, &out, &len, prot);
rcd_sn++; rcd_sn++;
} while (rc == 0 && len); } while (rc == 0 && len);
...@@ -348,7 +348,8 @@ static struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx, ...@@ -348,7 +348,8 @@ static struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx,
payload_len, sync_size, dummy_buf); payload_len, sync_size, dummy_buf);
if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv, if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv,
rcd_sn, sync_size + payload_len) < 0) rcd_sn, sync_size + payload_len,
&tls_ctx->prot_info) < 0)
goto free_nskb; goto free_nskb;
complete_skb(nskb, skb, tcp_payload_offset); complete_skb(nskb, skb, tcp_payload_offset);
......
...@@ -521,6 +521,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval, ...@@ -521,6 +521,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
case TLS_CIPHER_AES_CCM_128: case TLS_CIPHER_AES_CCM_128:
optsize = sizeof(struct tls12_crypto_info_aes_ccm_128); optsize = sizeof(struct tls12_crypto_info_aes_ccm_128);
break; break;
case TLS_CIPHER_CHACHA20_POLY1305:
optsize = sizeof(struct tls12_crypto_info_chacha20_poly1305);
break;
default: default:
rc = -EINVAL; rc = -EINVAL;
goto err_crypto_info; goto err_crypto_info;
......
...@@ -505,7 +505,7 @@ static int tls_do_encryption(struct sock *sk, ...@@ -505,7 +505,7 @@ static int tls_do_encryption(struct sock *sk,
memcpy(&rec->iv_data[iv_offset], tls_ctx->tx.iv, memcpy(&rec->iv_data[iv_offset], tls_ctx->tx.iv,
prot->iv_size + prot->salt_size); prot->iv_size + prot->salt_size);
xor_iv_with_seq(prot->version, rec->iv_data, tls_ctx->tx.rec_seq); xor_iv_with_seq(prot, rec->iv_data, tls_ctx->tx.rec_seq);
sge->offset += prot->prepend_size; sge->offset += prot->prepend_size;
sge->length -= prot->prepend_size; sge->length -= prot->prepend_size;
...@@ -748,14 +748,13 @@ static int tls_push_record(struct sock *sk, int flags, ...@@ -748,14 +748,13 @@ static int tls_push_record(struct sock *sk, int flags,
sg_chain(rec->sg_aead_out, 2, &msg_en->sg.data[i]); sg_chain(rec->sg_aead_out, 2, &msg_en->sg.data[i]);
tls_make_aad(rec->aad_space, msg_pl->sg.size + prot->tail_size, tls_make_aad(rec->aad_space, msg_pl->sg.size + prot->tail_size,
tls_ctx->tx.rec_seq, prot->rec_seq_size, tls_ctx->tx.rec_seq, record_type, prot);
record_type, prot->version);
tls_fill_prepend(tls_ctx, tls_fill_prepend(tls_ctx,
page_address(sg_page(&msg_en->sg.data[i])) + page_address(sg_page(&msg_en->sg.data[i])) +
msg_en->sg.data[i].offset, msg_en->sg.data[i].offset,
msg_pl->sg.size + prot->tail_size, msg_pl->sg.size + prot->tail_size,
record_type, prot->version); record_type);
tls_ctx->pending_open_record_frags = false; tls_ctx->pending_open_record_frags = false;
...@@ -1465,19 +1464,19 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, ...@@ -1465,19 +1464,19 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
kfree(mem); kfree(mem);
return err; return err;
} }
if (prot->version == TLS_1_3_VERSION) if (prot->version == TLS_1_3_VERSION ||
prot->cipher_type == TLS_CIPHER_CHACHA20_POLY1305)
memcpy(iv + iv_offset, tls_ctx->rx.iv, memcpy(iv + iv_offset, tls_ctx->rx.iv,
crypto_aead_ivsize(ctx->aead_recv)); crypto_aead_ivsize(ctx->aead_recv));
else else
memcpy(iv + iv_offset, tls_ctx->rx.iv, prot->salt_size); memcpy(iv + iv_offset, tls_ctx->rx.iv, prot->salt_size);
xor_iv_with_seq(prot->version, iv, tls_ctx->rx.rec_seq); xor_iv_with_seq(prot, iv, tls_ctx->rx.rec_seq);
/* Prepare AAD */ /* Prepare AAD */
tls_make_aad(aad, rxm->full_len - prot->overhead_size + tls_make_aad(aad, rxm->full_len - prot->overhead_size +
prot->tail_size, prot->tail_size,
tls_ctx->rx.rec_seq, prot->rec_seq_size, tls_ctx->rx.rec_seq, ctx->control, prot);
ctx->control, prot->version);
/* Prepare sgin */ /* Prepare sgin */
sg_init_table(sgin, n_sgin); sg_init_table(sgin, n_sgin);
...@@ -2070,7 +2069,8 @@ static int tls_read_size(struct strparser *strp, struct sk_buff *skb) ...@@ -2070,7 +2069,8 @@ static int tls_read_size(struct strparser *strp, struct sk_buff *skb)
data_len = ((header[4] & 0xFF) | (header[3] << 8)); data_len = ((header[4] & 0xFF) | (header[3] << 8));
cipher_overhead = prot->tag_size; cipher_overhead = prot->tag_size;
if (prot->version != TLS_1_3_VERSION) if (prot->version != TLS_1_3_VERSION &&
prot->cipher_type != TLS_CIPHER_CHACHA20_POLY1305)
cipher_overhead += prot->iv_size; cipher_overhead += prot->iv_size;
if (data_len > TLS_MAX_PAYLOAD_SIZE + cipher_overhead + if (data_len > TLS_MAX_PAYLOAD_SIZE + cipher_overhead +
...@@ -2290,6 +2290,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) ...@@ -2290,6 +2290,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
struct tls12_crypto_info_aes_gcm_128 *gcm_128_info; struct tls12_crypto_info_aes_gcm_128 *gcm_128_info;
struct tls12_crypto_info_aes_gcm_256 *gcm_256_info; struct tls12_crypto_info_aes_gcm_256 *gcm_256_info;
struct tls12_crypto_info_aes_ccm_128 *ccm_128_info; struct tls12_crypto_info_aes_ccm_128 *ccm_128_info;
struct tls12_crypto_info_chacha20_poly1305 *chacha20_poly1305_info;
struct tls_sw_context_tx *sw_ctx_tx = NULL; struct tls_sw_context_tx *sw_ctx_tx = NULL;
struct tls_sw_context_rx *sw_ctx_rx = NULL; struct tls_sw_context_rx *sw_ctx_rx = NULL;
struct cipher_context *cctx; struct cipher_context *cctx;
...@@ -2402,6 +2403,21 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) ...@@ -2402,6 +2403,21 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
cipher_name = "ccm(aes)"; cipher_name = "ccm(aes)";
break; break;
} }
case TLS_CIPHER_CHACHA20_POLY1305: {
chacha20_poly1305_info = (void *)crypto_info;
nonce_size = 0;
tag_size = TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE;
iv_size = TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE;
iv = chacha20_poly1305_info->iv;
rec_seq_size = TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE;
rec_seq = chacha20_poly1305_info->rec_seq;
keysize = TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE;
key = chacha20_poly1305_info->key;
salt = chacha20_poly1305_info->salt;
salt_size = TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE;
cipher_name = "rfc7539(chacha20,poly1305)";
break;
}
default: default:
rc = -EINVAL; rc = -EINVAL;
goto free_priv; goto free_priv;
......
...@@ -103,32 +103,58 @@ FIXTURE(tls) ...@@ -103,32 +103,58 @@ FIXTURE(tls)
FIXTURE_VARIANT(tls) FIXTURE_VARIANT(tls)
{ {
unsigned int tls_version; u16 tls_version;
u16 cipher_type;
}; };
FIXTURE_VARIANT_ADD(tls, 12) FIXTURE_VARIANT_ADD(tls, 12_gcm)
{ {
.tls_version = TLS_1_2_VERSION, .tls_version = TLS_1_2_VERSION,
.cipher_type = TLS_CIPHER_AES_GCM_128,
}; };
FIXTURE_VARIANT_ADD(tls, 13) FIXTURE_VARIANT_ADD(tls, 13_gcm)
{ {
.tls_version = TLS_1_3_VERSION, .tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_AES_GCM_128,
};
FIXTURE_VARIANT_ADD(tls, 12_chacha)
{
.tls_version = TLS_1_2_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
};
FIXTURE_VARIANT_ADD(tls, 13_chacha)
{
.tls_version = TLS_1_3_VERSION,
.cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
}; };
FIXTURE_SETUP(tls) FIXTURE_SETUP(tls)
{ {
struct tls12_crypto_info_aes_gcm_128 tls12; union tls_crypto_context tls12;
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t len; socklen_t len;
int sfd, ret; int sfd, ret;
size_t tls12_sz;
self->notls = false; self->notls = false;
len = sizeof(addr); len = sizeof(addr);
memset(&tls12, 0, sizeof(tls12)); memset(&tls12, 0, sizeof(tls12));
tls12.info.version = variant->tls_version; tls12.info.version = variant->tls_version;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128; tls12.info.cipher_type = variant->cipher_type;
switch (variant->cipher_type) {
case TLS_CIPHER_CHACHA20_POLY1305:
tls12_sz = sizeof(tls12_crypto_info_chacha20_poly1305);
break;
case TLS_CIPHER_AES_GCM_128:
tls12_sz = sizeof(tls12_crypto_info_aes_gcm_128);
break;
default:
tls12_sz = 0;
}
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = htonl(INADDR_ANY);
...@@ -156,7 +182,7 @@ FIXTURE_SETUP(tls) ...@@ -156,7 +182,7 @@ FIXTURE_SETUP(tls)
if (!self->notls) { if (!self->notls) {
ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12, ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12,
sizeof(tls12)); tls12_sz);
ASSERT_EQ(ret, 0); ASSERT_EQ(ret, 0);
} }
...@@ -169,7 +195,7 @@ FIXTURE_SETUP(tls) ...@@ -169,7 +195,7 @@ FIXTURE_SETUP(tls)
ASSERT_EQ(ret, 0); ASSERT_EQ(ret, 0);
ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12,
sizeof(tls12)); tls12_sz);
ASSERT_EQ(ret, 0); ASSERT_EQ(ret, 0);
} }
......
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