[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Nov 9 14:19:51 UTC 2016


The branch master has been updated
       via  6925a94839794a6712db181bd1a8ccf948deb4ff (commit)
       via  134bfe56c4fe9490ddcac070909252233ff82076 (commit)
       via  34574f193bf9961256d5b8bdb6950dcc890e0336 (commit)
       via  9b36b7d9bdb33d1edbc2bbfd8a773a0eb8645788 (commit)
       via  327c1627923288d3dbbfc34d1c7d8785552f6ad8 (commit)
       via  ddd2c38917976da07ce0dfcd0bf3f3826c94051c (commit)
       via  d2139cf8dffcfe4a936ef55d25f769b162a8c603 (commit)
      from  234b8af4b748311b8856bfd30ae45d187a184465 (commit)


- Log -----------------------------------------------------------------
commit 6925a94839794a6712db181bd1a8ccf948deb4ff
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 8 23:22:11 2016 +0000

    Ensure the key and iv labels are declared as static
    
    Fixes a travis failure
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 134bfe56c4fe9490ddcac070909252233ff82076
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 7 10:18:41 2016 +0000

    Add a test for the TLS1.3 secret generation
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 34574f193bf9961256d5b8bdb6950dcc890e0336
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 8 10:34:28 2016 +0000

    Add support for TLS1.3 secret generation
    
    Nothing is using this yet, it just adds the underlying functions necesary
    for generating the TLS1.3 secrets.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 9b36b7d9bdb33d1edbc2bbfd8a773a0eb8645788
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 8 10:33:35 2016 +0000

    Add support for initialising WPACKETs from a static buffer
    
    Normally WPACKETs will use a BUF_MEM which can grow as required. Sometimes
    though that may be overkill for what is needed - a static buffer may be
    sufficient. This adds that capability.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 327c1627923288d3dbbfc34d1c7d8785552f6ad8
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 8 10:25:21 2016 +0000

    Add some documentation for the new HKDF modes
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit ddd2c38917976da07ce0dfcd0bf3f3826c94051c
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 8 11:48:33 2016 +0000

    Following the changes to HKDF to accept a mode, add some tests for this
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d2139cf8dffcfe4a936ef55d25f769b162a8c603
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 7 10:16:57 2016 +0000

    Update HKDF to support separte Extract and Expand steps
    
    At the moment you can only do an HKDF Extract and Expand in one go. For
    TLS1.3 we need to be able to do an Extract first, and the subsequently do
    a number of Expand steps on the same PRK.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 crypto/kdf/hkdf.c                                  |  52 ++-
 doc/man3/EVP_PKEY_CTX_set_hkdf_md.pod              |  62 +++-
 include/openssl/kdf.h                              |  23 +-
 ssl/build.info                                     |   2 +-
 ssl/packet.c                                       |  55 +++-
 ssl/packet_locl.h                                  |  10 +
 ssl/ssl_locl.h                                     |  21 ++
 ssl/tls13_enc.c                                    | 217 +++++++++++++
 test/build.info                                    |  11 +
 test/evptests.txt                                  | 106 +++++++
 .../{80-test_dtls_mtu.t => 90-test_tls13secrets.t} |   9 +-
 test/tls13secretstest.c                            | 353 +++++++++++++++++++++
 test/wpackettest.c                                 |  27 ++
 13 files changed, 902 insertions(+), 46 deletions(-)
 create mode 100644 ssl/tls13_enc.c
 copy test/recipes/{80-test_dtls_mtu.t => 90-test_tls13secrets.t} (67%)
 create mode 100644 test/tls13secretstest.c

diff --git a/crypto/kdf/hkdf.c b/crypto/kdf/hkdf.c
index 00b95b5..8b6eeb3 100644
--- a/crypto/kdf/hkdf.c
+++ b/crypto/kdf/hkdf.c
@@ -34,6 +34,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
                                   unsigned char *okm, size_t okm_len);
 
 typedef struct {
+    int mode;
     const EVP_MD *md;
     unsigned char *salt;
     size_t salt_len;
@@ -77,6 +78,10 @@ static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
         kctx->md = p2;
         return 1;
 
+    case EVP_PKEY_CTRL_HKDF_MODE:
+        kctx->mode = p1;
+        return 1;
+
     case EVP_PKEY_CTRL_HKDF_SALT:
         if (p1 == 0 || p2 == NULL)
             return 1;
@@ -128,6 +133,21 @@ static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
                               const char *value)
 {
+    if (strcmp(type, "mode") == 0) {
+        int mode;
+
+        if (strcmp(value, "EXTRACT_AND_EXPAND") == 0)
+            mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND;
+        else if (strcmp(value, "EXTRACT_ONLY") == 0)
+            mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
+        else if (strcmp(value, "EXPAND_ONLY") == 0)
+            mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
+        else
+            return 0;
+
+        return EVP_PKEY_CTX_hkdf_mode(ctx, mode);
+    }
+
     if (strcmp(type, "md") == 0)
         return EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_get_digestbyname(value));
 
@@ -160,13 +180,27 @@ static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
     if (kctx->md == NULL || kctx->key == NULL)
         return 0;
 
-    if (HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key, kctx->key_len,
-             kctx->info, kctx->info_len, key, *keylen) == NULL)
-    {
+    switch (kctx->mode) {
+    case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
+        return HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
+                    kctx->key_len, kctx->info, kctx->info_len, key,
+                    *keylen) != NULL;
+
+    case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
+        if (key == NULL) {
+            *keylen = EVP_MD_size(kctx->md);
+            return 1;
+        }
+        return HKDF_Extract(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
+                            kctx->key_len, key, keylen) != NULL;
+
+    case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
+        return HKDF_Expand(kctx->md, kctx->key, kctx->key_len, kctx->info,
+                           kctx->info_len, key, *keylen) != NULL;
+
+    default:
         return 0;
     }
-
-    return 1;
 }
 
 const EVP_PKEY_METHOD hkdf_pkey_meth = {
@@ -206,12 +240,16 @@ static unsigned char *HKDF(const EVP_MD *evp_md,
                            unsigned char *okm, size_t okm_len)
 {
     unsigned char prk[EVP_MAX_MD_SIZE];
+    unsigned char *ret;
     size_t prk_len;
 
     if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len))
         return NULL;
 
-    return HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
+    ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
+    OPENSSL_cleanse(prk, sizeof(prk));
+
+    return ret;
 }
 
 static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
