Add TLS 1.3 second level key derivations

This commit adds helper functions to ssl_tls13_keys.[ch]
allowing to derive the secrets specific to each stage of
a TLS 1.3 handshake (early, handshake, application) from
the corresponding master secret (early secret, handshake
secret, master secret).

Signed-off-by: Hanno Becker <hanno.becker@arm.com>
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index 4e8fb43..ce551f6 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -24,6 +24,7 @@
 #include "mbedtls/hkdf.h"
 #include "ssl_misc.h"
 #include "ssl_tls13_keys.h"
+#include "mbedtls/debug.h"
 
 #include <stdint.h>
 #include <string.h>
@@ -346,4 +347,222 @@
     return( ret );
 }
 
+int mbedtls_ssl_tls1_3_derive_early_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *early_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_early_secrets *derived )
+{
+    int ret;
+    mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type );
+    size_t const md_size = mbedtls_md_get_size( md_info );
+
+    /* We should never call this function with an unknown hash,
+     * but add an assertion anyway. */
+    if( md_info == 0 )
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+
+    /*
+     *            0
+     *            |
+     *            v
+     *  PSK ->  HKDF-Extract = Early Secret
+     *            |
+     *            +-----> Derive-Secret(., "ext binder" | "res binder", "")
+     *            |                     = binder_key
+     *            |
+     *            +-----> Derive-Secret(., "c e traffic", ClientHello)
+     *            |                     = client_early_traffic_secret
+     *            |
+     *            +-----> Derive-Secret(., "e exp master", ClientHello)
+     *            |                     = early_exporter_master_secret
+     *            v
+     */
+
+    /* Create client_early_traffic_secret */
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+                         early_secret, md_size,
+                         MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_e_traffic ),
+                         transcript, transcript_len,
+                         MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+                         derived->client_early_traffic_secret,
+                         md_size );
+    if( ret != 0 )
+        return( ret );
+
+    /* Create early exporter */
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+                         early_secret, md_size,
+                         MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( e_exp_master ),
+                         transcript, transcript_len,
+                         MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+                         derived->early_exporter_master_secret,
+                         md_size );
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+int mbedtls_ssl_tls1_3_derive_handshake_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *handshake_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_handshake_secrets *derived )
+{
+    int ret;
+    mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type );
+    size_t const md_size = mbedtls_md_get_size( md_info );
+
+    /* We should never call this function with an unknown hash,
+     * but add an assertion anyway. */
+    if( md_info == 0 )
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+
+    /*
+     *
+     * Handshake Secret
+     * |
+     * +-----> Derive-Secret( ., "c hs traffic",
+     * |                     ClientHello...ServerHello )
+     * |                     = client_handshake_traffic_secret
+     * |
+     * +-----> Derive-Secret( ., "s hs traffic",
+     * |                     ClientHello...ServerHello )
+     * |                     = server_handshake_traffic_secret
+     *
+     */
+
+    /*
+     * Compute client_handshake_traffic_secret with
+     * Derive-Secret( ., "c hs traffic", ClientHello...ServerHello )
+     */
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+             handshake_secret, md_size,
+             MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_hs_traffic ),
+             transcript, transcript_len,
+             MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+             derived->client_handshake_traffic_secret,
+             md_size );
+    if( ret != 0 )
+        return( ret );
+
+    /*
+     * Compute server_handshake_traffic_secret with
+     * Derive-Secret( ., "s hs traffic", ClientHello...ServerHello )
+     */
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+             handshake_secret, md_size,
+             MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_hs_traffic ),
+             transcript, transcript_len,
+             MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+             derived->server_handshake_traffic_secret,
+             md_size );
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+int mbedtls_ssl_tls1_3_derive_application_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *application_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_application_secrets *derived )
+{
+    int ret;
+    mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type );
+    size_t const md_size = mbedtls_md_get_size( md_info );
+
+    /* We should never call this function with an unknown hash,
+     * but add an assertion anyway. */
+    if( md_info == 0 )
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+
+    /* Generate {client,server}_application_traffic_secret_0
+     *
+     * Master Secret
+     * |
+     * +-----> Derive-Secret( ., "c ap traffic",
+     * |                      ClientHello...server Finished )
+     * |                      = client_application_traffic_secret_0
+     * |
+     * +-----> Derive-Secret( ., "s ap traffic",
+     * |                      ClientHello...Server Finished )
+     * |                      = server_application_traffic_secret_0
+     * |
+     * +-----> Derive-Secret( ., "exp master",
+     * |                      ClientHello...server Finished)
+     * |                      = exporter_master_secret
+     *
+     */
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+              application_secret, md_size,
+              MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_ap_traffic ),
+              transcript, transcript_len,
+              MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+              derived->client_application_traffic_secret_N,
+              md_size );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+              application_secret, md_size,
+              MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_ap_traffic ),
+              transcript, transcript_len,
+              MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+              derived->server_application_traffic_secret_N,
+              md_size );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+              application_secret, md_size,
+              MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( exp_master ),
+              transcript, transcript_len,
+              MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+              derived->exporter_master_secret,
+              md_size );
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+/* Generate resumption_master_secret for use with the ticket exchange.
+ *
+ * This is not integrated with mbedtls_ssl_tls1_3_derive_application_secrets()
+ * because it uses the transcript hash up to and including ClientFinished. */
+int mbedtls_ssl_tls1_3_derive_resumption_master_secret(
+          mbedtls_md_type_t md_type,
+          unsigned char const *application_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_application_secrets *derived )
+{
+    int ret;
+    mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type );
+    size_t const md_size = mbedtls_md_get_size( md_info );
+
+    /* We should never call this function with an unknown hash,
+     * but add an assertion anyway. */
+    if( md_info == 0 )
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+
+    ret = mbedtls_ssl_tls1_3_derive_secret( md_type,
+              application_secret, md_size,
+              MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( res_master ),
+              transcript, transcript_len,
+              MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED,
+              derived->resumption_master_secret,
+              md_size );
+
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index 7089049..cb45cc9 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -70,6 +70,27 @@
 #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN  \
     MBEDTLS_MD_MAX_SIZE
 
