summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2016-11-17 18:00:17 +0000
committerMatt Caswell <matt@openssl.org>2016-11-29 23:31:10 +0000
commitbebc0c7d85a7484f1c5d0123f24cdc3c6b150243 (patch)
tree61127e8e2f69031b9a82c42d972960b6735419e2
parent54d028aa0f5dc50ec64a8d99ed43b81519b0443b (diff)
Use the TLSv1.3 nonce construction
This updates the record layer to use the TLSv1.3 style nonce construciton. It also updates TLSProxy and ossltest to be able to recognise the new layout. Reviewed-by: Rich Salz <rsalz@openssl.org>
-rw-r--r--engines/e_ossltest.c35
-rw-r--r--ssl/build.info2
-rw-r--r--ssl/record/record.h1
-rw-r--r--ssl/record/ssl3_record_tls13.c104
-rw-r--r--ssl/ssl_locl.h2
-rw-r--r--ssl/t1_lib.c5
-rw-r--r--ssl/tls13_enc.c62
-rw-r--r--util/TLSProxy/Record.pm2
8 files changed, 146 insertions, 67 deletions
diff --git a/engines/e_ossltest.c b/engines/e_ossltest.c
index afa5edfeec..32d3118e70 100644
--- a/engines/e_ossltest.c
+++ b/engines/e_ossltest.c
@@ -617,33 +617,46 @@ int ossltest_aes128_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
int ossltest_aes128_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t inl)
{
- const size_t datalen = inl - EVP_GCM_TLS_EXPLICIT_IV_LEN
- - EVP_GCM_TLS_TAG_LEN;
- unsigned char *tmpbuf = OPENSSL_malloc(datalen);
+ unsigned char *tmpbuf = OPENSSL_malloc(inl);
- if (tmpbuf == NULL)
+ if (tmpbuf == NULL && inl > 0)
return -1;
/* Remember what we were asked to encrypt */
- memcpy(tmpbuf, in + EVP_GCM_TLS_EXPLICIT_IV_LEN, datalen);
+ memcpy(tmpbuf, in, inl);
/* Go through the motions of encrypting it */
EVP_CIPHER_meth_get_do_cipher(EVP_aes_128_gcm())(ctx, out, in, inl);
/*
- * Throw it all away and just use the plaintext as the output with empty
- * IV and tag
+ * Throw it all away and just use the plaintext as the output
*/
- memset(out, 0, inl);
- memcpy(out + EVP_GCM_TLS_EXPLICIT_IV_LEN, tmpbuf, datalen);
+ memcpy(out, tmpbuf, inl);
OPENSSL_free(tmpbuf);
- return 1;
+ return inl;
}
static int ossltest_aes128_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
void *ptr)
{
+ int ret;
+
/* Pass the ctrl down */
- return EVP_CIPHER_meth_get_ctrl(EVP_aes_128_gcm())(ctx, type, arg, ptr);
+ ret = EVP_CIPHER_meth_get_ctrl(EVP_aes_128_gcm())(ctx, type, arg, ptr);
+
+ if (ret <= 0)
+ return ret;
+
+ switch(type) {
+ case EVP_CTRL_AEAD_GET_TAG:
+ /* Always give the same tag */
+ memset(ptr, 0, EVP_GCM_TLS_TAG_LEN);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
}
diff --git a/ssl/build.info b/ssl/build.info
index 72b8dfc2be..23d33d3df8 100644
--- a/ssl/build.info
+++ b/ssl/build.info
@@ -11,4 +11,4 @@ SOURCE[../libssl]=\
ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c ssl_mcnf.c \
bio_ssl.c ssl_err.c t1_reneg.c tls_srp.c t1_trce.c ssl_utst.c \
record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \
- statem/statem.c
+ statem/statem.c record/ssl3_record_tls13.c
diff --git a/ssl/record/record.h b/ssl/record/record.h
index e30010d170..e9951966d1 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -230,6 +230,7 @@ __owur int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t
size_t *written);
__owur int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send);
__owur int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send);
+__owur int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send);
int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_free(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c
new file mode 100644
index 0000000000..48d52700d4
--- /dev/null
+++ b/ssl/record/ssl3_record_tls13.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_locl.h"
+#include "record_locl.h"
+
+/*-
+ * tls13_enc encrypts/decrypts |n_recs| in |recs|.
+ *
+ * Returns:
+ * 0: (in non-constant time) if the record is publically invalid (i.e. too
+ * short etc).
+ * 1: if the record encryption was successful.
+ * -1: if the record's AEAD-authenticator is invalid or, if sending,
+ * an internal error occurred.
+ */
+int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send)
+{
+ EVP_CIPHER_CTX *ctx;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ size_t ivlen, offset, loop;
+ unsigned char *staticiv;
+ unsigned char *seq;
+ int lenu, lenf;
+ SSL3_RECORD *rec = &recs[0];
+
+ if (n_recs != 1) {
+ /* Should not happen */
+ /* TODO(TLS1.3): Support pipelining */
+ return -1;
+ }
+
+ if (send) {
+ ctx = s->enc_write_ctx;
+ staticiv = s->write_iv;
+ seq = RECORD_LAYER_get_write_sequence(&s->rlayer);
+ } else {
+ ctx = s->enc_read_ctx;
+ staticiv = s->read_iv;
+ seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
+ }
+
+ if (ctx == NULL) {
+ memmove(rec->data, rec->input, rec->length);
+ rec->input = rec->data;
+ return 1;
+ }
+ ivlen = EVP_CIPHER_CTX_iv_length(ctx);
+
+ if (!send) {
+ /*
+ * Take off tag. There must be at least one byte of content type as
+ * well as the tag
+ */
+ /*
+ * TODO(TLS1.3): We're going to need to figure out the tag len based on
+ * the cipher. For now we just support GCM tags.
+ * TODO(TLS1.3): When we've swapped over the record layer to TLSv1.3
+ * then the length must be 1 + the tag len to account for the content
+ * byte that we know must have been encrypted.
+ */
+ if (rec->length < EVP_GCM_TLS_TAG_LEN)
+ return 0;
+ rec->length -= EVP_GCM_TLS_TAG_LEN;
+ }
+
+ /* Set up IV */
+ if (ivlen < SEQ_NUM_SIZE) {
+ /* Should not happen */
+ return -1;
+ }
+ offset = ivlen - SEQ_NUM_SIZE;
+ memcpy(iv, staticiv, offset);
+ for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+ iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+
+ /* TODO(size_t): lenu/lenf should be a size_t but EVP can't support it */
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, send) <= 0
+ || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input,
+ (unsigned int)rec->length) <= 0
+ || (!send && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+ EVP_GCM_TLS_TAG_LEN,
+ rec->data + rec->length) <= 0)
+ || EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0
+ || (size_t)(lenu + lenf) != rec->length) {
+ return -1;
+ }
+
+ if (send) {
+ /* Add the tag */
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, EVP_GCM_TLS_TAG_LEN,
+ rec->data + rec->length) <= 0)
+ return -1;
+ rec->length += EVP_GCM_TLS_TAG_LEN;
+ }
+
+ return 1;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index e909cadf5a..cb29b996f3 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -960,10 +960,12 @@ struct ssl_st {
unsigned char client_finished_secret[EVP_MAX_MD_SIZE];
unsigned char server_finished_secret[EVP_MAX_MD_SIZE];
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
+ unsigned char read_iv[EVP_MAX_IV_LENGTH]; /* TLSv1.3 static read IV */
EVP_MD_CTX *read_hash; /* used for mac generation */
COMP_CTX *compress; /* compression */
COMP_CTX *expand; /* uncompress */
EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+ unsigned char write_iv[EVP_MAX_IV_LENGTH]; /* TLSv1.3 static write IV */
EVP_MD_CTX *write_hash; /* used for mac generation */
/* session info */
/* client cert? */
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index ce728b0a34..778f84ee72 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -79,7 +79,7 @@ SSL3_ENC_METHOD const TLSv1_2_enc_data = {
};
SSL3_ENC_METHOD const TLSv1_3_enc_data = {
- tls1_enc,
+ tls13_enc,
tls1_mac,
tls13_setup_key_block,
tls13_generate_master_secret,
@@ -89,8 +89,7 @@ SSL3_ENC_METHOD const TLSv1_3_enc_data = {
TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
tls1_alert_code,
tls1_export_keying_material,
- SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS | SSL_ENC_FLAG_SHA256_PRF
- | SSL_ENC_FLAG_TLS1_2_CIPHERS,
+ SSL_ENC_FLAG_SIGALGS | SSL_ENC_FLAG_SHA256_PRF,
ssl3_set_handshake_header,
tls_close_construct_packet,
ssl3_handshake_write
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index 698b9be5ca..5af0c303bb 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -284,7 +284,7 @@ int tls13_change_cipher_state(SSL *s, int which)
static const unsigned char server_application_traffic[] =
"server application traffic secret";
unsigned char key[EVP_MAX_KEY_LENGTH];
- unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char *iv;
unsigned char secret[EVP_MAX_MD_SIZE];
unsigned char *insecret;
unsigned char *finsecret = NULL;
@@ -306,6 +306,7 @@ int tls13_change_cipher_state(SSL *s, int which)
}
}
ciph_ctx = s->enc_read_ctx;
+ iv = s->read_iv;
RECORD_LAYER_reset_read_sequence(&s->rlayer);
} else {
@@ -319,6 +320,7 @@ int tls13_change_cipher_state(SSL *s, int which)
}
}
ciph_ctx = s->enc_write_ctx;
+ iv = s->write_iv;
RECORD_LAYER_reset_write_sequence(&s->rlayer);
}
@@ -357,13 +359,7 @@ int tls13_change_cipher_state(SSL *s, int which)
/* TODO(size_t): convert me */
keylen = EVP_CIPHER_key_length(ciph);
-
- if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE)
- ivlen = EVP_GCM_TLS_FIXED_IV_LEN;
- else if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE)
- ivlen = EVP_CCM_TLS_FIXED_IV_LEN;
- else
- ivlen = EVP_CIPHER_iv_length(ciph);
+ ivlen = EVP_CIPHER_iv_length(ciph);
if (!tls13_derive_key(s, secret, key, keylen)
|| !tls13_derive_iv(s, secret, iv, ivlen)
@@ -374,40 +370,10 @@ int tls13_change_cipher_state(SSL *s, int which)
goto err;
}
- if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE) {
- if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, NULL,
- (which & SSL3_CC_WRITE))
- || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_GCM_SET_IV_FIXED,
- (int)ivlen, iv)) {
- SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB);
- goto err;
- }
- } else if (EVP_CIPHER_mode(ciph) == EVP_CIPH_CCM_MODE) {
- int taglen;
-
- if (s->s3->tmp.new_cipher->algorithm_enc
- & (SSL_AES128CCM8 | SSL_AES256CCM8))
- taglen = 8;
- else
- taglen = 16;
- if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL,
- (which & SSL3_CC_WRITE))
- || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, 12,
- NULL)
- || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, taglen,
- NULL)
- || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_CCM_SET_IV_FIXED,
- (int)ivlen, iv)
- || !EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1)) {
- SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB);
- goto err;
- }
- } else {
- if (!EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, iv,
- (which & SSL3_CC_WRITE))) {
- SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB);
- goto err;
- }
+ if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, key, NULL,
+ (which & SSL3_CC_WRITE)) <= 0) {
+ SSLerr(SSL_F_TLS13_CHANGE_CIPHER_STATE, ERR_R_EVP_LIB);
+ goto err;
}
#ifdef OPENSSL_SSL_TRACE_CRYPTO
@@ -417,14 +383,10 @@ int tls13_change_cipher_state(SSL *s, int which)
if (ciph->key_len)
s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY,
key, ciph->key_len, s, s->msg_callback_arg);
- if (ivlen) {
- if (EVP_CIPHER_mode(ciph) == EVP_CIPH_GCM_MODE)
- wh |= TLS1_RT_CRYPTO_FIXED_IV;
- else
- wh |= TLS1_RT_CRYPTO_IV;
- s->msg_callback(2, s->version, wh, iv, ivlen, s,
- s->msg_callback_arg);
- }
+
+ wh |= TLS1_RT_CRYPTO_IV;
+ s->msg_callback(2, s->version, wh, iv, ivlen, s,
+ s->msg_callback_arg);
}
#endif
diff --git a/util/TLSProxy/Record.pm b/util/TLSProxy/Record.pm
index 7189035fb4..5a35925aeb 100644
--- a/util/TLSProxy/Record.pm
+++ b/util/TLSProxy/Record.pm
@@ -242,8 +242,6 @@ sub decrypt()
#an unecrypted alert, so don't try to decrypt
return $data if (length($data) == 2);
}
- #8 bytes for a GCM IV
- $data = substr($data, 8);
$mactaglen = 16;
} elsif ($self->version >= VERS_TLS_1_1()) {
#16 bytes for a standard IV