@@ -245,7 +283,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
     if (okm_len % dig_len)
         n++;
 
-    if (n > 255)
+    if (n > 255 || okm == NULL)
         return NULL;
 
     if ((hmac = HMAC_CTX_new()) == NULL)
diff --git a/doc/man3/EVP_PKEY_CTX_set_hkdf_md.pod b/doc/man3/EVP_PKEY_CTX_set_hkdf_md.pod
index 61e0eec..1115e13 100644
--- a/doc/man3/EVP_PKEY_CTX_set_hkdf_md.pod
+++ b/doc/man3/EVP_PKEY_CTX_set_hkdf_md.pod
@@ -3,13 +3,16 @@
 =head1 NAME
 
 EVP_PKEY_CTX_set_hkdf_md, EVP_PKEY_CTX_set1_hkdf_salt,
-EVP_PKEY_CTX_set1_hkdf_key, EVP_PKEY_CTX_add1_hkdf_info -
+EVP_PKEY_CTX_set1_hkdf_key, EVP_PKEY_CTX_add1_hkdf_info,
+EVP_PKEY_CTX_hkdf_mode -
 HMAC-based Extract-and-Expand key derivation algorithm
 
 =head1 SYNOPSIS
 
  #include <openssl/kdf.h>
 
+ int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *pctx, int mode);
+
  int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *pctx, const EVP_MD *md);
 
  int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *pctx, unsigned char *salt,
@@ -30,6 +33,41 @@ and "extracts" from it a fixed-length pseudorandom key K. The second stage
 "expands" the key K into several additional pseudorandom keys (the output
 of the KDF).
 
+EVP_PKEY_CTX_hkdf_mode() sets the mode for the HKDF operation. There are three
+modes that are currently defined:
+
+=over 4
+
+=item EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND
+
+This is the default mode. Calling L<EVP_PKEY_derive(3)> on an EVP_PKEY_CTX set
+up for HKDF will perform an extract followed by an expand operation in one go.
+The derived key returned will be the result after the expand operation. The
+intermediate fixed-length pseudorandom key K is not returned.
+
+In this mode the digest, key, salt and info values must be set before a key is
+derived or an error occurs.
+
+=item EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY
+
+In this mode calling L<EVP_PKEY_derive(3)> will just perform the extract
+operation. The value returned will be the intermediate fixed-length pseudorandom
+key K.
+
+The digest, key and salt values must be set before a key is derived or an
+error occurs.
+
+=item EVP_PKEY_HKDEF_MODE_EXPAND_ONLY
+
+In this mode calling L<EVP_PKEY_derive(3)> will just perform the expand
+operation. The input key should be set to the intermediate fixed-length
+pseudorandom key K returned from a previous extract operation.
+
+The digest, key and info values must be set before a key is derived or an
+error occurs.
+
+=back
+
 EVP_PKEY_set_hkdf_md() sets the message digest associated with the HKDF.
 
 EVP_PKEY_CTX_set1_hkdf_salt() sets the salt to B<saltlen> bytes of the
@@ -48,6 +86,8 @@ HKDF also supports string based control operations via
 L<EVP_PKEY_CTX_ctrl_str(3)>.
 The B<type> parameter "md" uses the supplied B<value> as the name of the digest
 algorithm to use.
+The B<type> parameter "mode" uses the values "EXTRACT_AND_EXPAND",
+"EXTRACT_ONLY" and "EXPAND_ONLY" to determine the mode to use.
 The B<type> parameters "salt", "key" and "info" use the supplied B<value>
 parameter as a B<seed>, B<key> or B<info> value.
 The names "hexsalt", "hexkey" and "hexinfo" are similar except they take a hex
@@ -61,19 +101,17 @@ A context for HKDF can be obtained by calling:
 
  EVP_PKEY_CTX *pctx = EVP_PKEY_new_id(EVP_PKEY_HKDF, NULL);
 
-The digest, key, salt and info values must be set before a key is derived or
-an error occurs.
-
 The total length of the info buffer cannot exceed 1024 bytes in length: this
 should be more than enough for any normal use of HKDF.
 
-The output length of the KDF is specified via the length parameter to the
-L<EVP_PKEY_derive(3)> function.
+The output length of an HKDF expand operation is specified via the length
+parameter to the L<EVP_PKEY_derive(3)> function.
 Since the HKDF output length is variable, passing a B<NULL> buffer as a means
-to obtain the requisite length is not meaningful with HKDF.
-Instead, the caller must allocate a buffer of the desired length, and pass that
-buffer to L<EVP_PKEY_derive(3)> along with (a pointer initialized to) the
-desired length.
+to obtain the requisite length is not meaningful with HKDF in any mode that
+performs an expand operation. Instead, the caller must allocate a buffer of the
+desired length, and pass that buffer to L<EVP_PKEY_derive(3)> along with (a
+pointer initialized to) the desired length. Passing a B<NULL> buffer to obtain
+the length is allowed when using EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY.
 
 Optimised versions of HKDF can be implemented in an ENGINE.
 
@@ -97,9 +135,9 @@ salt value "salt" and info value "label":
     /* Error */
  if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0)
     /* Error */
- if (EVP_PKEY_CTX_set1_salt(pctx, "salt", 4) <= 0)
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "salt", 4) <= 0)
     /* Error */
- if (EVP_PKEY_CTX_set1_key(pctx, "secret", 6) <= 0)
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, "secret", 6) <= 0)
     /* Error */
  if (EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 6) <= 0)
     /* Error */
