Implement TLS 1.3 key evolution function

Signed-off-by: Hanno Becker <hanno.becker@arm.com>
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index d9d5d98..1d61455 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -285,4 +285,66 @@
                                                   dstbuf, buflen ) );
 }
 
+int mbedtls_ssl_tls1_3_evolve_secret(
+                   mbedtls_md_type_t hash_alg,
+                   const unsigned char *secret_old,
+                   const unsigned char *input, size_t input_len,
+                   unsigned char *secret_new )
+{
+    int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+    size_t hlen, ilen;
+    unsigned char _secret[ MBEDTLS_MD_MAX_SIZE ] = { 0 };
+    unsigned char _input [ MBEDTLS_MD_MAX_SIZE ] = { 0 };
+
+    const mbedtls_md_info_t *md;
+    md = mbedtls_md_info_from_type( hash_alg );
+    if( md == NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    hlen = mbedtls_md_get_size( md );
+
+    /* For non-initial runs, call Derive-Secret( ., "derived", "")
+     * on the old secreet. */
+    if( secret_old != NULL )
+    {
+        ret = mbedtls_ssl_tls1_3_derive_secret(
+                   hash_alg,
+                   secret_old, hlen,
+                   MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( derived ),
+                   NULL, 0, /* context */
+                   MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED,
+                   _secret, hlen );
+        if( ret != 0 )
+            goto cleanup;
+    }
+
+    if( input != NULL )
+    {
+        memcpy( _input, input, input_len );
+        ilen = input_len;
+    }
+    else
+    {
+        ilen = hlen;
+    }
+
+    /* HKDF-Extract takes a salt and input key material.
+     * The salt is the old secret, and the input key material
+     * is the input secret (PSK / ECDHE). */
+    ret = mbedtls_hkdf_extract( md,
+                    _secret, hlen,
+                    _input, ilen,
+                    secret_new );
+    if( ret != 0 )
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+
+    mbedtls_platform_zeroize( _secret, sizeof(_secret) );
+    mbedtls_platform_zeroize( _input,  sizeof(_input)  );
+    return( ret );
+}
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index c877c06..a35e085 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -182,6 +182,79 @@
                    int context_already_hashed,
                    unsigned char *dstbuf, size_t buflen );
 
+/**
+ * \brief Compute the next secret in the TLS 1.3 key schedule
+ *
+ * The TLS 1.3 key schedule proceeds as follows to compute
+ * the three main secrets during the handshake: The early
+ * secret for early data, the handshake secret for all
+ * other encrypted handshake messages, and the master
+ * secret for all application traffic.
+ *
+ * <tt>
+ *                    0
+ *                    |
+ *                    v
+ *     PSK ->  HKDF-Extract = Early Secret
+ *                    |
+ *                    v
+ *     Derive-Secret( ., "derived", "" )
+ *                    |
+ *                    v
+ *  (EC)DHE -> HKDF-Extract = Handshake Secret
+ *                    |
+ *                    v
+ *     Derive-Secret( ., "derived", "" )
+ *                    |
+ *                    v
+ *     0 -> HKDF-Extract = Master Secret
+ * </tt>
+ *
+ * Each of the three secrets in turn is the basis for further
+ * key derivations, such as the derivation of traffic keys and IVs;
+ * see e.g. mbedtls_ssl_tls1_3_make_traffic_keys().
+ *
+ * This function implements one step in this evolution of secrets:
+ *
+ * <tt>
+ *                old_secret
+ *                    |
+ *                    v
+ *     Derive-Secret( ., "derived", "" )
+ *                    |
+ *                    v
+ *     input -> HKDF-Extract = new_secret
+ * </tt>
+ *
+ * \param hash_alg    The identifier for the hash function used for the
+ *                    applications of HKDF.
+ * \param secret_old  The address of the buffer holding the old secret
+ *                    on function entry. If not \c NULL, this must be a
+ *                    readable buffer whose size matches the output size
+ *                    of the hash function represented by \p hash_alg.
+ *                    If \c NULL, an all \c 0 array will be used instead.
+ * \param input       The address of the buffer holding the additional
+ *                    input for the key derivation (e.g., the PSK or the
+ *                    ephemeral (EC)DH secret). If not \c NULL, this must be
+ *                    a readable buffer whose size \p input_len Bytes.
+ *                    If \c NULL, an all \c 0 array will be used instead.
+ * \param input_len   The length of \p input in Bytes.
+ * \param secret_new  The address of the buffer holding the new secret
+ *                    on function exit. This must be a writable buffer
+ *                    whose size matches the output size of the hash
+ *                    function represented by \p hash_alg.
+ *                    This may be the same as \p secret_old.
+ *
+ * \returns           \c 0 on success.
+ * \returns           A negative error code on failure.
+ */
+
+int mbedtls_ssl_tls1_3_evolve_secret(
+                   mbedtls_md_type_t hash_alg,
+                   const unsigned char *secret_old,
+                   const unsigned char *input, size_t input_len,
+                   unsigned char *secret_new );
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
 
 #endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */