- if (ctx != NULL)
- BN_CTX_free(ctx);
- if (point != NULL)
- EC_POINT_free(point);
- return(ok);
- }
-
-int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y)
- {
- BN_CTX *ctx = NULL;
- BIGNUM *tx, *ty;
- EC_POINT *point = NULL;
- int ok = 0, tmp_nid, is_char_two = 0;
-
- if (!key || !key->group || !x || !y)
- {
- ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
- ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- ctx = BN_CTX_new();
- if (!ctx)
- goto err;
-
- point = EC_POINT_new(key->group);
-
- if (!point)
- goto err;
-
- tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(key->group));
-
- if (tmp_nid == NID_X9_62_characteristic_two_field)
- is_char_two = 1;
-
- tx = BN_CTX_get(ctx);
- ty = BN_CTX_get(ctx);
-#ifndef OPENSSL_NO_EC2M
- if (is_char_two)
- {
- if (!EC_POINT_set_affine_coordinates_GF2m(key->group, point,
- x, y, ctx))
- goto err;
- if (!EC_POINT_get_affine_coordinates_GF2m(key->group, point,
- tx, ty, ctx))
- goto err;
- }
- else
-#endif
- {
- if (!EC_POINT_set_affine_coordinates_GFp(key->group, point,
- x, y, ctx))
- goto err;
- if (!EC_POINT_get_affine_coordinates_GFp(key->group, point,
- tx, ty, ctx))
- goto err;
- }
- /* Check if retrieved coordinates match originals: if not values
- * are out of range.
- */
- if (BN_cmp(x, tx) || BN_cmp(y, ty))
- {
- ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
- EC_R_COORDINATES_OUT_OF_RANGE);
- goto err;
- }
-
- if (!EC_KEY_set_public_key(key, point))
- goto err;
-
- if (EC_KEY_check_key(key) == 0)
- goto err;
-
- ok = 1;
-
- err:
- if (ctx)
- BN_CTX_free(ctx);
- if (point)
- EC_POINT_free(point);
- return ok;
-
- }
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/*
+ * ECC Key validation as specified in SP800-56A R3.
+ * Section 5.6.2.3.3 ECC Full Public-Key Validation.
+ */
+int ec_key_public_check(const EC_KEY *eckey, BN_CTX *ctx)
+{
+ int ret = 0;
+ EC_POINT *point = NULL;
+ const BIGNUM *order = NULL;
+
+ if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) {
+ ECerr(0, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ /* 5.6.2.3.3 (Step 1): Q != infinity */
+ if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
+ ECerr(0, EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+
+ point = EC_POINT_new(eckey->group);
+ if (point == NULL)
+ return 0;
+
+ /* 5.6.2.3.3 (Step 2) Test if the public key is in range */
+ if (!ec_key_public_range_check(ctx, eckey)) {
+ ECerr(0, EC_R_COORDINATES_OUT_OF_RANGE);
+ goto err;
+ }
+
+ /* 5.6.2.3.3 (Step 3) is the pub_key on the elliptic curve */
+ if (EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx) <= 0) {
+ ECerr(0, EC_R_POINT_IS_NOT_ON_CURVE);
+ goto err;
+ }
+
+ order = eckey->group->order;
+ if (BN_is_zero(order)) {
+ ECerr(0, EC_R_INVALID_GROUP_ORDER);
+ goto err;
+ }
+ /* 5.6.2.3.3 (Step 4) : pub_key * order is the point at infinity. */
+ if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) {
+ ECerr(0, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (!EC_POINT_is_at_infinity(eckey->group, point)) {
+ ECerr(0, EC_R_WRONG_ORDER);
+ goto err;
+ }
+ ret = 1;
+err:
+ EC_POINT_free(point);
+ return ret;
+}
+
+/*
+ * ECC Key validation as specified in SP800-56A R3.
+ * Section 5.6.2.1.2 Owner Assurance of Private-Key Validity
+ * The private key is in the range [1, order-1]
+ */
+int ec_key_private_check(const EC_KEY *eckey)
+{
+ if (eckey == NULL || eckey->group == NULL || eckey->priv_key == NULL) {
+ ECerr(0, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if (BN_cmp(eckey->priv_key, BN_value_one()) < 0
+ || BN_cmp(eckey->priv_key, eckey->group->order) >= 0) {
+ ECerr(0, EC_R_INVALID_PRIVATE_KEY);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * ECC Key validation as specified in SP800-56A R3.
+ * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency (b)
+ * Check if generator * priv_key = pub_key
+ */
+int ec_key_pairwise_check(const EC_KEY *eckey, BN_CTX *ctx)
+{
+ int ret = 0;
+ EC_POINT *point = NULL;
+
+ if (eckey == NULL
+ || eckey->group == NULL
+ || eckey->pub_key == NULL
+ || eckey->priv_key == NULL) {
+ ECerr(0, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ point = EC_POINT_new(eckey->group);
+ if (point == NULL)
+ goto err;
+
+
+ if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) {
+ ECerr(0, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) {
+ ECerr(0, EC_R_INVALID_PRIVATE_KEY);
+ goto err;
+ }
+ ret = 1;
+err:
+ EC_POINT_free(point);
+ return ret;
+}
+
+
+/*
+ * ECC Key validation as specified in SP800-56A R3.
+ * Section 5.6.2.3.3 ECC Full Public-Key Validation
+ * Section 5.6.2.1.2 Owner Assurance of Private-Key Validity
+ * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency
+ * NOTES:
+ * Before calling this method in fips mode, there should be an assurance that
+ * an approved elliptic-curve group is used.
+ * Returns 1 if the key is valid, otherwise it returns 0.
+ */
+int ec_key_simple_check_key(const EC_KEY *eckey)
+{
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+
+ if (eckey == NULL) {
+ ECerr(0, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ if ((ctx = BN_CTX_new_ex(eckey->libctx)) == NULL)
+ return 0;
+
+ if (!ec_key_public_check(eckey, ctx))
+ goto err;
+
+ if (eckey->priv_key != NULL) {
+ if (!ec_key_private_check(eckey)
+ || !ec_key_pairwise_check(eckey, ctx))
+ goto err;
+ }
+ ok = 1;
+err:
+ BN_CTX_free(ctx);
+ return ok;
+}
+
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
+ BIGNUM *y)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *tx, *ty;
+ EC_POINT *point = NULL;
+ int ok = 0;
+
+ if (key == NULL || key->group == NULL || x == NULL || y == NULL) {
+ ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ ctx = BN_CTX_new_ex(key->libctx);
+ if (ctx == NULL)
+ return 0;
+
+ BN_CTX_start(ctx);
+ point = EC_POINT_new(key->group);
+
+ if (point == NULL)
+ goto err;
+
+ tx = BN_CTX_get(ctx);
+ ty = BN_CTX_get(ctx);
+ if (ty == NULL)
+ goto err;
+
+ if (!EC_POINT_set_affine_coordinates(key->group, point, x, y, ctx))
+ goto err;
+ if (!EC_POINT_get_affine_coordinates(key->group, point, tx, ty, ctx))
+ goto err;
+
+ /*
+ * Check if retrieved coordinates match originals. The range check is done
+ * inside EC_KEY_check_key().
+ */
+ if (BN_cmp(x, tx) || BN_cmp(y, ty)) {
+ ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES,
+ EC_R_COORDINATES_OUT_OF_RANGE);
+ goto err;
+ }
+
+ /* EC_KEY_set_public_key updates dirty_cnt */
+ if (!EC_KEY_set_public_key(key, point))
+ goto err;
+
+ if (EC_KEY_check_key(key) == 0)
+ goto err;
+
+ ok = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ EC_POINT_free(point);
+ return ok;
+
+}
+
+OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *key)
+{
+ return key->libctx;
+}
+
+const char *ec_key_get0_propq(const EC_KEY *key)
+{
+ return key->propq;
+}