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.
This commit is contained in:
Andrzej Kurek 2018-01-24 08:15:51 -05:00
parent 72a0789e63
commit 79f4e0e91d
6 changed files with 378 additions and 58 deletions

View file

@ -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
*/

View file

@ -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

View file

@ -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,

View file

@ -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 );

View file

@ -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

View file

@ -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 */