Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 130b392c authored by Dave Watson's avatar Dave Watson Committed by David S. Miller
Browse files

net: tls: Add tls 1.3 support



TLS 1.3 has minor changes from TLS 1.2 at the record layer.

* Header now hardcodes the same version and application content type in
  the header.
* The real content type is appended after the data, before encryption (or
  after decryption).
* The IV is xored with the sequence number, instead of concatinating four
  bytes of IV with the explicit IV.
* Zero-padding:  No exlicit length is given, we search backwards from the
  end of the decrypted data for the first non-zero byte, which is the
  content type.  Currently recv supports reading zero-padding, but there
  is no way for send to add zero padding.

Signed-off-by: default avatarDave Watson <davejwatson@fb.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fedf201e
Loading
Loading
Loading
Loading
+49 −17
Original line number Diff line number Diff line
@@ -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];
@@ -203,6 +206,7 @@ struct cipher_context {
	u16 rec_seq_size;
	char *rec_seq;
	u16 aad_size;
	u16 tail_size;
};

union tls_crypto_context {
@@ -397,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);

	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;
}

	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;
static inline void xor_iv_with_seq(int version, char *iv, char *seq)
{
	int i;

	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)
+4 −0
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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];
+2 −1
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -463,7 +463,8 @@ 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;
	}
Loading