Add ECDSA verify

Add tests for external verification when signing is done both internally and externally
This commit is contained in:
Andrzej Kurek 2018-01-23 06:10:53 -05:00
parent 4226dec155
commit c289bf1a30
5 changed files with 364 additions and 7 deletions

View File

@ -235,6 +235,27 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
#endif /* MBEDTLS_DEPRECATED_REMOVED */
#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
*
@ -253,9 +274,9 @@ int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx,
* 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

View File

@ -286,10 +286,71 @@ cleanup:
}
#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 @@ int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t
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 );

View File

@ -209,7 +209,7 @@ static int pkcs11_sign( void *ctx_arg,
}
/* 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 @@ exit:
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

View File

@ -5,3 +5,11 @@ pk_import_sign:"data_files/server3.key"
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"

View File

@ -323,3 +323,194 @@ exit:
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 */