diff --git a/include/openssl/kdf.h b/include/openssl/kdf.h
index 9f87f78..0df4532 100644
--- a/include/openssl/kdf.h
+++ b/include/openssl/kdf.h
@@ -14,13 +14,18 @@
 extern "C" {
 #endif
 
-# define EVP_PKEY_CTRL_TLS_MD       (EVP_PKEY_ALG_CTRL)
-# define EVP_PKEY_CTRL_TLS_SECRET   (EVP_PKEY_ALG_CTRL + 1)
-# define EVP_PKEY_CTRL_TLS_SEED     (EVP_PKEY_ALG_CTRL + 2)
-# define EVP_PKEY_CTRL_HKDF_MD      (EVP_PKEY_ALG_CTRL + 3)
-# define EVP_PKEY_CTRL_HKDF_SALT    (EVP_PKEY_ALG_CTRL + 4)
-# define EVP_PKEY_CTRL_HKDF_KEY     (EVP_PKEY_ALG_CTRL + 5)
-# define EVP_PKEY_CTRL_HKDF_INFO    (EVP_PKEY_ALG_CTRL + 6)
+# define EVP_PKEY_CTRL_TLS_MD                   (EVP_PKEY_ALG_CTRL)
+# define EVP_PKEY_CTRL_TLS_SECRET               (EVP_PKEY_ALG_CTRL + 1)
+# define EVP_PKEY_CTRL_TLS_SEED                 (EVP_PKEY_ALG_CTRL + 2)
+# define EVP_PKEY_CTRL_HKDF_MD                  (EVP_PKEY_ALG_CTRL + 3)
+# define EVP_PKEY_CTRL_HKDF_SALT                (EVP_PKEY_ALG_CTRL + 4)
+# define EVP_PKEY_CTRL_HKDF_KEY                 (EVP_PKEY_ALG_CTRL + 5)
+# define EVP_PKEY_CTRL_HKDF_INFO                (EVP_PKEY_ALG_CTRL + 6)
+# define EVP_PKEY_CTRL_HKDF_MODE                (EVP_PKEY_ALG_CTRL + 7)
+
+# define EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND 0
+# define EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY       1
+# define EVP_PKEY_HKDEF_MODE_EXPAND_ONLY        2
 
 # define EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) \
             EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
@@ -50,6 +55,10 @@ extern "C" {
             EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
                               EVP_PKEY_CTRL_HKDF_INFO, infolen, (void *)info)
 
+# define EVP_PKEY_CTX_hkdf_mode(pctx, mode) \
+            EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \
+                              EVP_PKEY_CTRL_HKDF_MODE, mode, NULL)
+
 /* BEGIN ERROR CODES */
 /*
  * The following lines are auto generated by the script mkerr.pl. Any changes
diff --git a/ssl/build.info b/ssl/build.info
index c7d4574..72b8dfc 100644
--- a/ssl/build.info
+++ b/ssl/build.info
@@ -3,7 +3,7 @@ SOURCE[../libssl]=\
         pqueue.c packet.c \
         statem/statem_srvr.c statem/statem_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
         statem/statem_lib.c s3_cbc.c s3_msg.c \
-        methods.c   t1_lib.c  t1_enc.c t1_ext.c \
+        methods.c   t1_lib.c  t1_enc.c tls13_enc.c t1_ext.c \
         d1_lib.c  record/rec_layer_d1.c d1_msg.c \
         statem/statem_dtls.c d1_srtp.c \
         ssl_lib.c ssl_cert.c ssl_sess.c \
diff --git a/ssl/packet.c b/ssl/packet.c
index 27462e9..5c55133 100644
--- a/ssl/packet.c
+++ b/ssl/packet.c
@@ -33,6 +33,9 @@ int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
     return 1;
 }
 
+#define GETBUF(p)   (((p)->staticbuf != NULL) \
+                     ? (p)->staticbuf : (unsigned char *)(p)->buf->data)
+
 int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
 {
     /* Internal API, so should not fail */
@@ -43,7 +46,7 @@ int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
     if (pkt->maxsize - pkt->written < len)
         return 0;
 
-    if (pkt->buf->length - pkt->written < len) {
+    if (pkt->staticbuf == NULL && (pkt->buf->length - pkt->written < len)) {
         size_t newlen;
         size_t reflen;
 
@@ -59,7 +62,7 @@ int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
         if (BUF_MEM_grow(pkt->buf, newlen) == 0)
             return 0;
     }
-    *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
+    *allocbytes = GETBUF(pkt) + pkt->curr;
 
     return 1;
 }
@@ -83,19 +86,12 @@ static size_t maxmaxsize(size_t lenbytes)
     return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
 }
 
-int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
+static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes)
 {
     unsigned char *lenchars;
 
-    /* Internal API, so should not fail */
-    assert(buf != NULL);
-    if (buf == NULL)
-        return 0;
-
-    pkt->buf = buf;
     pkt->curr = 0;
     pkt->written = 0;
-    pkt->maxsize = maxmaxsize(lenbytes);
 
     pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
     if (pkt->subs == NULL)
@@ -112,11 +108,42 @@ int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
         pkt->subs = NULL;
         return 0;
     }
-    pkt->subs->packet_len = lenchars - (unsigned char *)pkt->buf->data;
+    pkt->subs->packet_len = lenchars - GETBUF(pkt);
 
     return 1;
 }
 
+int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len,
+                            size_t lenbytes)
+{
+    size_t max = maxmaxsize(lenbytes);
+
+    /* Internal API, so should not fail */
+    assert(buf != NULL && len > 0);
+    if (buf == NULL || len == 0)
+        return 0;
+
+    pkt->staticbuf = buf;
+    pkt->buf = NULL;
+    pkt->maxsize = (max < len) ? max : len;
+
+    return wpacket_intern_init_len(pkt, lenbytes);
+}
+
+int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
+{
+    /* Internal API, so should not fail */
+    assert(buf != NULL);
+    if (buf == NULL)
+        return 0;
+
+    pkt->staticbuf = NULL;
+    pkt->buf = buf;
+    pkt->maxsize = maxmaxsize(lenbytes);
+
+    return wpacket_intern_init_len(pkt, lenbytes);
+}
+
 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
 {
     return WPACKET_init_len(pkt, buf, 0);
@@ -179,8 +206,8 @@ static int wpacket_intern_close(WPACKET *pkt)
 
     /* Write out the WPACKET length if needed */
     if (sub->lenbytes > 0
-                && !put_value((unsigned char *)&pkt->buf->data[sub->packet_len],
-                              packlen, sub->lenbytes))
+                && !put_value(&GETBUF(pkt)[sub->packet_len], packlen,
+                              sub->lenbytes))
             return 0;
 
     pkt->subs = sub->parent;
@@ -248,7 +275,7 @@ int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes)
     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
         return 0;
     /* Convert to an offset in case the underlying BUF_MEM gets realloc'd */
-    sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
+    sub->packet_len = lenchars - GETBUF(pkt);
 
     return 1;
 }
