pkcs11_client: implement RSA sign/verify

Make mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo from rsa.c public,
and use it in the pkcs11_client module.

pkcs11_client: refactor pkcs11_sign and pkcs11_verify to simplify
memory managmement. Implement these functions for RSA.
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index fcecdaf..826ee64 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -227,6 +227,8 @@
 
 #define MBEDTLS_OID_HMAC_SHA1                   MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */
 
+#define MBEDTLS_MD_OID_MAX_SIZE 10 /**< Maximum length of an OID of a supported digest algorithm*/
+
 /*
  * Encryption algorithms
  */
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index d7503ac..046bfc5 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -737,6 +737,36 @@
                             size_t output_max_len );
 
 /**
+ * \brief          Encode a hash into a DigestInfo structure as specified
+ *                 by PKCS#1(RFC 8017, EMSA-PKCS1-v1_5-ENCODE step 2).
+ *                 Note: function works backwards in data buffer.
+ *
+ * \param p        Reference to the current position pointer
+ * \param start    Start of the buffer (for bounds checking)
+ * \param md_alg   Digest algorithm
+ * \param hash     Hash value
+ * \param hashlen  Length of the hash, or 0 to calculate it from \c md_alg
+ *
+ * \note           This function writes from right to left: the start of the
+ *                 written data is the value of \c *p on exit, and the end of
+ *                 the written data is the value of \c *p on entry.
+ *
+ * \note           If \c md_alg is \c MBEDTLS_MD_NONE, this function just
+ *                 copies \c hashlen bytes to the left of \c *p.
+ */
+int mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo( unsigned char **p,
+                                                  unsigned char *start,
+                                                  mbedtls_md_type_t md_alg,
+                                                  const unsigned char *hash,
+                                                  size_t hashlen );
+
+/** Maximum size of the output of
+ * mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo()  */
+#define MBEDTLS_RSA_PKCS1_DIGESTINFO_MAX_SIZE   \
+    ( MBEDTLS_MD_MAX_SIZE +                     \
+      MBEDTLS_MD_OID_MAX_SIZE +                 \
+      10 /*additional encoding bytes*/ )
+/**
  * \brief          Generic wrapper to perform a PKCS#1 signature using the
  *                 mode from the context. Do a private RSA operation to sign
  *                 a message digest
diff --git a/library/pkcs11_client.c b/library/pkcs11_client.c
index a3e387a..2e97d0e 100644
--- a/library/pkcs11_client.c
+++ b/library/pkcs11_client.c
@@ -138,6 +138,39 @@
     }
 }
 
+static int pkcs11_sign_core( mbedtls_pk_pkcs11_context_t *ctx,
+                             CK_MECHANISM_TYPE mechanism_type,
+                             const unsigned char *payload, size_t payload_len,
+                             unsigned char *sig, size_t *sig_len,
+                             size_t sig_size )
+{
+    CK_ULONG ck_sig_len = sig_size;
+    CK_MECHANISM mechanism = {mechanism_type, NULL_PTR, 0};
+    CK_RV rv;
+    rv = C_SignInit( ctx->hSession, &mechanism, ctx->hPrivateKey );
+    if( rv != CKR_OK )
+        goto exit;
+    rv = C_Sign( ctx->hSession, (CK_BYTE_PTR) payload, payload_len,
+                 sig, &ck_sig_len );
+    if( rv != CKR_OK )
+        goto exit;
+    *sig_len = ck_sig_len;
+exit:
+    return( pkcs11_err_to_mbedtls_pk_err( rv ) );
+}
+
+#if defined(MBEDTLS_RSA_C)
+static int pkcs11_sign_rsa( mbedtls_pk_pkcs11_context_t *ctx,
+                            const unsigned char *digest_info,
+                            size_t digest_info_len,
+                            unsigned char *sig, size_t *sig_len )
+{
+    return( pkcs11_sign_core( ctx, CKM_RSA_PKCS,
+                              digest_info, digest_info_len,
+                              sig, sig_len, ( ctx->bit_length + 7 ) / 8 ) );
+}
+#endif /* MBEDTLS_RSA_C */
+
 static int pkcs11_sign( void *ctx_arg,
                         mbedtls_md_type_t md_alg,
                         const unsigned char *hash, size_t hash_len,
@@ -146,9 +179,9 @@
                         void *p_rng )
 {
     mbedtls_pk_pkcs11_context_t *ctx = ctx_arg;
-    CK_RV rv;
-    CK_MECHANISM mechanism = {0, NULL_PTR, 0};
-    CK_ULONG ck_sig_len;
+    int ret;
+
+    *sig_len = 0;
 
     /* This function takes size_t arguments but the underlying layer
        takes unsigned long. Either type may be smaller than the other.
@@ -163,30 +196,27 @@
     {
 #if defined(MBEDTLS_RSA_C)
     case MBEDTLS_PK_RSA:
-        ck_sig_len = ( ctx->bit_length + 7 ) / 8;
-        // FIXME: these mechanisms perform hashing as well as signing.
-        // But here we get the hash as input. So we need to invoke
-        // CKM_RSA_PKCS. But CKM_RSA_PKCS doesn't perform the hash
-        // encoding, only a part of the padding.
-        switch( md_alg )
+        /* There is no mechanism in PKCS#11 that computes a PKCS#1 v1.5
+         * signature from a hash value and a hash type, only mechanisms
+         * that include the hash calculation and a mechanism that expects
+         * a DigestInfo (encoded hash that isn't padded). So we use the
+         * mechanism that expects a DigestInfo, and calculate the DigestInfo
+         * ourselves if needed. */
+        if( md_alg == MBEDTLS_MD_NONE )
         {
-        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 );
+            ret = pkcs11_sign_rsa( ctx, hash, hash_len, sig, sig_len );
+        }
+        else
+        {
+            unsigned char digest_info[MBEDTLS_RSA_PKCS1_DIGESTINFO_MAX_SIZE];
+            unsigned char *p = digest_info + sizeof( digest_info );
+            size_t digest_info_len;
+            if( mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo(
+                    &p, digest_info,
+                    md_alg, hash, hash_len ) != 0 )
+                return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+            digest_info_len = digest_info + sizeof( digest_info ) - p;
+            ret = pkcs11_sign_rsa( ctx, p, digest_info_len, sig, sig_len );
         }
         break;
 #endif /* MBEDTLS_RSA_C */
