mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-23 00:15:40 +01:00
Add ECDSA verify
Add tests for external verification when signing is done both internally and externally
This commit is contained in:
parent
4226dec155
commit
c289bf1a30
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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( ¶ms_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 */
|
||||
|
Loading…
Reference in New Issue
Block a user