diff --git a/ssl/packet_locl.h b/ssl/packet_locl.h
index 94933c1..4658734 100644
--- a/ssl/packet_locl.h
+++ b/ssl/packet_locl.h
@@ -625,6 +625,9 @@ struct wpacket_st {
     /* The buffer where we store the output data */
     BUF_MEM *buf;
 
+    /* Fixed sized buffer which can be used as an alternative to buf */
+    unsigned char *staticbuf;
+
     /*
      * Offset into the buffer where we are currently writing. We use an offset
      * in case the buffer grows and gets reallocated.
@@ -671,6 +674,13 @@ int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes);
 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf);
 
 /*
+ * Same as WPACKET_init_len except we do not use a growable BUF_MEM structure.
+ * A fixed buffer of memory |buf| of size |len| is used instead. A failure will
+ * occur if you attempt to write beyond the end of the buffer
+ */
+int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len,
+                            size_t lenbytes);
+/*
  * Set the flags to be applied to the current sub-packet
  */
 int WPACKET_set_flags(WPACKET *pkt, unsigned int flags);
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index dcc2336..0c7aeed 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -944,6 +944,12 @@ struct ssl_st {
      * be 'copied' into these ones
      */
     uint32_t mac_flags;
+    /*
+     * The TLS1.3 early_secret and handshake_secret. The master_secret is stored
+     * in the session.
+     */
+    unsigned char early_secret[EVP_MAX_MD_SIZE];
+    unsigned char handshake_secret[EVP_MAX_MD_SIZE];
     EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
     EVP_MD_CTX *read_hash;      /* used for mac generation */
     COMP_CTX *compress;         /* compression */
@@ -2004,6 +2010,21 @@ __owur size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
 __owur int tls1_generate_master_secret(SSL *s, unsigned char *out,
                                        unsigned char *p, size_t len,
                                        size_t *secret_size);
+__owur int tls13_derive_secret(SSL *s, const unsigned char *insecret,
+                               const unsigned char *label, size_t labellen,
+                               unsigned char *secret);
+__owur int tls13_derive_key(SSL *s, const unsigned char *secret,
+                            unsigned char *key, size_t keylen);
+__owur int tls13_derive_iv(SSL *s, const unsigned char *secret,
+                           unsigned char *iv, size_t ivlen);
+__owur int tls13_generate_early_secret(SSL *s, const unsigned char *insecret,
+                                       size_t insecretlen);
+__owur int tls13_generate_handshake_secret(SSL *s,
+                                           const unsigned char *insecret,
+                                           size_t insecretlen);
+__owur int tls13_generate_master_secret(SSL *s, unsigned char *out,
+                                        unsigned char *prev, size_t prevlen,
+                                        size_t *secret_size);
 __owur int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
                                        const char *label, size_t llen,
                                        const unsigned char *p, size_t plen,
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
new file mode 100644
index 0000000..39a61f4
--- /dev/null
+++ b/ssl/tls13_enc.c
@@ -0,0 +1,217 @@
+/*
+ * 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 <stdlib.h>
+#include "ssl_locl.h"
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+
+#define TLS13_MAX_LABEL_LEN     246
+
+/* Always filled with zeros */
+static const unsigned char default_zeros[EVP_MAX_MD_SIZE];
+
+static const unsigned char keylabel[] = "key";
+static const unsigned char ivlabel[] = "iv";
+
+/*
+ * Given a |secret|; a |label| of length |labellen|; and a |hash| of the
+ * handshake messages, derive a new secret |outlen| bytes long and store it in
+ * the location pointed to be |out|. The |hash| value may be NULL.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+static int tls13_hkdf_expand(SSL *s, const unsigned char *secret,
+                             const unsigned char *label, size_t labellen,
+                             const unsigned char *hash,
+                             unsigned char *out, size_t outlen)
+{
+    const unsigned char label_prefix[] = "TLS 1.3, ";
+    const EVP_MD *md = ssl_handshake_md(s);
+    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+    int ret;
+    size_t hkdflabellen;
+    size_t hashlen;
+    /*
+     * 2 bytes for length of whole HkdfLabel + 1 byte for length of combined
+     * prefix and label + bytes for the label itself + bytes for the hash
+     */
+    unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t) +
+                            + sizeof(label_prefix) + TLS13_MAX_LABEL_LEN
+                            + EVP_MAX_MD_SIZE];
+    WPACKET pkt;
+
+    if (pctx == NULL)
+        return 0;
+
+    hashlen = EVP_MD_size(md);
+
+    if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0)
+            || !WPACKET_put_bytes_u16(&pkt, outlen)
+            || !WPACKET_start_sub_packet_u8(&pkt)
+            || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1)
+            || !WPACKET_memcpy(&pkt, label, labellen)
+            || !WPACKET_close(&pkt)
+            || !WPACKET_sub_memcpy_u8(&pkt, hash, (hash == NULL) ? 0 : hashlen)
+            || !WPACKET_get_total_written(&pkt, &hkdflabellen)
+            || !WPACKET_finish(&pkt)) {
+        WPACKET_cleanup(&pkt);
+        return 0;
+    }
+
+    ret = EVP_PKEY_derive_init(pctx) <= 0
+            || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY)
+               <= 0
+            || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0
+            || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0
+            || EVP_PKEY_derive(pctx, out, &outlen) <= 0;
+
+    EVP_PKEY_CTX_free(pctx);
+
+    return ret == 0;
+}
+
+/*
+ * Given a input secret |insecret| and a |label| of length |labellen|, derive a
+ * new |secret|. This will be the length of the current hash output size and
+ * will be based on the current state of the handshake hashes.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_derive_secret(SSL *s, const unsigned char *insecret,
+                        const unsigned char *label, size_t labellen,
+                        unsigned char *secret)
+{
+    unsigned char hash[EVP_MAX_MD_SIZE];
+    size_t hashlen;
+
+    if (!ssl3_digest_cached_records(s, 1))
+        return 0;
+
+    if (!ssl_handshake_hash(s, hash, sizeof(hash), &hashlen))
+        return 0;
+
+    return tls13_hkdf_expand(s, insecret, label, labellen, hash, secret,
+                             hashlen);
+}
+
+/*
+ * Given a |secret| generate a |key| of length |keylen| bytes.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_derive_key(SSL *s, const unsigned char *secret, unsigned char *key,
+                     size_t keylen)
+{
+    return tls13_hkdf_expand(s, secret, keylabel, sizeof(keylabel) - 1, NULL,
+                             key, keylen);
+}
+
+/*
+ * Given a |secret| generate an |iv| of length |ivlen| bytes.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_derive_iv(SSL *s, const unsigned char *secret, unsigned char *iv,
+                    size_t ivlen)
+{
+    return tls13_hkdf_expand(s, secret, ivlabel, sizeof(ivlabel) - 1, NULL,
+                             iv, ivlen);
+}
+
+/*
+ * Given the previous secret |prevsecret| and a new input secret |insecret| of
+ * length |insecretlen|, generate a new secret and store it in the location
+ * pointed to by |outsecret|.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+static int tls13_generate_secret(SSL *s, const unsigned char *prevsecret,
+                                 const unsigned char *insecret,
+                                 size_t insecretlen,
+                                 unsigned char *outsecret)
+{
+    const EVP_MD *md = ssl_handshake_md(s);
+    size_t mdlen, prevsecretlen;
+    int ret;
+    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+
+    if (pctx == NULL)
+        return 0;
+
+    mdlen = EVP_MD_size(md);
+
+    if (insecret == NULL) {
+        insecret = default_zeros;
+        insecretlen = mdlen;
+    }
+    if (prevsecret == NULL) {
+        prevsecret = default_zeros;
+        prevsecretlen = 0;
+    } else {
+        prevsecretlen = mdlen;
+    }
+
+    ret = EVP_PKEY_derive_init(pctx) <= 0
+            || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY)
+               <= 0
+            || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_key(pctx, insecret, insecretlen) <= 0
+            || EVP_PKEY_CTX_set1_hkdf_salt(pctx, prevsecret, prevsecretlen)
+               <= 0
+            || EVP_PKEY_derive(pctx, outsecret, &mdlen)
+               <= 0;
+
+    EVP_PKEY_CTX_free(pctx);
+    return ret == 0;
+}
+
+/*
+ * Given an input secret |insecret| of length |insecretlen| generate the early
+ * secret.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_generate_early_secret(SSL *s, const unsigned char *insecret,
+                                size_t insecretlen)
+{
+    return tls13_generate_secret(s, NULL, insecret, insecretlen,
+                                 (unsigned char *)&s->early_secret);
+}
+
+/*
+ * Given an input secret |insecret| of length |insecretlen| generate the
+ * handshake secret. This requires the early secret to already have been
+ * generated.
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_generate_handshake_secret(SSL *s, const unsigned char *insecret,
+                                size_t insecretlen)
+{
+    return tls13_generate_secret(s, s->early_secret, insecret, insecretlen,
+                                 (unsigned char *)&s->handshake_secret);
+}
+
+/*
+ * Given the handshake secret |prev| of length |prevlen| generate the master
+ * secret and store its length in |*secret_size|
+ *
+ * Returns 1 on success  0 on failure.
+ */
+int tls13_generate_master_secret(SSL *s, unsigned char *out,
+                                 unsigned char *prev, size_t prevlen,
+                                 size_t *secret_size)
+{
+    *secret_size = EVP_MD_size(ssl_handshake_md(s));
+    return tls13_generate_secret(s, prev, NULL, 0, out);
+}
+
+
diff --git a/test/build.info b/test/build.info
index 719ae44..6ec03f7 100644
--- a/test/build.info
+++ b/test/build.info
@@ -385,6 +385,17 @@ IF[{- !$disabled{tests} -}]
   SOURCE[mdc2_internal_test]=mdc2_internal_test.c testutil.c
   INCLUDE[mdc2_internal_test]=.. ../include
   DEPEND[mdc2_internal_test]=../libcrypto
