Use the TLSv1.3 nonce construction
authorMatt Caswell <matt@openssl.org>
Thu, 17 Nov 2016 18:00:17 +0000 (18:00 +0000)
committerMatt Caswell <matt@openssl.org>
Tue, 29 Nov 2016 23:31:10 +0000 (23:31 +0000)
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>
engines/e_ossltest.c
ssl/build.info
ssl/record/record.h
ssl/record/ssl3_record_tls13.c [new file with mode: 0644]
ssl/ssl_locl.h
ssl/t1_lib.c
ssl/tls13_enc.c
util/TLSProxy/Record.pm

index afa5edfeece1163eed4c9cbab672628242a46f29..32d3118e7027ff248a304eb3fba175595f104175 100644 (file)
@@ -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;
 }
index 72b8dfc2be65788867303e8f496d0e331223fcb8..23d33d3df8419f6eb91e99a8016a130ce40b35ec 100644 (file)
@@ -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
index e30010d170e7fd535336736bfd6214b4fd8711d1..e9951966d1097e95f8187562c5529325833707fe 100644 (file)
@@ -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 (file)
index 0000000..48d5270
--- /dev/null
@@ -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;
+}
index e909cadf5a79be0e2367be1c4ae3f0ecc6e801a3..cb29b996f3477e12ecccdd33613749fa37be8104 100644 (file)
@@ -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? */
index ce728b0a3423ec639ac33912694be42daca41571..778f84ee729891caa2209a8f2107a1ebf90ba66d 100644 (file)
@@ -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
index 698b9be5ca67587a795d3bbb0de39700363820a9..5af0c303bb9e243a74f8c0df30245b006c5072bf 100644 (file)
@@ -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
 
index 7189035fb4afd15a6574236e99ee259617f2ed6c..5a35925aebf221355de81df92d308b861fd78a28 100644 (file)
@@ -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