Merge changes from topic "mb/psa-crypto-ecdsa" into integration

* changes:
  docs: mark PSA_CRYPTO as an experimental feature
  feat(fvp): increase BL1 RW area for PSA_CRYPTO implementation
  feat(mbedtls-psa): mbedTLS PSA Crypto with ECDSA
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 654ddc5..347cf20 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -1195,7 +1195,8 @@
   The platform will use PSA compliant Crypto APIs during authentication and
   image measurement process by enabling this option. It uses APIs defined as
   per the `PSA Crypto API specification`_. This feature is only supported if
-  using MbedTLS 3.x version. By default it is disabled (``0``).
+  using MbedTLS 3.x version. By default it is disabled (``0``), and this is an
+  experimental feature.
 
 - ``ENABLE_CONSOLE_GETC``: Boolean option to enable `getc()` feature in console
   driver(s). By default it is disabled (``0``) because it constitutes an attack
diff --git a/drivers/auth/mbedtls/mbedtls_psa_crypto.c b/drivers/auth/mbedtls/mbedtls_psa_crypto.c
index 2fa8e63..5891acf 100644
--- a/drivers/auth/mbedtls/mbedtls_psa_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_psa_crypto.c
@@ -28,6 +28,13 @@
 
 #define LIB_NAME		"mbed TLS PSA"
 
