Merge pull request #163 from ARMmbed/tls_psk_to_ms_derivation

PSA: Phase 2: Add support for TLS-1.2 PSK-to-MasterSecret derivation
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 15c8130..d1a3f0f 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -1202,6 +1202,16 @@
 #define PSA_ALG_TLS12_PRF_BASE                     ((psa_algorithm_t)0x30000200)
 /** Macro to build a TLS-1.2 PRF algorithm.
  *
+ * TLS 1.2 uses a custom pseudorandom function (PRF) for key schedule,
+ * specified in Section 5 of RFC 5246. It is based on HMAC and can be
+ * used with either SHA-256 or SHA-384.
+ *
+ * For the application to TLS-1.2, the salt and label arguments passed
+ * to psa_key_derivation() are what's called 'seed' and 'label' in RFC 5246,
+ * respectively. For example, for TLS key expansion, the salt is the
+ * concatenation of ServerHello.Random + ClientHello.Random,
+ * while the label is "key expansion".
+ *
  * For example, `PSA_ALG_TLS12_PRF(PSA_ALG_SHA256)` represents the
  * TLS 1.2 PRF using HMAC-SHA-256.
  *
@@ -1217,10 +1227,6 @@
 
 /** Whether the specified algorithm is a TLS-1.2 PRF algorithm.
  *
- * TLS 1.2 uses a custom pseudorandom function (PRF) for key schedule,
- * specified in Section 5 of RFC 5246. It is based on HMAC and can be
- * used with either SHA-256 or SHA-384.
- *
  * \param alg An algorithm identifier (value of type #psa_algorithm_t).
  *
  * \return 1 if \c alg is a TLS-1.2 PRF algorithm, 0 otherwise.
@@ -1232,6 +1238,46 @@
 #define PSA_ALG_TLS12_PRF_GET_HASH(hkdf_alg)                         \
     (PSA_ALG_CATEGORY_HASH | ((hkdf_alg) & PSA_ALG_HASH_MASK))
 
+#define PSA_ALG_TLS12_PSK_TO_MS_BASE ((psa_algorithm_t)0x30000300)
+/** Macro to build a TLS-1.2 PSK-to-MasterSecret algorithm.
+ *
+ * In a pure-PSK handshake in TLS 1.2, the master secret is derived
+ * from the PreSharedKey (PSK) through the application of padding
+ * (RFC 4279, Section 2) and the TLS-1.2 PRF (RFC 5246, Section 5).
+ * The latter is based on HMAC and can be used with either SHA-256
+ * or SHA-384.
+ *
+ * For the application to TLS-1.2, the salt passed to psa_key_derivation()
+ * (and forwarded to the TLS-1.2 PRF) is the concatenation of the
+ * ClientHello.Random + ServerHello.Random, while the label is "master secret"
+ * or "extended master secret".
+ *
+ * For example, `PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA256)` represents the
+ * TLS-1.2 PSK to MasterSecret derivation PRF using HMAC-SHA-256.
+ *
+ * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
+ *                      #PSA_ALG_IS_HASH(\p hash_alg) is true).
+ *
+ * \return              The corresponding TLS-1.2 PSK to MS algorithm.
+ * \return              Unspecified if \p alg is not a supported
+ *                      hash algorithm.
+ */
+#define PSA_ALG_TLS12_PSK_TO_MS(hash_alg)                                  \
+    (PSA_ALG_TLS12_PSK_TO_MS_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
+
+/** Whether the specified algorithm is a TLS-1.2 PSK to MS algorithm.
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \c alg is a TLS-1.2 PSK to MS algorithm, 0 otherwise.
+ *         This macro may return either 0 or 1 if \c alg is not a supported
+ *         key derivation algorithm identifier.
+ */
+#define PSA_ALG_IS_TLS12_PSK_TO_MS(alg)                                    \
+    (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_TLS12_PSK_TO_MS_BASE)
+#define PSA_ALG_TLS12_PSK_TO_MS_GET_HASH(hkdf_alg)                         \
+    (PSA_ALG_CATEGORY_HASH | ((hkdf_alg) & PSA_ALG_HASH_MASK))
+
 #define PSA_ALG_KEY_DERIVATION_MASK             ((psa_algorithm_t)0x010fffff)
 
 /** Use a shared secret as is.
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index f0a1ba7..7e17956 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -131,6 +131,22 @@
 #define PSA_VENDOR_ECC_MAX_CURVE_BITS 0
 #endif
 
+/** \def PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN
+ *
+ * This macro returns the maximum length of the PSK supported
+ * by the TLS-1.2 PSK-to-MS key derivation.
+ *
+ * Quoting RFC 4279, Sect 5.3:
+ * TLS implementations supporting these ciphersuites MUST support
+ * arbitrary PSK identities up to 128 octets in length, and arbitrary
+ * PSKs up to 64 octets in length.  Supporting longer identities and
+ * keys is RECOMMENDED.
+ *
+ * Therefore, no implementation should define a value smaller than 64
+ * for #PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN.
+ */
+#define PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN 128
+
 /** \def PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE
  *
  * Maximum size of an asymmetric signature.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index b0fb5a8..010c338 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -3275,7 +3275,9 @@
         mbedtls_free( generator->ctx.hkdf.info );
         status = psa_hmac_abort_internal( &generator->ctx.hkdf.hmac );
     }
-    else if( PSA_ALG_IS_TLS12_PRF( generator->alg ) )
+    else if( PSA_ALG_IS_TLS12_PRF( generator->alg ) ||
+             /* TLS-1.2 PSK-to-MS KDF uses the same generator as TLS-1.2 PRF */
+             PSA_ALG_IS_TLS12_PSK_TO_MS( generator->alg ) )
     {
         if( generator->ctx.tls12_prf.key != NULL )
         {
@@ -3578,7 +3580,8 @@
         status = psa_generator_hkdf_read( &generator->ctx.hkdf, hash_alg,
                                           output, output_length );
     }
-    else if( PSA_ALG_IS_TLS12_PRF( generator->alg ) )
+    else if( PSA_ALG_IS_TLS12_PRF( generator->alg ) ||
+             PSA_ALG_IS_TLS12_PSK_TO_MS( generator->alg ) )
     {
         status = psa_generator_tls12_prf_read( &generator->ctx.tls12_prf,
                                                generator->alg, output,
@@ -3749,6 +3752,47 @@
 
     return( PSA_SUCCESS );
 }
+
+/* Set up a TLS-1.2-PSK-to-MS-based generator. */
+static psa_status_t psa_generator_tls12_psk_to_ms_setup(
+    psa_tls12_prf_generator_t *tls12_prf,
+    const unsigned char *psk,
+    size_t psk_len,
+    psa_algorithm_t hash_alg,
+    const uint8_t *salt,
+    size_t salt_length,
+    const uint8_t *label,
+    size_t label_length )
+{
+    psa_status_t status;
+    unsigned char pms[ 4 + 2 * PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN ];
+
+    if( psk_len > PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Quoting RFC 4279, Section 2:
+     *
+     * The premaster secret is formed as follows: if the PSK is N octets
+     * long, concatenate a uint16 with the value N, N zero octets, a second
+     * uint16 with the value N, and the PSK itself.
+     */
+
+    pms[0] = ( psk_len >> 8 ) & 0xff;
+    pms[1] = ( psk_len >> 0 ) & 0xff;
+    memset( pms + 2, 0, psk_len );
+    pms[2 + psk_len + 0] = pms[0];
+    pms[2 + psk_len + 1] = pms[1];
+    memcpy( pms + 4 + psk_len, psk, psk_len );
+
+    status = psa_generator_tls12_prf_setup( tls12_prf,
+                                            pms, 4 + 2 * psk_len,
+                                            hash_alg,
+                                            salt, salt_length,
+                                            label, label_length );
+
+    mbedtls_zeroize( pms, sizeof( pms ) );
+    return( status );
+}
 #endif /* MBEDTLS_MD_C */
 
 /* Note that if this function fails, you must call psa_generator_abort()
@@ -3799,7 +3843,9 @@
                                            salt, salt_length,
                                            label, label_length );
     }
-    else if( PSA_ALG_IS_TLS12_PRF( alg ) )
+    /* TLS-1.2 PRF and TLS-1.2 PSK-to-MS are very similar, so share code. */
+    else if( PSA_ALG_IS_TLS12_PRF( alg ) ||
+             PSA_ALG_IS_TLS12_PSK_TO_MS( alg ) )
     {
         psa_algorithm_t hash_alg = PSA_ALG_TLS12_PRF_GET_HASH( alg );
         size_t hash_size = PSA_HASH_SIZE( hash_alg );
@@ -3812,10 +3858,22 @@
         }
 
         max_capacity = 255 * hash_size;
-        status = psa_generator_tls12_prf_setup( &generator->ctx.tls12_prf,
-                                                secret, secret_length,
-                                                hash_alg, salt, salt_length,
-                                                label, label_length );
+
+        if( PSA_ALG_IS_TLS12_PRF( alg ) )
+        {
+            status = psa_generator_tls12_prf_setup( &generator->ctx.tls12_prf,
+                                                    secret, secret_length,
+                                                    hash_alg, salt, salt_length,
+                                                    label, label_length );
+        }
+        else
+        {
+            status = psa_generator_tls12_psk_to_ms_setup(
+                &generator->ctx.tls12_prf,
+                secret, secret_length,
+                hash_alg, salt, salt_length,
+                label, label_length );
+        }
     }
     else
 #endif
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index da105d2..ea214d2 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -1537,6 +1537,33 @@
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
 derive_output:PSA_ALG_TLS12_PRF(PSA_ALG_SHA_384):"b80b733d6ceefcdc71566ea48e5567df":"cd665cf6a8447dd6ff8b27555edb7465":"74657374206c6162656c":148:"7b0c18e9ced410ed1804f2cfa34a336a1c14dffb4900bb5fd7942107e81c83cde9ca0faa60be9fe34f82b1233c9146a0e534cb400fed2700884f9dc236f80edd8bfa961144c9e8d792ec":"a722a7b32fc3d416d473ebc2c5fd4abfdad05d9184259b5bf8cd4d90fa0d31e2dec479e4f1a26066f2eea9a69236a3e52655c9e9aee691c8f3a26854308d5eaa3be85e0990703d73e5"
 
+# Test case manually extracted from debug output of TLS-PSK run
+# Label: "master secret"
+# Salt: Concatenation of ClientHello.Random and ServerHello.Random
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-256, 48+0
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"01020304":"5bc0b19b4a8b24b07afe7ec65c471e94a7d518fcef06c3574315255c52afe21b5bc0b19b872b9b26508458f03603744d575f463a11ae7f1b090c012606fd3e9f":"6d617374657220736563726574":48:"5a9dd5ffa78b4d1f28f40d91b4e6e6ed37849042d61ba32ca43d866e744cee7cd1baaa497e1ecd5c2e60f9f13030a710":""
+
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-256, 24+24
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"01020304":"5bc0b19b4a8b24b07afe7ec65c471e94a7d518fcef06c3574315255c52afe21b5bc0b19b872b9b26508458f03603744d575f463a11ae7f1b090c012606fd3e9f":"6d617374657220736563726574":48:"5a9dd5ffa78b4d1f28f40d91b4e6e6ed37849042d61ba32c":"a43d866e744cee7cd1baaa497e1ecd5c2e60f9f13030a710"
+
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-256, 0+48
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"01020304":"5bc0b19b4a8b24b07afe7ec65c471e94a7d518fcef06c3574315255c52afe21b5bc0b19b872b9b26508458f03603744d575f463a11ae7f1b090c012606fd3e9f":"6d617374657220736563726574":48:"":"5a9dd5ffa78b4d1f28f40d91b4e6e6ed37849042d61ba32ca43d866e744cee7cd1baaa497e1ecd5c2e60f9f13030a710"
+
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-384, 48+0
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384):"01020304":"5bed47716a11a49a6268a8350b085929116ad9ccc8181f09a05b07a7741576d65bed47718dfd82f2d3f57544afe52decae6819b970dc716ada72ae0dd3072e9a":"6d617374657220736563726574":48:"f5a61fbdd2ec415762abb8042a6c16645a53d2edb6dec8c85ca71689301f9f4d875128c87608b75250b20a9550e4fe18":""
+
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-384, 24+24
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384):"01020304":"5bed47716a11a49a6268a8350b085929116ad9ccc8181f09a05b07a7741576d65bed47718dfd82f2d3f57544afe52decae6819b970dc716ada72ae0dd3072e9a":"6d617374657220736563726574":48:"":"f5a61fbdd2ec415762abb8042a6c16645a53d2edb6dec8c85ca71689301f9f4d875128c87608b75250b20a9550e4fe18"
+
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-384, 0+48
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+derive_output:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384):"01020304":"5bed47716a11a49a6268a8350b085929116ad9ccc8181f09a05b07a7741576d65bed47718dfd82f2d3f57544afe52decae6819b970dc716ada72ae0dd3072e9a":"6d617374657220736563726574":48:"f5a61fbdd2ec415762abb8042a6c16645a53d2edb6dec8c8":"5ca71689301f9f4d875128c87608b75250b20a9550e4fe18"
+
 PSA key derivation: HKDF SHA-256, request maximum capacity
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
 derive_output:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":255 * 32:"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865":""
@@ -1553,6 +1580,10 @@
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA1_C
 derive_setup:PSA_KEY_TYPE_DERIVE:"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c":PSA_ALG_HKDF(PSA_ALG_SHA_1):"":"":255 * 20 + 1:PSA_ERROR_INVALID_ARGUMENT
 
+PSA key derivation: TLS 1.2 PSK-to-MS, SHA-256, PSK too long (160 Bytes)
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+derive_setup:PSA_KEY_TYPE_DERIVE:"01020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708010203040506070801020304050607080102030405060708":PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"":"":100:PSA_ERROR_INVALID_ARGUMENT
+
 PSA key derivation: over capacity 42: output 42+1
 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
 derive_output:PSA_ALG_HKDF(PSA_ALG_SHA_256):"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":"000102030405060708090a0b0c":"f0f1f2f3f4f5f6f7f8f9":42:"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865":"ff"