Add ECDSA verify

Add tests for external verification when signing is done both internally and externally
diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h
index c0088db..ed88c8a 100644
--- a/include/mbedtls/ecdsa.h
+++ b/include/mbedtls/ecdsa.h
@@ -236,6 +236,27 @@
 #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
 
 /**
+ * \brief           Convert a signature from ASN.1 to a raw concatenation
+ *                  of {r,s}
+ *
+ * \param sig       Signature to be converted
+ * \param ssize     Size of the passed buffer
+ * \param byte_len  Length of a single number of the signature
+ * \param buf       Buffer pointer
+ * \param slen      Size of the written signature
+ *
+ * \note            The size of the buffer \c ssize should be at least
+ *                  2*byte_len bytes long, otherwise this function will
+ *                  return an error.
+ *
+ * \return          0 if successful, or a MBEDTLS_ERR_ECP_BAD_INPUT_DATA or
+ *                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH error code
+ *
+ */
+int mbedtls_ecdsa_signature_to_raw( const unsigned char *sig,
+                            size_t ssize, uint16_t byte_len,
+                            unsigned char *buf, size_t* slen );
+/**
  * \brief           Convert a signature from numbers to ASN.1
  *
  * \param r         First number of the signature
@@ -253,9 +274,9 @@
  *                  or a MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code
  *
  */
-int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
-                             unsigned char *sig, size_t *slen,
-                             size_t ssize );
+int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r,
+                             const mbedtls_mpi *s, unsigned char *sig,
+                             size_t *slen, size_t ssize );
 
 /**
  * \brief           Read and verify an ECDSA signature
diff --git a/library/ecdsa.c b/library/ecdsa.c
index fdd0afb..645fbb5 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -287,9 +287,70 @@
 #endif /* MBEDTLS_ECDSA_VERIFY_ALT */
 
 /*
+ * Convert a signature to a raw concatenation of {r, s}
+ */
+int mbedtls_ecdsa_signature_to_raw( const unsigned char *sig,
+                            size_t ssize, uint16_t byte_len,
+                            unsigned char *buf, size_t* slen )
+{
+    int ret;
+    unsigned char *p = (unsigned char *) sig;
+    const unsigned char *end = sig + ssize;
+    size_t len;
+    mbedtls_mpi r, s;
+
+    if( 2 * byte_len > ssize )
+    {
+        return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+    }
+
+    mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+    {
+        ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
+    if( p + len != end )
+    {
+        ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
+        goto cleanup;
+    }
+
+    if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 ||
+            ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 )
+    {
+        ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+    p = (unsigned char *) buf;
+    if( ( ret = mbedtls_mpi_write_binary(&r, p, byte_len) ) )
+    {
+        ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+    p += byte_len;
+    if( ( ret = mbedtls_mpi_write_binary(&s, p, byte_len) ) )
+    {
+        ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+    *slen = 2*byte_len;
+    cleanup:
+        mbedtls_mpi_free( &r );
+        mbedtls_mpi_free( &s );
+
+        return( ret );
+}
+
+/*
  * Convert a signature (given by context) to ASN.1
  */
-int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
+int mbedtls_ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s,
                              unsigned char *sig, size_t *slen, size_t ssize )
 {
     int ret;
@@ -339,7 +400,7 @@
                          hash, hlen, f_rng, p_rng ) );
 #endif
 
-    MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecdsa_signature_to_asn1( &r, &s, sig, slen, ssize ) );
 
 cleanup:
     mbedtls_mpi_free( &r );
diff --git a/library/pkcs11_client.c b/library/pkcs11_client.c
index 92120c6..70cc0de 100644
--- a/library/pkcs11_client.c
+++ b/library/pkcs11_client.c
@@ -209,7 +209,7 @@
         }
         /* The signature buffer is guaranteed to have enough room for
            the encoded signature by the pk_sign interface. */
-        if( ecdsa_signature_to_asn1( &r, &s, sig, sig_len, sig_size ) != 0 )
+        if( mbedtls_ecdsa_signature_to_asn1( &r, &s, sig, sig_len, sig_size ) != 0 )
         {
             rv = CKR_GENERAL_ERROR;
             goto ecdsa_exit;
@@ -231,12 +231,88 @@
     return( pkcs11_err_to_mbedtls_pk_err( rv ) );
 }
 
+static int pkcs11_verify( void *ctx_arg,
+                        mbedtls_md_type_t md_alg,
+                        const unsigned char *hash, size_t hash_len,
+                        const unsigned char *sig, size_t sig_len)
+{
+    mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
+    CK_RV rv;
+    CK_MECHANISM mechanism = {0, NULL_PTR, 0};
+    unsigned char *decoded_sig = NULL_PTR;
+    size_t decoded_sig_len;
+
+    /* This function takes size_t arguments but the underlying layer
+       takes unsigned long. Either type may be smaller than the other.
+       Legitimate values won't overflow either type but we still need
+       to check for overflow for robustness. */
+    if( hash_len > (CK_ULONG)( -1 ) )
+        return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+
+    switch( ctx->key_type )
+    {
+#if defined(MBEDTLS_RSA_C)
+    case MBEDTLS_PK_RSA:
+        switch( md_alg )
+        {
+        case MBEDTLS_MD_MD5:
+            mechanism.mechanism = CKM_MD5_RSA_PKCS;
+            break;
+        case MBEDTLS_MD_SHA1:
+            mechanism.mechanism = CKM_SHA1_RSA_PKCS;
+            break;
+        case MBEDTLS_MD_SHA256:
+            mechanism.mechanism = CKM_SHA256_RSA_PKCS;
+            break;
+        case MBEDTLS_MD_SHA384:
+            mechanism.mechanism = CKM_SHA384_RSA_PKCS;
+            break;
+        case MBEDTLS_MD_SHA512:
+            mechanism.mechanism = CKM_SHA512_RSA_PKCS;
+            break;
+        default:
+            return( MBEDTLS_ERR_PK_INVALID_ALG );
+        }
+        break;
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_ECDSA_C)
+    case MBEDTLS_PK_ECKEY:
+        mechanism.mechanism = CKM_ECDSA;
+        break;
+#endif /* MBEDTLS_ECDSA_C */
+    default:
+        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
+    }
+    if( mechanism.mechanism == CKM_ECDSA )
+    {
+        uint16_t byte_len = ( ( ctx->bit_length + 7 ) / 8 );
+        decoded_sig = malloc( 2 * byte_len );
+        if( mbedtls_ecdsa_signature_to_raw( sig, sig_len, byte_len,
+                                    decoded_sig, &decoded_sig_len ) != 0 )
+        {
+            rv = CKR_GENERAL_ERROR;
+            goto exit;
+        }
+    }
+    rv = C_VerifyInit( ctx->hSession, &mechanism, ctx->hPublicKey );
+    if( rv != CKR_OK )
+        goto exit;
+    rv = C_Verify( ctx->hSession, (CK_BYTE_PTR) hash, hash_len,
+           decoded_sig, decoded_sig_len );
+    if( rv != CKR_OK )
+        goto exit;
+
+exit:
+    free(decoded_sig);
+    return( pkcs11_err_to_mbedtls_pk_err( rv ) );
+}
+
 static const mbedtls_pk_info_t mbedtls_pk_pkcs11_info =
     MBEDTLS_PK_OPAQUE_INFO_1( "pkcs11"
                               , pkcs11_pk_get_bitlen
                               , pkcs11_pk_can_do //can_do
                               , pkcs11_pk_signature_size
-                              , NULL //pkcs11_verify
+                              , pkcs11_verify
                               , pkcs11_sign
                               , NULL //pkcs11_decrypt
                               , NULL //pkcs11_encrypt
diff --git a/tests/suites/test_suite_pkcs11_client.data b/tests/suites/test_suite_pkcs11_client.data
index fb47f51..33a75c3 100644
--- a/tests/suites/test_suite_pkcs11_client.data
+++ b/tests/suites/test_suite_pkcs11_client.data
@@ -5,3 +5,11 @@
 PKCS#11 ECDSA generate and sign
 depends_on:MBEDTLS_PK_C:MBEDTLS_ECDSA_C
 pk_generate_sign:MBEDTLS_PK_ECDSA
+
+PKCS#11 ECDSA generate, sign and verify with Cryptoki
+depends_on:MBEDTLS_PK_C:MBEDTLS_ECDSA_C
+pk_signX_verifyX:MBEDTLS_PK_ECDSA
+
+PKCS#11 ECDSA import, sign with MbedTLS and verify with Cryptoki
+depends_on:MBEDTLS_PK_C:MBEDTLS_ECDSA_C
+pk_import_signI_verifyX:"data_files/server3.key"
diff --git a/tests/suites/test_suite_pkcs11_client.function b/tests/suites/test_suite_pkcs11_client.function
index 1dfe70d..e14996b 100644
--- a/tests/suites/test_suite_pkcs11_client.function
+++ b/tests/suites/test_suite_pkcs11_client.function
@@ -323,3 +323,194 @@
     mbedtls_pk_free( &transparent_ctx );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PK_C:MBEDTLS_SHA256_C */
+void pk_signX_verifyX( int key_type )
+{
+    /* Sign with cryptoki, convert to mbedTLS format and save, 
+       verify by cryptoki with a conversion to a raw, concatenated
+       format by the engine. */
+    mbedtls_pk_context pkcs11_ctx;
+    mbedtls_pk_context transparent_ctx;
+    CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+    unsigned char hash_value[32] = "Fake hash, it doesn't matter....";
+    unsigned char sig_buffer[RSA_KEY_SIZE_BYTES];
+    size_t sig_length = sizeof( sig_buffer );
+
+    mbedtls_pk_init( &pkcs11_ctx );
+    mbedtls_pk_init( &transparent_ctx );
+
+    /* Initialize cryptoki and generate a key in the token */
+    hSession = pkcs11_init( );
+    TEST_ASSERT( hSession != CK_INVALID_HANDLE );
+
+    CK_ASSERT( pkcs11_generate_key( key_type,
+                                    hSession,
+                                    &hPublicKey, &hPrivateKey ) );
+    TEST_ASSERT( hPublicKey != CK_INVALID_HANDLE );
+    TEST_ASSERT( hPrivateKey != CK_INVALID_HANDLE );
+
+    /* Prepare the mbed TLS contexts */
+    TEST_ASSERT( mbedtls_pk_setup( &transparent_ctx,
+                                   mbedtls_pk_info_from_type( key_type ) ) == 0 );
+    TEST_ASSERT( mbedtls_pk_setup_pkcs11( &pkcs11_ctx,
+                                          hSession,
+                                          hPublicKey,
+                                          hPrivateKey ) == 0 );
+
+    /* Retrieve the public key from the token */
+    switch( key_type )
+    {
+#if defined(MBEDTLS_RSA_C)
+    case MBEDTLS_PK_RSA:
+        {
+            unsigned char n_buffer[RSA_KEY_SIZE_BYTES];
+            unsigned char e_buffer[RSA_KEY_SIZE_BYTES];
+            CK_ATTRIBUTE public_attributes[] = {
+                {CKA_MODULUS, n_buffer, sizeof( n_buffer )},
+                {CKA_PUBLIC_EXPONENT, e_buffer, sizeof( e_buffer )},
+            };
+            CK_ULONG *n_length = &public_attributes[0].ulValueLen;
+            CK_ULONG *e_length = &public_attributes[1].ulValueLen;
+            mbedtls_rsa_context *rsa_ctx = mbedtls_pk_rsa( transparent_ctx );
+
+            CK_ASSERT( C_GetAttributeValue( hSession, hPublicKey,
+                                            public_attributes, ARRAY_LENGTH( public_attributes ) ) );
+            TEST_ASSERT( mbedtls_mpi_read_binary( &rsa_ctx->N,
+                                                  n_buffer, *n_length ) == 0 );
+            TEST_ASSERT( mbedtls_mpi_read_binary( &rsa_ctx->E,
+                                                  e_buffer, *e_length ) == 0 );
+            rsa_ctx->len = mbedtls_mpi_size( &rsa_ctx->N );
+        }
+        break;
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECDSA_C)
+    case MBEDTLS_PK_ECDSA:
+        {
+            unsigned char ecParams[16];
+            unsigned char ecPoint[128];
+            CK_ATTRIBUTE public_attributes[] = {
+                {CKA_EC_PARAMS, ecParams, sizeof( ecParams )},
+                {CKA_EC_POINT, ecPoint, sizeof( ecPoint )},
+            };
+            mbedtls_ecp_keypair *ecp_ctx = mbedtls_pk_ec( transparent_ctx );
+
+            CK_ASSERT( C_GetAttributeValue( hSession, hPublicKey,
+                                            public_attributes, ARRAY_LENGTH( public_attributes ) ) );
+            // TODO: lift out a function or two from pkparse.c
+            // * pk_get_ecparams followed by pk_use_ecparams for ecParams?
+            // * Some code from pk_group_from_specified to read an octet string for ecPoint?
+            {
+                mbedtls_asn1_buf params_asn1;
+                CK_ULONG ecParams_length = public_attributes[0].ulValueLen;
+                mbedtls_ecp_group_id grp_id;
+                params_asn1.tag = ecParams[0];
+                params_asn1.len = ecParams[1];
+                params_asn1.p = ecParams + 2;
+                TEST_ASSERT( ecParams_length == 2 + params_asn1.len );
+                TEST_ASSERT( mbedtls_oid_get_ec_grp( &params_asn1, &grp_id ) == 0 );
+                TEST_ASSERT( mbedtls_ecp_group_load( &ecp_ctx->grp, grp_id ) == 0 );
+            }
+            {
+                unsigned char *p = ecPoint;
+                size_t len;
+                CK_ULONG ecPoint_length = public_attributes[1].ulValueLen;
+                TEST_ASSERT( mbedtls_asn1_get_tag( &p,
+                                                   ecPoint + ecPoint_length,
+                                                   &len,
+                                                   MBEDTLS_ASN1_OCTET_STRING ) == 0 );
+                TEST_ASSERT( mbedtls_ecp_point_read_binary( &ecp_ctx->grp,
+                                                            &ecp_ctx->Q,
+                                                            p, len ) == 0 );
+            }
+        }
+        break;
+#endif /* MBEDTLS_ECDSA_C */
+
+    default:
+        TEST_ASSERT( !"Unsupported key type in test data" );
+        break;
+    }
+
+    /* Sign with the token and verify in software */
+    TEST_ASSERT( mbedtls_pk_sign( &pkcs11_ctx, MBEDTLS_MD_SHA256,
+                                  hash_value, 32,
+                                  sig_buffer, &sig_length,
+                                  NULL, NULL ) == 0 );
+    TEST_ASSERT( mbedtls_pk_verify( &pkcs11_ctx, MBEDTLS_MD_SHA256,
+                                    hash_value, 32,
+                                    sig_buffer, sig_length ) == 0 );
+
+exit:
+    if( hPublicKey != CK_INVALID_HANDLE )
+        C_DestroyObject( hSession, hPublicKey );
+    if( hPrivateKey != CK_INVALID_HANDLE )
+        C_DestroyObject( hSession, hPrivateKey );
+    C_CloseSession( hSession );
+    C_Finalize( NULL_PTR );
+    mbedtls_pk_free( &pkcs11_ctx );
+    mbedtls_pk_free( &transparent_ctx );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PK_C:MBEDTLS_SHA256_C */
+void pk_import_signI_verifyX( char *file )
+{
+    /* Sign with mbedTLS, verify by cryptoki with a conversion 
+       to a raw, concatenated format by the engine. */
+    mbedtls_pk_context pkcs11_ctx;
+    mbedtls_pk_context transparent_ctx;
+    CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+    unsigned char hash_value[32] = "Fake hash, it doesn't matter....";
+    unsigned char sig_buffer[4096];
+    size_t sig_length = sizeof( sig_buffer );
+
+    mbedtls_pk_init( &pkcs11_ctx );
+    mbedtls_pk_init( &transparent_ctx );
+
+    /* Read a transparent key */
+    TEST_ASSERT( mbedtls_pk_parse_keyfile( &transparent_ctx, file, NULL ) == 0 );
+
+    /* Initialize cryptoki and import the key into the token */
+    hSession = pkcs11_init( );
+    TEST_ASSERT( hSession != CK_INVALID_HANDLE );
+
+    TEST_ASSERT( mbedtls_pk_import_to_pkcs11( &transparent_ctx,
+                                              MBEDTLS_PK_FLAG_SIGN |
+                                              MBEDTLS_PK_FLAG_VERIFY,
+                                              hSession,
+                                              &hPublicKey,
+                                              &hPrivateKey ) == 0 );
+    TEST_ASSERT( hPublicKey != CK_INVALID_HANDLE );
+    TEST_ASSERT( hPrivateKey != CK_INVALID_HANDLE );
+    TEST_ASSERT( mbedtls_pk_setup_pkcs11( &pkcs11_ctx,
+                                          hSession,
+                                          hPublicKey,
+                                          hPrivateKey ) == 0 );
+
+    /* Sign with the token and verify with cryptoki */
+    TEST_ASSERT( sizeof( sig_buffer ) >= mbedtls_pk_signature_size( &pkcs11_ctx ) );
+    TEST_ASSERT( mbedtls_pk_sign( &transparent_ctx, MBEDTLS_MD_SHA256,
+                                  hash_value, 32,
+                                  sig_buffer, &sig_length,
+                                  NULL, NULL ) == 0 );
+    TEST_ASSERT( mbedtls_pk_verify( &pkcs11_ctx, MBEDTLS_MD_SHA256,
+                                    hash_value, 32,
+                                    sig_buffer, sig_length ) == 0 );
+
+exit:
+    if( hPublicKey != CK_INVALID_HANDLE )
+        C_DestroyObject( hSession, hPublicKey );
+    if( hPrivateKey != CK_INVALID_HANDLE )
+        C_DestroyObject( hSession, hPrivateKey );
+    C_CloseSession( hSession );
+    C_Finalize( NULL_PTR );
+    mbedtls_pk_free( &pkcs11_ctx );
+    mbedtls_pk_free( &transparent_ctx );
+}
+/* END_CASE */