Add an EC J-PAKE KDF to transform K -> SHA256(K.X) for TLS 1.2

TLS uses it to derive the session secret. The algorithm takes a serialized
point in an uncompressed form, extracts the X coordinate and computes
SHA256 of it. It is only expected to work with P-256.
Fixes #5978.
Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index b0116dd..5c05f79 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -4243,7 +4243,8 @@
 
 #if defined(BUILTIN_ALG_ANY_HKDF) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
-    defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
+    defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
 #define AT_LEAST_ONE_BUILTIN_KDF
 #endif /* At least one builtin KDF */
 
@@ -4350,6 +4351,14 @@
     else
 #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) ||
         * defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) */
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+    if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
+    {
+        mbedtls_platform_zeroize( operation->ctx.tls12_ecjpake_to_pms.data,
+            PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE );
+    }
+    else
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) */
     {
         status = PSA_ERROR_BAD_STATE;
     }
@@ -4631,6 +4640,31 @@
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
         * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
 
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+static psa_status_t psa_key_derivation_tls12_ecjpake_to_pms_read(
+    psa_tls12_ecjpake_to_pms_t *ecjpake,
+    uint8_t *output,
+    size_t output_length )
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    size_t output_size;
+
+    if( output_length != 32 )
+        return ( PSA_ERROR_INVALID_ARGUMENT );
+
+    status = psa_hash_compute( PSA_ALG_SHA_256, ecjpake->data,
+        PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE, output, output_length,
+        &output_size );
+    if( status != PSA_SUCCESS )
+        return ( status );
+
+    if( output_size != output_length )
+        return ( PSA_ERROR_GENERIC_ERROR );
+
+    return ( PSA_SUCCESS );
+}
+#endif
+
 psa_status_t psa_key_derivation_output_bytes(
     psa_key_derivation_operation_t *operation,
     uint8_t *output,
@@ -4685,6 +4719,15 @@
     else
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
         * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+    if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
+    {
+        status = psa_key_derivation_tls12_ecjpake_to_pms_read(
+            &operation->ctx.tls12_ecjpake_to_pms, output, output_length );
+    }
+    else
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
+
     {
         (void) kdf_alg;
         return( PSA_ERROR_BAD_STATE );
@@ -5077,6 +5120,10 @@
     if( PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) )
         return( 1 );
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+    if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
+        return( 1 );
+#endif
     return( 0 );
 }
 
@@ -5100,19 +5147,26 @@
     if( ! is_kdf_alg_supported( kdf_alg ) )
         return( PSA_ERROR_NOT_SUPPORTED );
 
-    /* All currently supported key derivation algorithms are based on a
-     * hash algorithm. */
+    /* All currently supported key derivation algorithms (apart from
+     * ecjpake to pms are based on a hash algorithm. */
     psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
     size_t hash_size = PSA_HASH_LENGTH( hash_alg );
-    if( hash_size == 0 )
-        return( PSA_ERROR_NOT_SUPPORTED );
+    if( !PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
+    {
+        if( hash_size == 0 )
+            return( PSA_ERROR_NOT_SUPPORTED );
 
-    /* Make sure that hash_alg is a supported hash algorithm. Otherwise
-     * we might fail later, which is somewhat unfriendly and potentially
-     * risk-prone. */
-    psa_status_t status = psa_hash_try_support( hash_alg );
-    if( status != PSA_SUCCESS )
-        return( status );
+        /* Make sure that hash_alg is a supported hash algorithm. Otherwise
+         * we might fail later, which is somewhat unfriendly and potentially
+         * risk-prone. */
+        psa_status_t status = psa_hash_try_support( hash_alg );
+        if( status != PSA_SUCCESS )
+            return( status );
+    }
+    else
+    {
+        hash_size = PSA_HASH_LENGTH( PSA_ALG_SHA_256 );
+    }
 
     if( ( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
           PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) &&
@@ -5513,6 +5567,25 @@
 }
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
 
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+static psa_status_t psa_tls12_ecjpake_to_pms_input(
+    psa_tls12_ecjpake_to_pms_t *ecjpake,
+    const uint8_t *data,
+    size_t data_length )
+{
+    if( data_length != PSA_TLS12_ECJPAKE_TO_PMS_INPUT_SIZE )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Check if the passed point is in an uncompressed form */
+    if( data[0] != 0x04 )
+        return( PSA_ERROR_INVALID_ARGUMENT );
+
+    /* Only K.X has to be extracted - bytes 1 to 32 inclusive. */
+    memcpy( ecjpake->data, data + 1, PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE );
+
+    return( PSA_SUCCESS );
+}
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
 /** Check whether the given key type is acceptable for the given
  * input step of a key derivation.
  *
@@ -5591,6 +5664,14 @@
     }
     else
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
+    if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
+    {
+        status = psa_tls12_ecjpake_to_pms_input(
+            &operation->ctx.tls12_ecjpake_to_pms, data, data_length );
+    }
+    else
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
     {
         /* This can't happen unless the operation object was not initialized */
         (void) data;