/* * EC public key is an EC point * * The caller is responsible for clearing the structure upon failure if * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. */ static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, mbedtls_ecp_keypair *key ) { int ret; if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, (const unsigned char *) *p, end - *p ) ) == 0 ) { ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); } /* * We know mbedtls_ecp_point_read_binary consumed all bytes or failed */ *p = (unsigned char *) end; return( ret ); }
/* * Verify ECDSA signature of hashed message (SEC1 4.1.4) * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) */ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) { int ret; mbedtls_mpi e, s_inv, u1, u2; mbedtls_ecp_point R; mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ if( grp->N.p == NULL ) return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); /* * Step 1: make sure r and s are in range 1..n-1 */ if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } /* * Additional precaution: make sure Q is valid */ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); /* * Step 3: derive MPI from hashed message */ MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Step 4: u1 = e / s mod n, u2 = r / s mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); /* * Step 5: R = u1 G + u2 Q * * Since we're not using any secret data, no need to pass a RNG to * mbedtls_ecp_mul() for countermesures. */ MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); if( mbedtls_ecp_is_zero( &R ) ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } /* * Step 6: convert xR to an integer (no-op) * Step 7: reduce xR mod n (gives v) */ MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); /* * Step 8: check if v (that is, R.X) is equal to r */ if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) { ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; goto cleanup; } cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); return( ret ); }
int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; void* pHeap = NULL; size_t heapSize = 0; size_t public_key_size = (grp->nbits+7)/8 ; const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); uint32_t secret_size = ( ( grp->nbits + 7 ) / 8 ) ; const uint32_t secret_size_in_heap = secret_size; uint8_t* secret = mbedtls_calloc( 1, secret_size_in_heap ); if ( secret == NULL ) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); /* * Make sure Q is a valid pubkey before using it */ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); if ( pDomain ) { uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; cc_ecc_ws_comp_shared_params_t* ecdhParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_comp_shared_params_t) ); if ( ecdhParams == NULL ) { ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; goto cleanup; } pHeap = ecdhParams; heapSize = sizeof(cc_ecc_ws_comp_shared_params_t); MBEDTLS_MPI_CHK( mbedtls_ecp_point_write_binary( grp, Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &public_key_size, temp_buf, sizeof(temp_buf) ) ); ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_BuildPublKey( pDomain, temp_buf, public_key_size, &ecdhParams->pubKey ) ); if ( ret != 0 ) { goto cleanup; } memset ( temp_buf, 0, sizeof(temp_buf) ); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, temp_buf, mbedtls_mpi_size( d ) ) ); ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_BuildPrivKey( pDomain, temp_buf, mbedtls_mpi_size( d ), &ecdhParams->privKey ) ); mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); if ( ret != 0 ) { goto cleanup; } ret = convert_CrysError_to_mbedtls_err( CRYS_ECDH_SVDP_DH( &ecdhParams->pubKey, &ecdhParams->privKey, secret, &secret_size, &ecdhParams->ecdhTempData ) ); if ( ret != 0 ) { goto cleanup; } } else if ( grp->id == MBEDTLS_ECP_DP_CURVE25519 ) { cc_ecc_25519_comp_shared_params_t* ecdhParams = mbedtls_calloc( 1, sizeof(cc_ecc_25519_comp_shared_params_t) ); if ( ecdhParams == NULL ) { ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; goto cleanup; } pHeap = ecdhParams; heapSize = sizeof(cc_ecc_25519_comp_shared_params_t); MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, ecdhParams->privKey, mbedtls_mpi_size( d ) ) ) ; MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &Q->X, ecdhParams->pubKey, public_key_size ) ); ret = convert_CrysError_to_mbedtls_err( CRYS_ECMONT_Scalarmult( secret, ( size_t* )&secret_size, ecdhParams->privKey, CURVE_25519_KEY_SIZE , ecdhParams->pubKey, CURVE_25519_KEY_SIZE , &ecdhParams->kgTempData ) ); if ( ret != 0 ) { goto cleanup; } } else { ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( z, secret, secret_size ) ); cleanup: if ( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free ( pHeap ); } if ( secret ) { mbedtls_zeroize( secret, secret_size_in_heap ); mbedtls_free ( secret ); } return ( ret ); }