Allow importing Montgomery public keys in PSA Crypto

PSA Crypto was checking the byte length of a to-be-imported public ECP key
against the expected length for Weierstrass keys, forgetting that
Curve25519/Curve448 exists.

Signed-off-by: Steven Cooreman <steven.cooreman@silabs.com>
diff --git a/ChangeLog.d/psa_curve25519_public_key_import.txt b/ChangeLog.d/psa_curve25519_public_key_import.txt
new file mode 100644
index 0000000..2ea11e2
--- /dev/null
+++ b/ChangeLog.d/psa_curve25519_public_key_import.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * PSA key import will now correctly import a Curve25519/Curve448 public key
+     instead of erroring out. Contributed by Steven Cooreman in #3492.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 6e9d259..056e677 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -732,19 +732,34 @@
     mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE;
     psa_status_t status;
     mbedtls_ecp_keypair *ecp = NULL;
-    size_t curve_size = size;
+    size_t curve_size;
 
     if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) )
     {
-        /* A public key is represented as:
-         * - The byte 0x04;
-         * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
-         * - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
-         * So its data length is 2m+1 where n is the key size in bits.
-         */
-        if( ( size & 1 ) == 0 )
-            return( PSA_ERROR_INVALID_ARGUMENT );
-        curve_size = size / 2;
+        if( PSA_KEY_TYPE_ECC_GET_FAMILY( type ) == PSA_ECC_FAMILY_MONTGOMERY )
+        {
+            /* A Montgomery public key is represented as its raw
+             * compressed public point.
+             */
+            curve_size = size;
+        }
+        else
+        {
+            /* A Weierstrass public key is represented as:
+             * - The byte 0x04;
+             * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
+             * - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
+             * So its data length is 2m+1 where n is the key size in bits.
+             */
+            if( ( size & 1 ) == 0 )
+                return( PSA_ERROR_INVALID_ARGUMENT );
+            curve_size = size / 2;
+        }
+    }
+    else
+    {
+        /* Private keys are represented as the raw private value */
+        curve_size = size;
     }
 
     /* Allocate and initialize a key representation. */
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 6a28591..d1855fd 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -252,6 +252,10 @@
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_BP256R1_ENABLED
 import_export:"04768c8cae4abca6306db0ed81b0c4a6215c378066ec6d616c146e13f1c7df809b96ab6911c27d8a02339f0926840e55236d3d1efbe2669d090e4c4c660fada91d":PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_BRAINPOOL_P_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:256:0:PSA_SUCCESS:1
 
+PSA import/export curve25519 public key: good
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+import_export:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:255:0:PSA_SUCCESS:1
+
 PSA import/export AES key: policy forbids export
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
 import_export:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_KEY_TYPE_AES:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CTR:128:0:PSA_ERROR_NOT_PERMITTED:1
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 4576b8b..f4b9a8f 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -961,14 +961,23 @@
 #if defined(MBEDTLS_ECP_C)
         if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ) )
         {
-            /* The representation of an ECC public key is:
-             *      - The byte 0x04;
-             *      - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
-             *      - `y_P` as a `ceiling(m/8)`-byte string, big-endian;
-             *      - where m is the bit size associated with the curve.
-             */
-            TEST_EQUAL( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ), end );
-            TEST_EQUAL( p[0], 4 );
+            if( PSA_KEY_TYPE_ECC_GET_FAMILY( type ) == PSA_ECC_FAMILY_MONTGOMERY )
+            {
+                /* The representation of an ECC Montgomery public key is
+                 * the raw compressed point */
+                 TEST_EQUAL( p + PSA_BITS_TO_BYTES( bits ), end );
+            }
+            else
+            {
+                /* The representation of an ECC Weierstrass public key is:
+                 *      - The byte 0x04;
+                 *      - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
+                 *      - `y_P` as a `ceiling(m/8)`-byte string, big-endian;
+                 *      - where m is the bit size associated with the curve.
+                 */
+                TEST_EQUAL( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ), end );
+                TEST_EQUAL( p[0], 4 );
+            }
         }
         else
 #endif /* MBEDTLS_ECP_C */