+/* Maximum length of R_S pair in the ECDSA signature in bytes */
+#define MAX_ECDSA_R_S_PAIR_LEN	64U
+
+/* Size of ASN.1 length and tag in bytes*/
+#define SIZE_OF_ASN1_LEN	1U
+#define SIZE_OF_ASN1_TAG	1U
+
 #if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
 CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
 /*
@@ -108,6 +115,7 @@
 
 static void construct_psa_key_alg_and_type(mbedtls_pk_type_t pk_alg,
 					   mbedtls_md_type_t md_alg,
+					   psa_ecc_family_t psa_ecc_family,
 					   psa_algorithm_t *psa_alg,
 					   psa_key_type_t *psa_key_type)
 {
@@ -118,14 +126,173 @@
 		*psa_alg = PSA_ALG_RSA_PSS(psa_md_alg);
 		*psa_key_type = PSA_KEY_TYPE_RSA_PUBLIC_KEY;
 		break;
+	case MBEDTLS_PK_ECDSA:
+		*psa_alg = PSA_ALG_ECDSA(psa_md_alg);
+		*psa_key_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(psa_ecc_family);
+		break;
 	default:
 		*psa_alg = PSA_ALG_NONE;
 		*psa_key_type = PSA_KEY_TYPE_NONE;
 		break;
 	}
+}
+
+
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+
+/*
+ * This is a helper function to detect padding byte (if the MSB bit of the
+ * first data byte is set to 1, for example 0x80) and on detection, ignore the
+ * padded byte(0x00) and increase the buffer pointer beyond padded byte and
+ * decrease the length of the buffer by 1.
+ *
+ * On Success returns 0, error otherwise.
+ **/
+static inline int ignore_asn1_int_padding_byte(unsigned char **buf_start,
+					       size_t *buf_len)
+{
+	unsigned char *local_buf = *buf_start;
+
+	/* Check for negative number */
+	if ((local_buf[0] & 0x80U) != 0U) {
+		return -1;
+	}
+
+	if ((local_buf[0] == 0U) && (local_buf[1] > 0x7FU) &&
+	    (*buf_len > 1U)) {
+		*buf_start = &local_buf[1];
+		(*buf_len)--;
+	}
+
+	return 0;
+}
+
+/*
+ * This is a helper function that gets a pointer to the encoded ECDSA publicKey
+ * and its length (as per RFC5280) and returns corresponding decoded publicKey
+ * and its length. As well, it retrieves the family of ECC key in the PSA
+ * format.
+ *
+ * This function returns error(CRYPTO_ERR_SIGNATURE) on ASN.1 parsing failure,
+ * otherwise success(0).
+ **/
+static int get_ecdsa_pkinfo_from_asn1(unsigned char **pk_start,
+				      unsigned int *pk_len,
+				      psa_ecc_family_t *psa_ecc_family)
+{
+	mbedtls_asn1_buf alg_oid, alg_params;
+	mbedtls_ecp_group_id grp_id;
+	int rc;
+	unsigned char *pk_end;
+	size_t len;
+	size_t curve_bits;
+	unsigned char *pk_ptr = *pk_start;
+
+	pk_end = pk_ptr + *pk_len;
+	rc = mbedtls_asn1_get_tag(&pk_ptr, pk_end, &len,
+				  MBEDTLS_ASN1_CONSTRUCTED |
+				  MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	pk_end = pk_ptr + len;
+	rc = mbedtls_asn1_get_alg(&pk_ptr, pk_end, &alg_oid, &alg_params);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	if (alg_params.tag == MBEDTLS_ASN1_OID) {
+		if (mbedtls_oid_get_ec_grp(&alg_params, &grp_id) != 0) {
+			return CRYPTO_ERR_SIGNATURE;
+		}
+		*psa_ecc_family = mbedtls_ecc_group_to_psa(grp_id,
+							   &curve_bits);
+	} else {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	pk_end = pk_ptr + len - (alg_oid.len + alg_params.len +
+		 2 * (SIZE_OF_ASN1_LEN + SIZE_OF_ASN1_TAG));
+	rc = mbedtls_asn1_get_bitstring_null(&pk_ptr, pk_end, &len);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	*pk_start = pk_ptr;
+	*pk_len = len;
+
+	return rc;
 }
 
 /*
+ * Ecdsa-Sig-Value  ::=  SEQUENCE  {
+ *   r     INTEGER,
+ *   s     INTEGER
+ * }
+ *
+ * This helper function that gets a pointer to the encoded ECDSA signature and
+ * its length (as per RFC5280) and returns corresponding decoded signature
+ * (R_S pair) and its size.
+ *
+ * This function returns error(CRYPTO_ERR_SIGNATURE) on ASN.1 parsing failure,
+ * otherwise success(0).
+ **/
+static int get_ecdsa_signature_from_asn1(unsigned char *sig_ptr,
+					 size_t *sig_len,
+					 unsigned char *r_s_pair)
+{
+	int rc;
+	unsigned char *sig_end;
+	size_t len, r_len, s_len;
+
+	sig_end = sig_ptr + *sig_len;
+	rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &len,
+				  MBEDTLS_ASN1_CONSTRUCTED |
+				  MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	sig_end = sig_ptr + len;
+	rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &r_len,
+				  MBEDTLS_ASN1_INTEGER);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	if (ignore_asn1_int_padding_byte(&sig_ptr, &r_len) != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	(void)memcpy((void *)&r_s_pair[0], (const void *)sig_ptr, r_len);
+
+	sig_ptr = sig_ptr + r_len;
+	sig_end = sig_ptr + len - (r_len + (SIZE_OF_ASN1_LEN +
+		  SIZE_OF_ASN1_TAG));
+	rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &s_len,
+				  MBEDTLS_ASN1_INTEGER);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	if (ignore_asn1_int_padding_byte(&sig_ptr, &s_len) != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	(void)memcpy((void *)&r_s_pair[r_len], (const void *)sig_ptr, s_len);
+
+	*sig_len = s_len + r_len;
+
+	return 0;
+}
+#endif /*
+	* TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+	* TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+	**/
+
+/*
  * Verify a signature.
  *
  * Parameters are passed using the DER encoding format following the ASN.1
@@ -143,6 +310,10 @@
 	int rc;
 	void *sig_opts = NULL;
 	unsigned char *p, *end;
+	unsigned char *local_sig_ptr;
+	size_t local_sig_len;
+	psa_ecc_family_t psa_ecc_family = 0U;
+	__unused unsigned char reformatted_sig[MAX_ECDSA_R_S_PAIR_LEN] = {0};
 
 	/* construct PSA key algo and type */
 	psa_status_t status = PSA_SUCCESS;
@@ -174,10 +345,36 @@
 		rc = CRYPTO_ERR_SIGNATURE;
 		goto end2;
 	}
-	signature.p = p;
+
+	local_sig_ptr = p;
+	local_sig_len = signature.len;
+
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+	if (pk_alg == MBEDTLS_PK_ECDSA) {
+		rc = get_ecdsa_signature_from_asn1(local_sig_ptr,
+						   &local_sig_len,
+						   reformatted_sig);
+		if (rc != 0) {
+			goto end2;
+		}
+
+		local_sig_ptr = reformatted_sig;
+
+		rc = get_ecdsa_pkinfo_from_asn1((unsigned char **)&pk_ptr,
+						&pk_len,
+						&psa_ecc_family);
+		if (rc != 0) {
+			goto end2;
+		}
+	}
+#endif /*
+	* TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+	* TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+	**/
 
 	/* Convert this pk_alg and md_alg to PSA key type and key algorithm */
-	construct_psa_key_alg_and_type(pk_alg, md_alg,
+	construct_psa_key_alg_and_type(pk_alg, md_alg, psa_ecc_family,
 				       &psa_alg, &psa_key_type);
 
 
@@ -208,7 +405,7 @@
 	 */
 	status = psa_verify_message(psa_key_id, psa_alg,
 				    data_ptr, data_len,
-				    signature.p, signature.len);
+				    local_sig_ptr, local_sig_len);
 
 	if (status != PSA_SUCCESS) {
 		rc = CRYPTO_ERR_SIGNATURE;
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 836080a..aad0417 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -193,8 +193,10 @@
 /*
  * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
  * plus a little space for growth.
+ * In case of PSA Crypto API, few algorithms like ECDSA needs bigger BL1 RW
+ * area.
  */
-#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA || PSA_CRYPTO
 #define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xC000)
 #else
 #define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xB000)