+
+  # We disable this test completely in a shared build because it deliberately
+  # redefines some internal libssl symbols. This doesn't work in a non-shared
+  # build
+  IF[{- !$disabled{shared} -}]
+    PROGRAMS_NO_INST=tls13secretstest
+    SOURCE[tls13secretstest]=tls13secretstest.c testutil.c
+    SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../ssl/packet.c
+    INCLUDE[tls13secretstest]=.. ../include
+    DEPEND[tls13secretstest]=../libcrypto ../libssl
+  ENDIF
 ENDIF
 
 {-
diff --git a/test/evptests.txt b/test/evptests.txt
index b0d0992..5c427b3 100644
--- a/test/evptests.txt
+++ b/test/evptests.txt
@@ -3364,6 +3364,20 @@ Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9
 Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+Ctrl.salt = hexsalt:000102030405060708090a0b0c
+Output = 077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5
+Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9
+Output = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865
+
+KDF = HKDF
 Ctrl.md = md:SHA256
 Ctrl.IKM = hexkey:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
 Ctrl.salt = hexsalt:606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
@@ -3371,6 +3385,20 @@ Ctrl.info = hexinfo:b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd
 Output = b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
+Ctrl.salt = hexsalt:606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
+Output = 06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244
+Ctrl.info = hexinfo:b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+Output = b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87
+
+KDF = HKDF
 Ctrl.md = md:SHA256
 Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
 Ctrl.salt = salt:
@@ -3378,6 +3406,21 @@ Ctrl.info = info:
 Output = 8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+Ctrl.salt = salt:
+Ctrl.info = info:
+Output = 19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA256
+Ctrl.IKM = hexkey:19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04
+Ctrl.info = info:
+Output = 8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8
+
+KDF = HKDF
 Ctrl.md = md:SHA1
 Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b
 Ctrl.salt = hexsalt:000102030405060708090a0b0c
@@ -3385,6 +3428,20 @@ Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9
 Output = 085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b
+Ctrl.salt = hexsalt:000102030405060708090a0b0c
+Output = 9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243
+Ctrl.info = hexinfo:f0f1f2f3f4f5f6f7f8f9
+Output = 085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896
+
+KDF = HKDF
 Ctrl.md = md:SHA1
 Ctrl.IKM = hexkey:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
 Ctrl.salt = hexsalt:606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
@@ -3392,9 +3449,37 @@ Ctrl.info = hexinfo:b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd
 Output = 0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
+Ctrl.salt = hexsalt:606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
+Output = 8adae09a2a307059478d309b26c4115a224cfaf6
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:8adae09a2a307059478d309b26c4115a224cfaf6
+Ctrl.info = hexinfo:b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+Output = 0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4
+
+KDF = HKDF
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+Ctrl.salt = salt:
+Ctrl.info = info:
+Output = 0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918
+
+KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
 Ctrl.md = md:SHA1
 Ctrl.IKM = hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
 Ctrl.salt = salt:
+Output = da8c8a73c7fa77288ec6f5e7c297786aa0d32d01
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:da8c8a73c7fa77288ec6f5e7c297786aa0d32d01
 Ctrl.info = info:
 Output = 0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918
 
@@ -3406,6 +3491,20 @@ Ctrl.info = info:
 Output = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
 
 KDF = HKDF
+Ctrl.mode = mode:EXTRACT_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+Ctrl.salt = salt:
+Output = 2adccada18779e7c2077ad2eb19d3f3e731385dd
+
+KDF = HKDF
+Ctrl.mode = mode:EXPAND_ONLY
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:2adccada18779e7c2077ad2eb19d3f3e731385dd
+Ctrl.info = info:
+Output = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
+
+KDF = HKDF
 Ctrl.IKM = hexkey:0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
 Ctrl.salt = salt:
 Ctrl.info = info:
@@ -3431,6 +3530,13 @@ Ctrl.IKM = hexkey:0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
 Ctrl.salt = salt:
 Output = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
 
+KDF = HKDF
+Ctrl.mode = mode:EXTRACT_AND_EXPAND
+Ctrl.md = md:SHA1
+Ctrl.IKM = hexkey:0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+Ctrl.salt = salt:
+Output = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
+
 # ECDH tests
 
 Derive=P-256
diff --git a/test/recipes/80-test_dtls_mtu.t b/test/recipes/90-test_tls13secrets.t
similarity index 67%
copy from test/recipes/80-test_dtls_mtu.t
copy to test/recipes/90-test_tls13secrets.t
index 86d7de0..5490885 100644
--- a/test/recipes/80-test_dtls_mtu.t
+++ b/test/recipes/90-test_tls13secrets.t
@@ -6,16 +6,15 @@
 # in the file LICENSE in the source distribution or at
 # https://www.openssl.org/source/license.html
 
-
 use OpenSSL::Test;
 use OpenSSL::Test::Utils;
 
-my $test_name = "test_dtls_mtu";
+my $test_name = "tls13secrets";
 setup($test_name);
 
-plan skip_all => "$test_name needs DTLS and PSK support enabled"
-    if disabled("dtls1_2") || disabled("psk");
+plan skip_all => "$test_name is not supported in this build"
+    if disabled("tls1_3") || disabled("shared");
 
 plan tests => 1;
 
-ok(run(test(["dtls_mtu_test"])), "running dtls_mtu_test");
+ok(run(test(["tls13secretstest"])), "running tls13secretstest");
diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
new file mode 100644
index 0000000..6b6c9bc
--- /dev/null
+++ b/test/tls13secretstest.c
@@ -0,0 +1,353 @@
+/*
+ * 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 <openssl/ssl.h>
+#include <openssl/evp.h>
+#include "../ssl/ssl_locl.h"
+
+#include "testutil.h"
+
+#define IVLEN   12
+#define KEYLEN  16
+
+/* The following are unofficial test vectors generated from a locally modified
+ * version of picotls.
+ * TODO(TLS1.3): As and when official vectors become available we should use
+ * those, e.g. see
+ * https://www.ietf.org/id/draft-thomson-tls-tls13-vectors-00.txt, however at
+ * the time of writing these are not suitable because they are based on
+ * draft -16, which works slightly differently to the draft -18 vectors below.
+ */
+
+static unsigned char hs_start_hash[] = {
+0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e,
+0x41, 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74,
+0x82, 0xaf, 0x75, 0x88, 0x1c, 0x0a
+};
+
+static unsigned char hs_full_hash[] = {
+0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91,
+0x8e, 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30,
+0xac, 0x30, 0xbb, 0xeb, 0x23, 0xe2,
+};
+
+static unsigned char early_secret[] = {
+0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b, 0x09, 0xe6, 0xcd, 0x98, 0x93,
+0x68, 0x0c, 0xe2, 0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f, 0x26, 0x60, 0xe1, 0xb2,
+0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a
+};
+
+static unsigned char ecdhe_secret[] = {
+0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6,
+0x9d, 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15,
+0xe3, 0x12, 0x71, 0xdf, 0x4b, 0x40
+};
+
+static unsigned char handshake_secret[] = {
+0xdf, 0xc9, 0x41, 0xd8, 0x26, 0x93, 0x2a, 0x59, 0x11, 0xb3, 0xb7, 0xd0, 0x38,
+0xcb, 0x65, 0x6f, 0xda, 0xaf, 0x77, 0x07, 0x1e, 0x40, 0x9a, 0x9b, 0xa6, 0xca,
+0x74, 0xda, 0x17, 0xb4, 0xe0, 0x04,
+};
+
+static const char *client_hts_label = "client handshake traffic secret";
+
+static unsigned char client_hts[] = {
+0x4b, 0x38, 0x48, 0xf1, 0x5d, 0xb1, 0x5e, 0x88, 0xcf, 0x3e, 0x3b, 0xff, 0xa6,
+0xba, 0x02, 0xc1, 0xc5, 0xd1, 0xe5, 0xb1, 0xc3, 0xf3, 0x10, 0xdf, 0xe5, 0xc9,
+0x69, 0x5a, 0x4a, 0xc6, 0x06, 0x38,
+};
+
+static unsigned char client_hts_key[] = {
+0xe5, 0x7b, 0x8c, 0x38, 0x6d, 0x6f, 0x09, 0x14, 0xe2, 0xe5, 0x4e, 0x36, 0x23,
+0x91, 0x2a, 0xd4
+};
+
+static unsigned char client_hts_iv[] = {
+0x4d, 0x2e, 0x61, 0x0c, 0x4d, 0x3a, 0x8e, 0x5f, 0x15, 0x41, 0x1e, 0xfd
+};
+
+static const char *server_hts_label = "server handshake traffic secret";
+
+static unsigned char server_hts[] = {
+0x74, 0x1f, 0xb3, 0xb8, 0x41, 0x24, 0xc4, 0x7e, 0x1b, 0x2e, 0xa9, 0x4f, 0x0c,
+0x42, 0xc9, 0x06, 0xb7, 0x7c, 0x84, 0x92, 0x05, 0xed, 0x5f, 0x19, 0xda, 0xbb,
+0xbb, 0xce, 0xc7, 0x29, 0x06, 0x7e,
+};
+
+static unsigned char server_hts_key[] = {
+0x72, 0x61, 0x1c, 0xc8, 0x0d, 0x65, 0x9c, 0x89, 0xf8, 0x94, 0x9e, 0x32, 0x67,
+0xe1, 0x6c, 0x2d
+
+};
+
+static unsigned char server_hts_iv[] = {
+0x43, 0xfe, 0x11, 0x29, 0x0f, 0xe8, 0xfe, 0x84, 0x9c, 0x9b, 0x21, 0xef,
+};
+
+static unsigned char master_secret[] = {
+0xfe, 0x8d, 0xfb, 0xd0, 0x14, 0x94, 0x4e, 0x22, 0x65, 0x16, 0x7d, 0xc4, 0x20,
+0x01, 0x5b, 0x10, 0x64, 0x74, 0xb7, 0x22, 0x9a, 0x95, 0xd1, 0x48, 0x0c, 0xb9,
+0xac, 0xd1, 0xa0, 0x28, 0xb7, 0x67
+};
+
+static const char *client_ats_label = "client application traffic secret";
+
+static unsigned char client_ats[] = {
+0x56, 0x9e, 0x9c, 0x17, 0xe3, 0x52, 0x1f, 0xdd, 0x09, 0xf4, 0xb8, 0x4f, 0x6c,
+0xd6, 0x6d, 0xa8, 0x23, 0xde, 0xeb, 0x81, 0xbb, 0xb1, 0xde, 0x61, 0xe2, 0x82,
+0x56, 0x27, 0xf7, 0x00, 0x63, 0x81,
+};
+
+static unsigned char client_ats_key[] = {
+0xcb, 0xfa, 0xae, 0x71, 0x8d, 0xfb, 0x52, 0xba, 0x7b, 0x87, 0xde, 0x8b, 0x6d,
+0xac, 0x92, 0x60
+};
+
+static unsigned char client_ats_iv[] = {
+0x74, 0x86, 0x88, 0xe9, 0x7f, 0x72, 0xfb, 0xf3, 0x33, 0x1e, 0xfb, 0x55
+};
+
+static const char *server_ats_label = "server application traffic secret";
+
+static unsigned char server_ats[] = {
+0xd1, 0xbf, 0xdc, 0x8b, 0x84, 0xf4, 0x16, 0xb7, 0xc6, 0x90, 0xd9, 0xc9, 0x2c,
+0x23, 0x11, 0xb3, 0x05, 0xad, 0x75, 0xfc, 0xe6, 0x29, 0x90, 0x2b, 0xe1, 0x03,
+0xdd, 0x0c, 0x12, 0x51, 0xea, 0xd2,
+};
+
+static unsigned char server_ats_key[] = {
+0x35, 0xc2, 0xd1, 0x54, 0xa8, 0x43, 0x03, 0xc6, 0x55, 0xa0, 0x2e, 0x5e, 0x1f,
+0x82, 0x31, 0x62
+};
+
+static unsigned char server_ats_iv[] = {
+0xe5, 0x77, 0xd9, 0x8a, 0xb3, 0x2e, 0xec, 0x79, 0xb1, 0x63, 0x68, 0xc2
+};
+
+/* Mocked out implementations of various functions */
+int ssl3_digest_cached_records(SSL *s, int keep)
+{
+    return 1;
+}
+
+static int full_hash = 0;
+
+/* Give a hash of the currently set handshake */
+int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen,
+                       size_t *hashlen)
+{
+    if (sizeof(hs_start_hash) > outlen
+            || sizeof(hs_full_hash) != sizeof(hs_start_hash))
+        return 0;
+
+    if (full_hash) {
+        memcpy(out, hs_full_hash, sizeof(hs_full_hash));
+        *hashlen = sizeof(hs_full_hash);
+    } else {
+        memcpy(out, hs_start_hash, sizeof(hs_start_hash));
+        *hashlen = sizeof(hs_start_hash);
+    }
+
+    return 1;
+}
+
+const EVP_MD *ssl_handshake_md(SSL *s)
+{
+    return EVP_sha256();
+}
+
+/* End of mocked out code */
+
+static int test_secret(SSL *s, unsigned char *prk,
+                       const unsigned char *label, size_t labellen,
+                       const unsigned char *ref_secret,
+                       const unsigned char *ref_key, const unsigned char *ref_iv)
+{
+    size_t hashsize = EVP_MD_size(ssl_handshake_md(s));
+    unsigned char gensecret[EVP_MAX_MD_SIZE];
+    unsigned char key[KEYLEN];
+    unsigned char iv[IVLEN];
+
+    if (!tls13_derive_secret(s, prk, label, labellen, gensecret)) {
+        fprintf(stderr, "Secret generation failed\n");
+        return 0;
+    }
+
+    if (memcmp(gensecret, ref_secret, hashsize) != 0) {
+        fprintf(stderr, "Generated secret does not match\n");
+        return 0;
+    }
+
+    if (!tls13_derive_key(s, gensecret, key, KEYLEN)) {
+        fprintf(stderr, "Key generation failed\n");
+        return 0;
+    }
+
+    if (memcmp(key, ref_key, KEYLEN) != 0) {
+        fprintf(stderr, "Generated key does not match\n");
+        return 0;
+    }
+
+    if (!tls13_derive_iv(s, gensecret, iv, IVLEN)) {
+        fprintf(stderr, "IV generation failed\n");
+        return 0;
+    }
+
+    if (memcmp(iv, ref_iv, IVLEN) != 0) {
+        fprintf(stderr, "Generated IV does not match\n");
+        return 0;
+    }
+
+    return 1;
+}
+
+static int test_handshake_secrets(void)
+{
+    SSL_CTX *ctx = NULL;
+    SSL *s = NULL;
+    int ret = 0;
+    size_t hashsize;
+    unsigned char out_master_secret[EVP_MAX_MD_SIZE];
+    size_t master_secret_length;
+
+    ctx = SSL_CTX_new(TLS_method());
+    if (ctx == NULL)
+        goto err;
+
+    s = SSL_new(ctx);
+    if (s == NULL)
+        goto err;
+
+    if (!tls13_generate_early_secret(s, NULL, 0)) {
+        fprintf(stderr, "Early secret generation failed\n");
+        goto err;
+    }
+
+    if (memcmp(s->early_secret, early_secret, sizeof(early_secret)) != 0) {
+        fprintf(stderr, "Early secret does not match\n");
+        goto err;
+    }
+
+    if (!tls13_generate_handshake_secret(s, ecdhe_secret,
+                                         sizeof(ecdhe_secret))) {
+        fprintf(stderr, "Hanshake secret generation failed\n");
+        goto err;
+    }
+
+    if (memcmp(s->handshake_secret, handshake_secret,
+               sizeof(handshake_secret)) != 0) {
+        fprintf(stderr, "Handshake secret does not match\n");
+        goto err;
+    }
+
+    hashsize = EVP_MD_size(ssl_handshake_md(s));
+    if (sizeof(client_hts) != hashsize || sizeof(client_hts_key) != KEYLEN
+            || sizeof(client_hts_iv) != IVLEN) {
+        fprintf(stderr, "Internal test error\n");
+        goto err;
+    }
+
+    if (!test_secret(s, s->handshake_secret, (unsigned char *)client_hts_label,
+                     strlen(client_hts_label), client_hts, client_hts_key,
+                     client_hts_iv)) {
+        fprintf(stderr, "Client handshake secret test failed\n");
+        goto err;
+    }
+
+    if (sizeof(server_hts) != hashsize || sizeof(server_hts_key) != KEYLEN
+            || sizeof(server_hts_iv) != IVLEN) {
+        fprintf(stderr, "Internal test error\n");
+        goto err;
+    }
+
+    if (!test_secret(s, s->handshake_secret, (unsigned char *)server_hts_label,
+                     strlen(server_hts_label), server_hts, server_hts_key,
+                     server_hts_iv)) {
+        fprintf(stderr, "Server handshake secret test failed\n");
+        goto err;
+    }
+
+    /*
+     * Ensure the mocked out ssl_handshake_hash() returns the full handshake
+     * hash.
+     */
+    full_hash = 1;
+
+    if (!tls13_generate_master_secret(s, out_master_secret,
+                                      s->handshake_secret, hashsize,
+                                      &master_secret_length)) {
+        fprintf(stderr, "Master secret generation failed\n");
+        goto err;
+    }
+
+    if (master_secret_length != sizeof(master_secret) ||
+            memcmp(out_master_secret, master_secret,
+                   sizeof(master_secret)) != 0) {
+        fprintf(stderr, "Master secret does not match\n");
+        goto err;
+    }
+
+    if (sizeof(client_ats) != hashsize || sizeof(client_ats_key) != KEYLEN
+            || sizeof(client_ats_iv) != IVLEN) {
+        fprintf(stderr, "Internal test error\n");
+        goto err;
+    }
+
+    if (!test_secret(s, out_master_secret, (unsigned char *)client_ats_label,
+                     strlen(client_ats_label), client_ats, client_ats_key,
+                     client_ats_iv)) {
+        fprintf(stderr, "Client application data secret test failed\n");
+        goto err;
+    }
+
+    if (sizeof(server_ats) != hashsize || sizeof(server_ats_key) != KEYLEN
+            || sizeof(server_ats_iv) != IVLEN) {
+        fprintf(stderr, "Internal test error\n");
+        goto err;
+    }
+
+    if (!test_secret(s, out_master_secret, (unsigned char *)server_ats_label,
+                     strlen(server_ats_label), server_ats, server_ats_key,
+                     server_ats_iv)) {
+        fprintf(stderr, "Server application data secret test failed\n");
+        goto err;
+    }
+
+    ret = 1;
+ err:
+    SSL_free(s);
+    SSL_CTX_free(ctx);
+    return ret;
+}
+
+int main(int argc, char *argv[])
+{
+    BIO *err = NULL;
+    int testresult = 1;
+
+    err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+
+    CRYPTO_set_mem_debug(1);
+    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+
+    ADD_TEST(test_handshake_secrets);
+
+    testresult = run_tests(argv[0]);
+
+#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+    if (CRYPTO_mem_leaks(err) <= 0)
+        testresult = 1;
+#endif
+    BIO_free(err);
+
+    if (!testresult)
+        fprintf(stderr, "PASS\n");
+
+    return testresult;
+}
diff --git a/test/wpackettest.c b/test/wpackettest.c
index aabf781..e082b18 100644
--- a/test/wpackettest.c
+++ b/test/wpackettest.c
@@ -20,6 +20,7 @@ const static unsigned char seqsub[] = { 0x01, 0xff, 0x01, 0xff };
 const static unsigned char empty = 0x00;
 const static unsigned char alloc[] = { 0x02, 0xfe, 0xff };
 const static unsigned char submem[] = { 0x03, 0x02, 0xfe, 0xff };
