int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, const ECDSA_SIG *sig, const EC_KEY *eckey) { int ret = 0; BN_CTX *ctx; BIGNUM *u1, *u2, *m, *X; EC_POINT *point = NULL; const EC_GROUP *group; const EC_POINT *pub_key; // check input values if ((group = EC_KEY_get0_group(eckey)) == NULL || (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS); return 0; } ctx = BN_CTX_new(); if (!ctx) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); return 0; } BN_CTX_start(ctx); u1 = BN_CTX_get(ctx); u2 = BN_CTX_get(ctx); m = BN_CTX_get(ctx); X = BN_CTX_get(ctx); if (u1 == NULL || u2 == NULL || m == NULL || X == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } const BIGNUM *order = EC_GROUP_get0_order(group); if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); goto err; } // calculate tmp1 = inv(S) mod order int no_inverse; if (!BN_mod_inverse_odd(u2, &no_inverse, sig->s, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } if (!digest_to_bn(m, digest, digest_len, order)) { goto err; } // u1 = m * tmp mod order if (!BN_mod_mul(u1, m, u2, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } // u2 = r * w mod q if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } point = EC_POINT_new(group); if (point == NULL) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); goto err; } if (!BN_nnmod(u1, X, order, ctx)) { OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); goto err; } // if the signature is correct u1 is equal to sig->r if (BN_ucmp(u1, sig->r) != 0) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); goto err; } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(ctx); EC_POINT_free(point); return ret; }
int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp, *tmp_Z; BIGNUM **prod_Z = NULL; int ret = 0; if (num == 0) { return 1; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); tmp_Z = BN_CTX_get(ctx); if (tmp == NULL || tmp_Z == NULL) { goto err; } prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0])); if (prod_Z == NULL) { goto err; } OPENSSL_memset(prod_Z, 0, num * sizeof(prod_Z[0])); for (size_t i = 0; i < num; i++) { prod_Z[i] = BN_new(); if (prod_Z[i] == NULL) { goto err; } } // Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, // skipping any zero-valued inputs (pretend that they're 1). if (!BN_is_zero(&points[0]->Z)) { if (!BN_copy(prod_Z[0], &points[0]->Z)) { goto err; } } else { if (BN_copy(prod_Z[0], &group->one) == NULL) { goto err; } } for (size_t i = 1; i < num; i++) { if (!BN_is_zero(&points[i]->Z)) { if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], &points[i]->Z, ctx)) { goto err; } } else { if (!BN_copy(prod_Z[i], prod_Z[i - 1])) { goto err; } } } // Now use a single explicit inversion to replace every non-zero points[i]->Z // by its inverse. We use |BN_mod_inverse_odd| instead of doing a constant- // time inversion using Fermat's Little Theorem because this function is // usually only used for converting multiples of a public key point to // affine, and a public key point isn't secret. If we were to use Fermat's // Little Theorem then the cost of the inversion would usually be so high // that converting the multiples to affine would be counterproductive. int no_inverse; if (!BN_mod_inverse_odd(tmp, &no_inverse, prod_Z[num - 1], &group->field, ctx)) { OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); goto err; } if (group->meth->field_encode != NULL) { // In the Montgomery case, we just turned R*H (representing H) // into 1/(R*H), but we need R*(1/H) (representing 1/H); // i.e. we need to multiply by the Montgomery factor twice. if (!group->meth->field_encode(group, tmp, tmp, ctx) || !group->meth->field_encode(group, tmp, tmp, ctx)) { goto err; } } for (size_t i = num - 1; i > 0; --i) { // Loop invariant: tmp is the product of the inverses of // points[0]->Z .. points[i]->Z (zero-valued inputs skipped). if (BN_is_zero(&points[i]->Z)) { continue; } // Set tmp_Z to the inverse of points[i]->Z (as product // of Z inverses 0 .. i, Z values 0 .. i - 1). if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx) || // Update tmp to satisfy the loop invariant for i - 1. !group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx) || // Replace points[i]->Z by its inverse. !BN_copy(&points[i]->Z, tmp_Z)) { goto err; } } // Replace points[0]->Z by its inverse. if (!BN_is_zero(&points[0]->Z) && !BN_copy(&points[0]->Z, tmp)) { goto err; } // Finally, fix up the X and Y coordinates for all points. for (size_t i = 0; i < num; i++) { EC_POINT *p = points[i]; if (!BN_is_zero(&p->Z)) { // turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1). if (!group->meth->field_sqr(group, tmp, &p->Z, ctx) || !group->meth->field_mul(group, &p->X, &p->X, tmp, ctx) || !group->meth->field_mul(group, tmp, tmp, &p->Z, ctx) || !group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) { goto err; } if (BN_copy(&p->Z, &group->one) == NULL) { goto err; } } } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); if (prod_Z != NULL) { for (size_t i = 0; i < num; i++) { if (prod_Z[i] == NULL) { break; } BN_clear_free(prod_Z[i]); } OPENSSL_free(prod_Z); } return ret; }