Merge branch 'iotssl-2578-psa-sig-verification' into development-psa-proposed
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 3af17d3..6aacba8 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -50,7 +50,9 @@
 #endif
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "psa/crypto.h"
 #include "mbedtls/psa_util.h"
+#include "mbedtls/asn1.h"
 #endif
 
 #if defined(MBEDTLS_PLATFORM_C)
@@ -480,6 +482,154 @@
     return( type == MBEDTLS_PK_ECDSA );
 }
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+/*
+ * An ASN.1 encoded signature is a sequence of two ASN.1 integers. Parse one of
+ * those integers and convert it to the fixed-length encoding expected by PSA.
+ */
+static int extract_ecdsa_sig_int( unsigned char **from, const unsigned char *end,
+                                  unsigned char *to, size_t to_len )
+{
+    int ret;
+    size_t unpadded_len, padding_len;
+
+    if( ( ret = mbedtls_asn1_get_tag( from, end, &unpadded_len,
+                                      MBEDTLS_ASN1_INTEGER ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    while( unpadded_len > 0 && **from == 0x00 )
+    {
+        ( *from )++;
+        unpadded_len--;
+    }
+
+    if( unpadded_len > to_len || unpadded_len == 0 )
+        return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+    padding_len = to_len - unpadded_len;
+    memset( to, 0x00, padding_len );
+    memcpy( to + padding_len, *from, unpadded_len );
+    ( *from ) += unpadded_len;
+
+    return( 0 );
+}
+
+/*
+ * Convert a signature from an ASN.1 sequence of two integers
+ * to a raw {r,s} buffer. Note: the provided sig buffer must be at least
+ * twice as big as int_size.
+ */
+static int extract_ecdsa_sig( unsigned char **p, const unsigned char *end,
+                              unsigned char *sig, size_t int_size )
+{
+    int ret;
+    size_t tmp_size;
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &tmp_size,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+        return( ret );
+
+    /* Extract r */
+    if( ( ret = extract_ecdsa_sig_int( p, end, sig, int_size ) ) != 0 )
+        return( ret );
+    /* Extract s */
+    if( ( ret = extract_ecdsa_sig_int( p, end, sig + int_size, int_size ) ) != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
+                       const unsigned char *hash, size_t hash_len,
+                       const unsigned char *sig, size_t sig_len )
+{
+    int ret;
+    psa_key_slot_t key_slot;
+    psa_key_policy_t policy;
+    psa_key_type_t psa_type;
+    mbedtls_pk_context key;
+    int key_len;
+    /* see ECP_PUB_DER_MAX_BYTES in pkwrite.c */
+    unsigned char buf[30 + 2 * MBEDTLS_ECP_MAX_BYTES];
+    unsigned char *p = (unsigned char*) sig;
+    mbedtls_pk_info_t pk_info = mbedtls_eckey_info;
+    psa_algorithm_t psa_sig_md, psa_md;
+    psa_ecc_curve_t curve = mbedtls_psa_translate_ecc_group(
+                            ( (mbedtls_ecdsa_context *) ctx )->grp.id );
+    const size_t signature_part_size = ( ( (mbedtls_ecdsa_context *) ctx )->grp.nbits + 7 ) / 8;
+
+    if( curve == 0 )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    /* mbedlts_pk_write_pubkey_der() expects a full PK context,
+     * re-construct one to make it happy */
+    key.pk_info = &pk_info;
+    key.pk_ctx = ctx;
+    key_len = mbedtls_pk_write_pubkey_der( &key, buf, sizeof( buf ) );
+    if( key_len <= 0 )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    if( ( ret = mbedtls_psa_get_free_key_slot( &key_slot ) ) != PSA_SUCCESS )
+        return( mbedtls_psa_err_translate_pk( ret ) );
+
+    psa_md = mbedtls_psa_translate_md( md_alg );
+    if( psa_md == 0 )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+    psa_sig_md = PSA_ALG_ECDSA( psa_md );
+    psa_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve );
+
+    psa_key_policy_init( &policy );
+    psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, psa_sig_md );
+    if( ( ret = psa_set_key_policy( key_slot, &policy ) ) != PSA_SUCCESS )
+    {
+        ret = mbedtls_psa_err_translate_pk( ret );
+        goto cleanup;
+    }
+
+    if( psa_import_key( key_slot, psa_type, buf + sizeof( buf ) - key_len, key_len )
+         != PSA_SUCCESS )
+    {
+        ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
+    /* We don't need the exported key anymore and can
+     * reuse its buffer for signature extraction. */
+    if( 2 * signature_part_size > sizeof( buf ) )
+    {
+        ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
+    if( ( ret = extract_ecdsa_sig( &p, sig + sig_len, buf,
+                                   signature_part_size ) ) != 0 )
+    {
+        goto cleanup;
+    }
+
+    if( psa_asymmetric_verify( key_slot, psa_sig_md,
+                               hash, hash_len,
+                               buf, 2 * signature_part_size )
+         != PSA_SUCCESS )
+    {
+         ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
+         goto cleanup;
+    }
+
+    if( p != sig + sig_len )
+    {
+        ret = MBEDTLS_ERR_PK_SIG_LEN_MISMATCH;
+        goto cleanup;
+    }
+    ret = 0;
+
+cleanup:
+    psa_destroy_key( key_slot );
+    return( ret );
+}
+#else /* MBEDTLS_USE_PSA_CRYPTO */
 static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg,
                        const unsigned char *hash, size_t hash_len,
                        const unsigned char *sig, size_t sig_len )
@@ -495,6 +645,7 @@
 
     return( ret );
 }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg,
                    const unsigned char *hash, size_t hash_len,
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index 0497502..a6a0089 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -41,6 +41,38 @@
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP192R1:"046FDD3028FA94A863CD4F78DBFF8B3AA561FC6D9CCBBCA88E0AE6FA437F5415F957542D0717FF8B84562DAE99872EF841":"546869732073686F756C64206265207468652068617368206F662061206D6573736167652E00":"30350218185B2A7FB5CD9C9A8488B119B68B47D6EC833509CE9FA1FF021900FB7D259A744A2348BD45D241A39DC915B81CC2084100FA25":MBEDTLS_ERR_ECP_VERIFY_FAILED
 
+EC(DSA) verify test vector: good, bitlen(r) = 256
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"3046022100faecc085c6c5362b91ff1fd6dd77da80bc071bee9ff1ac0ef9509c017f13267c022100a7d0b908c938d3dd6c6a9cdc5b0a4a4ee455c519c1ff6cda959806b7e7461ba0":0
+
+EC(DSA) verify test vector: good, bitlen(r) = 255
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"30450220639f36215b2ff09bb2beb871e122de74c8d5e29ce8a105aa2b95661f42803e72022100becd8f81b2c186f9d5d2c92378d7b9452ce6de231b0c8d17bac2d8537d2331fd":0
+
+EC(DSA) verify test vector: good, bitlen(r) = 248
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"30450220009109f967f9082abc9c46e5ea07936529b82023a1a49b872c046f430983db2602210085f0b1960d61f8d75109b5b7ff991d3171320d2ab547104f864048455a965090":0
+
+EC(DSA) verify test vector: good, bitlen(r) = 247
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"3044021f461786833b50247b07194da6cedbd3caefbcd19c73b6283ccff5097cd0d73b022100d85d20b0b8c3b596eb1cdb0381e681fa0a8bccde4e89c139020af3b0f88e099c":0
+
+EC(DSA) verify test vector: good, bitlen(s) = 256
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"30450220639f36215b2ff09bb2beb871e122de74c8d5e29ce8a105aa2b95661f42803e72022100becd8f81b2c186f9d5d2c92378d7b9452ce6de231b0c8d17bac2d8537d2331fd":0
+
+EC(DSA) verify test vector: good, bitlen(s) = 255
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"304402206ae26950c606d08fe5e1682efdccfb3a7213ca46bd523ffd20c4213fe1400d3402207612106ada7055926167650b257da7f4c42c190b8aa9e3b680f8751fe90c63a5":0
+
+EC(DSA) verify test vector: good, bitlen(s) = 248
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"3045022100fd4d718ab483827492e10b89745fad100d2dd257102b99aff179ee596a569f1f022000a1b777e32a8b4909763b615b805e59194e6196eb05719287a36eb5f17aa485":0
+
+EC(DSA) verify test vector: good, bitlen(s) = 247
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_ec_test_vec:MBEDTLS_PK_ECKEY:MBEDTLS_ECP_DP_SECP256R1:"0437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edff":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855":"30430220685a6994daa6a14e4411b5267edc2a00beee907f2dddd956b2a5a1df791c15f8021f675db4538c000c734489ac737fddd5a739c5a23cd6c6eceea70c286ca4fac9":0
+
 ECDSA sign-verify
 depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 pk_sign_verify:MBEDTLS_PK_ECDSA:0:0
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 37cf5c5..9168b1d 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -356,7 +356,8 @@
     TEST_ASSERT( mbedtls_ecp_point_read_binary( &eckey->grp, &eckey->Q,
                                         key->x, key->len ) == 0 );
 
-    TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_NONE,
+    // MBEDTLS_MD_SHA1 is a dummy - it is ignored, but has to be other than MBEDTLS_MD_NONE.
+    TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA1,
                             hash->x, hash->len, sig->x, sig->len ) == ret );
 
 exit: