Add EC key validation to default provider
authorShane Lontis <shane.lontis@oracle.com>
Thu, 16 Jan 2020 07:18:26 +0000 (17:18 +1000)
committerShane Lontis <shane.lontis@oracle.com>
Wed, 11 Mar 2020 21:14:32 +0000 (07:14 +1000)
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10861)

crypto/ec/ec_check.c
crypto/ec/ec_key.c
crypto/ec/ec_lib.c
include/crypto/ec.h
providers/implementations/keymgmt/ec_kmgmt.c

index bb39177d644bc384a71e637f18f51096a7c8ba30..1283d8404f699849485446bbf4f21e66d52ea2c5 100644 (file)
@@ -20,26 +20,27 @@ int EC_GROUP_check_named_curve(const EC_GROUP *group, int nist_only,
                                BN_CTX *ctx)
 {
     int nid = NID_undef;
-#ifndef FIPS_MODE
     BN_CTX *new_ctx = NULL;
 
+    if (group == NULL) {
+        ECerr(0, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+
     if (ctx == NULL) {
-        ctx = new_ctx = BN_CTX_new();
+        ctx = new_ctx = BN_CTX_new_ex(NULL);
         if (ctx == NULL) {
-            ECerr(EC_F_EC_GROUP_CHECK_NAMED_CURVE, ERR_R_MALLOC_FAILURE);
-            goto err;
+            ECerr(0, ERR_R_MALLOC_FAILURE);
+            return NID_undef;
         }
     }
-#endif
 
     nid = ec_curve_nid_from_params(group, ctx);
     if (nid > 0 && nist_only && EC_curve_nid2nist(nid) == NULL)
         nid = NID_undef;
 
-#ifndef FIPS_MODE
- err:
-    BN_CTX_free(ctx);
-#endif
+err:
+    BN_CTX_free(new_ctx);
     return nid;
 }
 
index 18b544b9d336dad32ae747db7bf9614eb5a2b7a6..ae3e9742314b7765126d45b26e3e9e5b3136991a 100644 (file)
@@ -419,93 +419,151 @@ err:
 
 /*
  * 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.
+ * Section 5.6.2.3.3 ECC Full Public-Key Validation.
  */
-int ec_key_simple_check_key(const EC_KEY *eckey)
+int ec_key_public_check(const EC_KEY *eckey, BN_CTX *ctx)
 {
-    int ok = 0;
-    BN_CTX *ctx = NULL;
-    const BIGNUM *order = NULL;
+    int ret = 0;
     EC_POINT *point = NULL;
+    const BIGNUM *order = NULL;
 
     if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) {
-        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER);
+        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(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_AT_INFINITY);
-        goto err;
+        ECerr(0, EC_R_POINT_AT_INFINITY);
+        return 0;
     }
 
-    if ((ctx = BN_CTX_new_ex(eckey->libctx)) == NULL)
-        goto err;
-
-    if ((point = EC_POINT_new(eckey->group)) == NULL)
-        goto err;
+    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(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_COORDINATES_OUT_OF_RANGE);
+        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(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE);
+        ECerr(0, EC_R_POINT_IS_NOT_ON_CURVE);
         goto err;
     }
 
     order = eckey->group->order;
     if (BN_is_zero(order)) {
-        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_GROUP_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(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB);
+        ECerr(0, ERR_R_EC_LIB);
         goto err;
     }
     if (!EC_POINT_is_at_infinity(eckey->group, point)) {
-        ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER);
+        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) {
-        /*
-         * 5.6.2.1.2 Owner Assurance of Private-Key Validity
-         * The private key is in the range [1, order-1]
-         */
-        if (BN_cmp(eckey->priv_key, BN_value_one()) < 0
-                || BN_cmp(eckey->priv_key, order) >= 0) {
-            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_WRONG_ORDER);
+        if (!ec_key_private_check(eckey)
+            || !ec_key_pairwise_check(eckey, ctx))
             goto err;
-        }
-        /*
-         * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency (b)
-         * Check if generator * priv_key = pub_key
-         */
-        if (!EC_POINT_mul(eckey->group, point, eckey->priv_key,
-                          NULL, NULL, ctx)) {
-            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, ERR_R_EC_LIB);
-            goto err;
-        }
-        if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) {
-            ECerr(EC_F_EC_KEY_SIMPLE_CHECK_KEY, EC_R_INVALID_PRIVATE_KEY);
-            goto err;
-        }
     }
     ok = 1;
- err:
+err:
     BN_CTX_free(ctx);
-    EC_POINT_free(point);
     return ok;
 }
 
index 078d8b35fa47c2e1c7f9c3a111b8dd4a1e1478b9..e66a501a0e111d82715f7144f84820993b9421b5 100644 (file)
@@ -1261,3 +1261,8 @@ int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx)
 
     return group->meth->blind_coordinates(group, p, ctx);
 }
+
+OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *eckey)
+{
+    return eckey->libctx;
+}
index c4f7d2e778e497e0bcc32da075cee2f7d823e4a6..9ebf45d0f49b2f89258ef22d8359445939520524 100644 (file)
@@ -50,5 +50,9 @@ int ecdh_KDF_X9_63(unsigned char *out, size_t outlen,
                    const EVP_MD *md);
 
 int ec_generate_key(OPENSSL_CTX *libctx, EC_KEY *eckey, int pairwise_test);
+int ec_key_public_check(const EC_KEY *eckey, BN_CTX *ctx);
+int ec_key_private_check(const EC_KEY *eckey);
+int ec_key_pairwise_check(const EC_KEY *eckey, BN_CTX *ctx);
+OPENSSL_CTX *ec_key_get_libctx(const EC_KEY *eckey);
 # endif /* OPENSSL_NO_EC */
 #endif
index 107ab1b594737990e0d9e41ecd0bee14c55bc304..2db23cd4894e9defd7f76667d87e8fd9c0296e39 100644 (file)
 #include <openssl/core_numbers.h>
 #include <openssl/core_names.h>
 #include <openssl/bn.h>
-#include <openssl/ec.h>
 #include <openssl/objects.h>
 #include <openssl/params.h>
 #include "crypto/bn.h"
+#include "crypto/ec.h"
 #include "internal/param_build.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
@@ -32,6 +32,7 @@ static OSSL_OP_keymgmt_set_params_fn ec_set_params;
 static OSSL_OP_keymgmt_settable_params_fn ec_settable_params;
 static OSSL_OP_keymgmt_has_fn ec_has;
 static OSSL_OP_keymgmt_match_fn ec_match;
+static OSSL_OP_keymgmt_validate_fn ec_validate;
 static OSSL_OP_keymgmt_import_fn ec_import;
 static OSSL_OP_keymgmt_import_types_fn ec_import_types;
 static OSSL_OP_keymgmt_export_fn ec_export;
@@ -730,6 +731,35 @@ int ec_set_params(void *key, const OSSL_PARAM params[])
     return 1;
 }
 
+static
+int ec_validate(void *keydata, int selection)
+{
+    EC_KEY *eck = keydata;
+    int ok = 0;
+    BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(eck));
+
+    if (ctx == NULL)
+        return 0;
+
+    if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+        ok = 1;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+        ok = ok && EC_GROUP_check(EC_KEY_get0_group(eck), ctx);
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = ok && ec_key_public_check(eck, ctx);
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ok && ec_key_private_check(eck);
+
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
+        ok = ok && ec_key_pairwise_check(eck, ctx);
+
+    BN_CTX_free(ctx);
+    return ok;
+}
+
 const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata },
@@ -739,6 +769,7 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has },
     { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match },
+    { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))ec_validate },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },