diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index fcecdafdc..826ee6492 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 d7503ac83..046bfc501 100644 --- a/include/mbedtls/rsa.h +++ b/include/mbedtls/rsa.h @@ -736,6 +736,36 @@ int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, unsigned char *output, 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 diff --git a/library/pkcs11_client.c b/library/pkcs11_client.c index a3e387a9a..2e97d0e27 100644 --- a/library/pkcs11_client.c +++ b/library/pkcs11_client.c @@ -138,6 +138,39 @@ static size_t pkcs11_pk_signature_size( const void *ctx_arg ) } } +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 @@ static int pkcs11_sign( void *ctx_arg, 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 @@ static int pkcs11_sign( void *ctx_arg, { #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 @@ static int pkcs11_sign( void *ctx_arg, 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 9e4a21357..7f1a7451d 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1526,11 +1526,11 @@ int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, /* 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 @@ static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg, 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 3f4d4cfa3..ba47f951e 100644 --- a/tests/suites/test_suite_pkcs11_client.data +++ b/tests/suites/test_suite_pkcs11_client.data @@ -5,3 +5,15 @@ pk_import_sign:"data_files/server1.key" 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 34800ef1f..d97233644 100644 --- a/tests/suites/test_suite_pkcs11_client.function +++ b/tests/suites/test_suite_pkcs11_client.function @@ -294,3 +294,190 @@ exit: 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 */