@@ -194,37 +224,96 @@
         return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
     }
 
-    rv = C_SignInit( ctx->hSession, &mechanism, ctx->hPrivateKey );
-    if( rv != CKR_OK )
-        goto exit;
-    rv = C_Sign( ctx->hSession, (CK_BYTE_PTR) hash, hash_len,
-                 sig, &ck_sig_len );
-    if( rv != CKR_OK )
-        goto exit;
+    if( ret != 0 )
+        memset( sig, 0, *sig_len );
+    return( ret );
+}
 
-        *sig_len = ck_sig_len;
+static int pkcs11_verify_core( mbedtls_pk_pkcs11_context_t *ctx,
+                               CK_MECHANISM_TYPE mechanism_type,
+                               const unsigned char *payload, size_t payload_len,
+                               const unsigned char *sig, size_t sig_len )
+{
+    CK_MECHANISM mechanism = {mechanism_type, NULL_PTR, 0};
+    CK_RV rv;
+
+    rv = C_VerifyInit( ctx->hSession, &mechanism, ctx->hPublicKey );
+    if( rv != CKR_OK )
+        goto exit;
+    rv = C_Verify( ctx->hSession, (CK_BYTE_PTR) payload, payload_len,
+                   (CK_BYTE_PTR) sig, sig_len );
+    if( rv != CKR_OK )
+        goto exit;
 
 exit:
-    if( rv != CKR_OK )
-        memset( sig, 0, ck_sig_len );
     return( pkcs11_err_to_mbedtls_pk_err( rv ) );
 }
 