+typedef struct
+{
+    unsigned char binder_key                  [ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char client_early_traffic_secret [ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char early_exporter_master_secret[ MBEDTLS_MD_MAX_SIZE ];
+} mbedtls_ssl_tls1_3_early_secrets;
+
+typedef struct
+{
+    unsigned char client_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char server_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ];
+} mbedtls_ssl_tls1_3_handshake_secrets;
+
+typedef struct
+{
+    unsigned char client_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char server_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char exporter_master_secret             [ MBEDTLS_MD_MAX_SIZE ];
+    unsigned char resumption_master_secret           [ MBEDTLS_MD_MAX_SIZE ];
+} mbedtls_ssl_tls1_3_application_secrets;
+
 /* Maximum desired length for expanded key material generated
  * by HKDF-Expand-Label.
  *
@@ -199,6 +220,179 @@
                    unsigned char *dstbuf, size_t buflen );
 
 /**
+ * \brief Derive TLS 1.3 early data key material from early secret.
+ *
+ *        This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret()
+ *        with the appropriate labels.
+ *
+ * <tt>
+ *        Early Secret
+ *             |
+ *             +-----> Derive-Secret(., "c e traffic", ClientHello)
+ *             |                      = client_early_traffic_secret
+ *             |
+ *             +-----> Derive-Secret(., "e exp master", ClientHello)
+ *             .                      = early_exporter_master_secret
+ *             .
+ *             .
+ * </tt>
+ *
+ * \note  To obtain the actual key and IV for the early data traffic,
+ *        the client secret derived by this function need to be
+ *        further processed by mbedtls_ssl_tls1_3_make_traffic_keys().
+ *
+ * \note  The binder key, which is also generated from the early secret,
+ *        is omitted here. Its calculation is part of the separate routine
+ *        mbedtls_ssl_tls1_3_create_psk_binder().
+ *
+ * \param md_type      The hash algorithm associated with the PSK for which
+ *                     early data key material is being derived.
+ * \param early_secret The early secret from which the early data key material
+ *                     should be derived. This must be a readable buffer whose
+ *                     length is the digest size of the hash algorithm
+ *                     represented by \p md_size.
+ * \param transcript   The transcript of the handshake so far, calculated with
+ *                     respect to \p md_type. This must be a readable buffer
+ *                     whose length is the digest size of the hash algorithm
+ *                     represented by \p md_size.
+ * \param derived      The address of the structure in which to store
+ *                     the early data key material.
+ *
+ * \returns        \c 0 on success.
+ * \returns        A negative error code on failure.
+ */
+int mbedtls_ssl_tls1_3_derive_early_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *early_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_early_secrets *derived );
+
+/**
+ * \brief Derive TLS 1.3 handshake key material from the handshake secret.
+ *
+ *        This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret()
+ *        with the appropriate labels from the standard.
+ *
+ * <tt>
+ *        Handshake Secret
+ *              |
+ *              +-----> Derive-Secret( ., "c hs traffic",
+ *              |                      ClientHello...ServerHello )
+ *              |                      = client_handshake_traffic_secret
+ *              |
+ *              +-----> Derive-Secret( ., "s hs traffic",
+ *              .                      ClientHello...ServerHello )
+ *              .                      = server_handshake_traffic_secret
+ *              .
+ * </tt>
+ *
+ * \note  To obtain the actual key and IV for the encrypted handshake traffic,
+ *        the client and server secret derived by this function need to be
+ *        further processed by mbedtls_ssl_tls1_3_make_traffic_keys().
+ *
+ * \param md_type           The hash algorithm associated with the ciphersuite
+ *                          that's being used for the connection.
+ * \param handshake_secret  The handshake secret from which the handshake key
+ *                          material should be derived. This must be a readable
+ *                          buffer whose length is the digest size of the hash
+ *                          algorithm represented by \p md_size.
+ * \param transcript        The transcript of the handshake so far, calculated
+ *                          with respect to \p md_type. This must be a readable
+ *                          buffer whose length is the digest size of the hash
+ *                          algorithm represented by \p md_size.
+ * \param derived           The address of the structure in which to
+ *                          store the handshake key material.
+ *
+ * \returns        \c 0 on success.
+ * \returns        A negative error code on failure.
+ */
+int mbedtls_ssl_tls1_3_derive_handshake_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *handshake_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_handshake_secrets *derived );
+
+/**
+ * \brief Derive TLS 1.3 application key material from the master secret.
+ *
+ *        This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret()
+ *        with the appropriate labels from the standard.
+ *
+ * <tt>
+ *        Master Secret
+ *              |
+ *              +-----> Derive-Secret( ., "c ap traffic",
+ *              |                      ClientHello...server Finished )
+ *              |                      = client_application_traffic_secret_0
+ *              |
+ *              +-----> Derive-Secret( ., "s ap traffic",
+ *              |                      ClientHello...Server Finished )
+ *              |                      = server_application_traffic_secret_0
+ *              |
+ *              +-----> Derive-Secret( ., "exp master",
+ *              .                      ClientHello...server Finished)
+ *              .                      = exporter_master_secret
+ *              .
+ * </tt>
+ *
+ * \note  To obtain the actual key and IV for the (0-th) application traffic,
+ *        the client and server secret derived by this function need to be
+ *        further processed by mbedtls_ssl_tls1_3_make_traffic_keys().
+ *
+ * \param md_type           The hash algorithm associated with the ciphersuite
+ *                          that's being used for the connection.
+ * \param master_secret     The master secret from which the application key
+ *                          material should be derived. This must be a readable
+ *                          buffer whose length is the digest size of the hash
+ *                          algorithm represented by \p md_size.
+ * \param transcript        The transcript of the handshake up to and including
+ *                          the ServerFinished message, calculated with respect
+ *                          to \p md_type. This must be a readable buffer whose
+ *                          length is the digest size of the hash algorithm
+ *                          represented by \p md_type.
+ * \param derived           The address of the structure in which to
+ *                          store the application key material.
+ *
+ * \returns        \c 0 on success.
+ * \returns        A negative error code on failure.
+ */
+int mbedtls_ssl_tls1_3_derive_application_secrets(
+          mbedtls_md_type_t md_type,
+          unsigned char const *master_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_application_secrets *derived );
+
+/**
+ * \brief Derive TLS 1.3 resumption master secret from the master secret.
+ *
+ *        This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret()
+ *        with the appropriate labels from the standard.
+ *
+ * \param md_type           The hash algorithm used in the application for which
+ *                          key material is being derived.
+ * \param application_secret The application secret from which the resumption master
+ *                          secret should be derived. This must be a readable
+ *                          buffer whose length is the digest size of the hash
+ *                          algorithm represented by \p md_size.
+ * \param transcript        The transcript of the handshake up to and including
+ *                          the ClientFinished message, calculated with respect
+ *                          to \p md_type. This must be a readable buffer whose
+ *                          length is the digest size of the hash algorithm
+ *                          represented by \p md_type.
+ * \param transcript_len    The length of \p transcript in Bytes.
+ * \param derived           The address of the structure in which to
+ *                          store the resumption master secret.
+ *
+ * \returns        \c 0 on success.
+ * \returns        A negative error code on failure.
+ */
+int mbedtls_ssl_tls1_3_derive_resumption_master_secret(
+          mbedtls_md_type_t md_type,
+          unsigned char const *application_secret,
+          unsigned char const *transcript, size_t transcript_len,
+          mbedtls_ssl_tls1_3_application_secrets *derived );
+
+/**
  * \brief Compute the next secret in the TLS 1.3 key schedule
  *
  * The TLS 1.3 key schedule proceeds as follows to compute