/* * Free context */ void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) { if( ctx == NULL ) return; mbedtls_ecp_group_free( &ctx->grp ); mbedtls_ecp_point_free( &ctx->Q ); mbedtls_ecp_point_free( &ctx->Qp ); mbedtls_ecp_point_free( &ctx->Vi ); mbedtls_ecp_point_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->d ); mbedtls_mpi_free( &ctx->z ); mbedtls_mpi_free( &ctx->_d ); }
/* * Compute shared secret (SEC1 3.3.1) */ 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; mbedtls_ecp_point P; mbedtls_ecp_point_init( &P ); /* * Make sure Q is a valid pubkey before using it */ MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); if( mbedtls_ecp_is_zero( &P ) ) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); cleanup: mbedtls_ecp_point_free( &P ); return( ret ); }
/* * Clear some memory that was used to prepare the context */ static void ecc_clear_precomputed(mbedtls_ecp_group *grp) { size_t i = 0; if (grp->T) { for (i = 0; i < grp->T_size; i++) mbedtls_ecp_point_free(&grp->T[i]); free(grp->T); } grp->T = NULL; grp->T_size = 0; }
void ecp_clear_precomputed( mbedtls_ecp_group *grp ) { if( grp->T != NULL ) { size_t i; for( i = 0; i < grp->T_size; i++ ) mbedtls_ecp_point_free( &grp->T[i] ); mbedtls_free( grp->T ); } grp->T = NULL; grp->T_size = 0; }
/* * Verify ECDSA signature of hashed message (SEC1 4.1.4) * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) */ static int ecdsa_verify_restartable( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; mbedtls_mpi e, s_inv, u1, u2; mbedtls_ecp_point R; mbedtls_mpi *pu1 = &u1, *pu2 = &u2; 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 ); ECDSA_RS_ENTER( ver ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->ver != NULL ) { /* redirect to our context */ pu1 = &rs_ctx->ver->u1; pu2 = &rs_ctx->ver->u2; /* jump to current step */ if( rs_ctx->ver->state == ecdsa_ver_muladd ) goto muladd; } #endif /* MBEDTLS_ECP_RESTARTABLE */ /* * 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; } /* * 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 */ ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->ver != NULL ) rs_ctx->ver->state = ecdsa_ver_muladd; muladd: #endif /* * Step 5: R = u1 G + u2 Q */ MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp, &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) ); 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 ); ECDSA_RS_LEAVE( ver ); return( ret ); }
/* * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ static int ecdsa_sign_restartable( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret, key_tries, sign_tries; int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; mbedtls_ecp_point R; mbedtls_mpi k, e, t; mbedtls_mpi *pk = &k, *pr = r; /* 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 ); /* Make sure d is in range 1..n-1 */ if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) return( MBEDTLS_ERR_ECP_INVALID_KEY ); mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); ECDSA_RS_ENTER( sig ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) { /* redirect to our context */ p_sign_tries = &rs_ctx->sig->sign_tries; p_key_tries = &rs_ctx->sig->key_tries; pk = &rs_ctx->sig->k; pr = &rs_ctx->sig->r; /* jump to current step */ if( rs_ctx->sig->state == ecdsa_sig_mul ) goto mul; if( rs_ctx->sig->state == ecdsa_sig_modn ) goto modn; } #endif /* MBEDTLS_ECP_RESTARTABLE */ *p_sign_tries = 0; do { if( *p_sign_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } /* * Steps 1-3: generate a suitable ephemeral keypair * and set r = xR mod n */ *p_key_tries = 0; do { if( *p_key_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) rs_ctx->sig->state = ecdsa_sig_mul; mul: #endif MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G, f_rng, p_rng, ECDSA_RS_ECP ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) ); } while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) rs_ctx->sig->state = ecdsa_sig_modn; modn: #endif /* * Accounting for everything up to the end of the loop * (step 6, but checking now avoids saving e and t) */ ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 ); /* * Step 5: derive MPI from hashed message */ MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Generate a random value to blind inv_mod in next step, * avoiding a potential timing leak. */ MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) ); /* * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); } while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); #if defined(MBEDTLS_ECP_RESTARTABLE) if( rs_ctx != NULL && rs_ctx->sig != NULL ) mbedtls_mpi_copy( r, pr ); #endif cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); ECDSA_RS_LEAVE( sig ); return( ret ); }
/* * Compute ECDSA signature of a hashed message (SEC1 4.1.3) * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) */ int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, const mbedtls_mpi *d, const unsigned char *buf, size_t blen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, key_tries, sign_tries, blind_tries; mbedtls_ecp_point R; mbedtls_mpi k, e, t; /* 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 ); mbedtls_ecp_point_init( &R ); mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); sign_tries = 0; do { /* * Steps 1-3: generate a suitable ephemeral keypair * and set r = xR mod n */ key_tries = 0; do { MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); if( key_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } } while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); /* * Step 5: derive MPI from hashed message */ MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); /* * Generate a random value to blind inv_mod in next step, * avoiding a potential timing leak. */ blind_tries = 0; do { size_t n_size = ( grp->nbits + 7 ) / 8; MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); /* See mbedtls_ecp_gen_keypair() */ if( ++blind_tries > 30 ) return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); } while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); /* * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n */ MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); if( sign_tries++ > 10 ) { ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; goto cleanup; } } while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); cleanup: mbedtls_ecp_point_free( &R ); mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); 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 ); }