+const static unsigned char fixed[] = { 0xff, 0xff, 0xff };
 
 static BUF_MEM *buf;
 
@@ -34,6 +35,7 @@ static int test_WPACKET_init(void)
     WPACKET pkt;
     int i;
     size_t written;
+    unsigned char sbuf[3];
 
     if (!WPACKET_init(&pkt, buf)
             || !WPACKET_put_bytes_u8(&pkt, 0xff)
@@ -95,6 +97,31 @@ static int test_WPACKET_init(void)
         return 0;
     }
 
+    /* Test initialising from a fixed size buffer */
+    if (!WPACKET_init_static_len(&pkt, sbuf, sizeof(sbuf), 0)
+                /* Adding 3 bytes should succeed */
+            || !WPACKET_put_bytes_u24(&pkt, 0xffffff)
+                /* Adding 1 more byte should fail */
+            ||  WPACKET_put_bytes_u8(&pkt, 0xff)
+                /* Finishing the top level WPACKET should succeed */
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(fixed)
+            || memcmp(sbuf, fixed, sizeof(sbuf)) != 0
+                /* Initialise with 1 len byte */
+            || !WPACKET_init_static_len(&pkt, sbuf, sizeof(sbuf), 1)
+                /* Adding 2 bytes should succeed */
+            || !WPACKET_put_bytes_u16(&pkt, 0xfeff)
+                /* Adding 1 more byte should fail */
+            ||  WPACKET_put_bytes_u8(&pkt, 0xff)
+            || !WPACKET_finish(&pkt)
+            || !WPACKET_get_total_written(&pkt, &written)
+            ||  written != sizeof(alloc)
+            ||  memcmp(sbuf, alloc, written) != 0) {
+        testfail("test_WPACKET_init():5 failed\n", &pkt);
+        return 0;
+    }
+
     return 1;
 }
 


More information about the openssl-commits mailing list