-static const mbedtls_pk_info_t mbedtls_pk_pkcs11_info = {
-    MBEDTLS_PK_OPAQUE,
-    "pkcs11",
-    pkcs11_pk_get_bitlen,
-    pkcs11_pk_can_do, //can_do
-    NULL, //pkcs11_verify,
-    pkcs11_sign,
-    NULL, //pkcs11_decrypt,
-    NULL, //pkcs11_encrypt,
-    NULL, //check_pair_func
-    pkcs11_pk_alloc,
-    pkcs11_pk_free,
-    NULL, //debug_func
-    pkcs11_pk_signature_size,
-};
+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;
+
+    /* 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:
+        /* There is no mechanism in PKCS#11 that computes a PKCS#1 v1.5
+         * signature from a hash value and a hash type, only mechanisms
+         * that include the hash calculation and a mechanism that expects
+         * a DigestInfo (encoded hash that isn't padded). So we use the
+         * mechanism that expects a DigestInfo, and calculate the DigestInfo
+         * ourselves if needed. */
+        if( md_alg == MBEDTLS_MD_NONE )
+        {
+            return( pkcs11_verify_core( ctx, CKM_RSA_PKCS,
+                                        hash, hash_len,
+                                        sig, sig_len ) );
+        }
+        else
+        {
+            unsigned char digest_info[MBEDTLS_RSA_PKCS1_DIGESTINFO_MAX_SIZE];
+            unsigned char *p = digest_info + sizeof( digest_info );
+            size_t digest_info_len;
+            if( mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo(
+                    &p, digest_info,
+                    md_alg, hash, hash_len ) != 0 )
+                return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
+            digest_info_len = digest_info + sizeof( digest_info ) - p;
+            return( pkcs11_verify_core( ctx, CKM_RSA_PKCS,
+                                        p, digest_info_len,
+                                        sig, sig_len ) );
+        }
+        break;
+#endif /* MBEDTLS_RSA_C */
+    default:
+        return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG );
+    }
+}
+
+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
+                              , pkcs11_verify
+                              , pkcs11_sign
+                              , NULL //pkcs11_decrypt
+                              , NULL //pkcs11_encrypt
+                              , NULL //check_pair_func
+                              , pkcs11_pk_alloc
+                              , pkcs11_pk_free
+                              , NULL //debug_func
+        );
 
 int mbedtls_pk_setup_pkcs11( mbedtls_pk_context *ctx,
                              CK_SESSION_HANDLE hSession,
diff --git a/library/rsa.c b/library/rsa.c
index 9e4a213..7f1a745 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1526,11 +1526,11 @@
 /* Encode a hash into a DigestInfo structure as specified by PKCS#1
  * (RFC 8017, EMSA-PKCS1-v1_5-ENCODE step 2).
  * Write to the left of p and set *p to the leftmost byte written. */
-static int rsa_emsa_pkcs1_v15_encode_digestinfo( unsigned char **p,
-                                                 unsigned char *start,
-                                                 mbedtls_md_type_t md_alg,
-                                                 const unsigned char *hash,
-                                                 size_t hashlen )
+int mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo( unsigned char **p,
+                                                  unsigned char *start,
+                                                  mbedtls_md_type_t md_alg,
+                                                  const unsigned char *hash,
+                                                  size_t hashlen )
 {
     const mbedtls_md_info_t *md_info;
     const char *oid;
@@ -1661,8 +1661,8 @@
     if( md_alg != MBEDTLS_MD_NONE )
         hashlen = 0;
 
-    ret = rsa_emsa_pkcs1_v15_encode_digestinfo( &p, dst,
-                                                md_alg, hash, hashlen );
+    ret = mbedtls_rsa_emsa_pkcs1_v15_encode_digestinfo( &p, dst,
+                                                        md_alg, hash, hashlen );
     if( ret != 0 )
         return( ret );
 
diff --git a/tests/suites/test_suite_pkcs11_client.data b/tests/suites/test_suite_pkcs11_client.data
index 3f4d4cf..ba47f95 100644
--- a/tests/suites/test_suite_pkcs11_client.data
+++ b/tests/suites/test_suite_pkcs11_client.data
@@ -5,3 +5,15 @@
 PKCS#11 RSA generate and sign
 depends_on:MBEDTLS_PK_C:MBEDTLS_RSA_C
 pk_generate_sign:MBEDTLS_PK_RSA
+
+PKCS#11 RSA import, sign and verify with Cryptoki
+depends_on:MBEDTLS_PK_C:MBEDTLS_RSA_C
+pk_import_sign_verify:"data_files/server1.key"
+
+PKCS#11 RSA import, sign with MbedTLS and verify with Cryptoki
+depends_on:MBEDTLS_PK_C:MBEDTLS_RSA_C
+pk_import_verify_signed:"data_files/server1.key"
+
+PKCS#11 RSA verify a hardcoded signature with Cryptoki
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_PKCS1_V15
+pk_rsa_hardcoded_verify:"206ef4bf396c6087f8229ef196fd35f37ccb8de5efcdb238f20d556668f114257a11fbe038464a67830378e62ae9791453953dac1dbd7921837ba98e84e856eb80ed9487e656d0b20c28c8ba5e35db1abbed83ed1c7720a97701f709e3547a4bfcabca9c89c57ad15c3996577a0ae36d7c7b699035242f37954646c1cd5c08ac":MBEDTLS_MD_SHA1:1024:16:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":16:"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":0
diff --git a/tests/suites/test_suite_pkcs11_client.function b/tests/suites/test_suite_pkcs11_client.function
index 34800ef..d972336 100644
--- a/tests/suites/test_suite_pkcs11_client.function
+++ b/tests/suites/test_suite_pkcs11_client.function
@@ -294,3 +294,190 @@
     mbedtls_pk_free( &transparent_ctx );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PK_C:MBEDTLS_SHA256_C */
+void pk_import_sign_verify( char *file )
+ {
+    /* 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[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( &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_verify_signed( 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,
+                                              NULL ) == 0 );
+    TEST_ASSERT( hPublicKey != CK_INVALID_HANDLE );
+    TEST_ASSERT( mbedtls_pk_setup_pkcs11( &pkcs11_ctx,
+                                          hSession,
+                                          hPublicKey,
+                                          CK_INVALID_HANDLE ) == 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 */
+
+/* BEGIN_CASE depends_on:MBEDTLS_RSA_C */
+void pk_rsa_hardcoded_verify( char *message_hex_string, int digest,
+                       int mod, int radix_N, char *input_N, int radix_E,
+                       char *input_E, char *result_hex_str, int result )
+{
+    unsigned char message_str[1000];
+    unsigned char hash_result[1000];
+    unsigned char result_str[1000];
+    mbedtls_rsa_context *rsa;
+    mbedtls_pk_context transparent_ctx;
+    int msg_len;
+
+    mbedtls_pk_context pkcs11_ctx;
+    CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPublicKey = CK_INVALID_HANDLE;
+    CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE;
+
+    mbedtls_pk_init( &transparent_ctx );
+
+    memset( message_str, 0x00, 1000 );
+    memset( hash_result, 0x00, 1000 );
+    memset( result_str, 0x00, 1000 );
+
+    TEST_ASSERT( mbedtls_pk_setup( &transparent_ctx, mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == 0 );
+    rsa = mbedtls_pk_rsa( transparent_ctx );
+
+    rsa->len = mod / 8;
+    TEST_ASSERT( mbedtls_mpi_read_string( &rsa->N, radix_N, input_N ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &rsa->E, radix_E, input_E ) == 0 );
+
+    msg_len = unhexify( message_str, message_hex_string );
+    unhexify( result_str, result_hex_str );
+
+    if( mbedtls_md_info_from_type( digest ) != NULL )
+        TEST_ASSERT( mbedtls_md( mbedtls_md_info_from_type( digest ), message_str, msg_len, hash_result ) == 0 );
+
+    // PKCS11 part
+    mbedtls_pk_init( &pkcs11_ctx );
+
+    /* 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,
+                                              NULL ) == 0 );
+    TEST_ASSERT( hPublicKey != CK_INVALID_HANDLE );
+    TEST_ASSERT( mbedtls_pk_setup_pkcs11( &pkcs11_ctx,
+                                          hSession,
+                                          hPublicKey,
+                                          CK_INVALID_HANDLE ) == 0 );
+
+    TEST_ASSERT( mbedtls_pk_verify( &pkcs11_ctx, digest, hash_result, 0,
+                            result_str, mbedtls_pk_get_len( &transparent_ctx ) ) == result );
+
+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 */