EC_KEY: add EC_KEY_decoded_from_explicit_params()
authorTomas Mraz <tmraz@fedoraproject.org>
Fri, 21 Aug 2020 12:50:52 +0000 (14:50 +0200)
committerTomas Mraz <tmraz@fedoraproject.org>
Thu, 17 Sep 2020 15:15:15 +0000 (17:15 +0200)
The function returns 1 when the encoding of a decoded EC key used
explicit encoding of the curve parameters.

Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/12683)

crypto/ec/ec_asn1.c
crypto/ec/ec_key.c
crypto/ec/ec_lib.c
crypto/ec/ec_local.h
doc/man3/EC_KEY_new.pod
include/openssl/ec.h
test/ec_internal_test.c
util/libcrypto.num

index 879ff9faa223620cd79def8f5039cce6029eb44f..9454f580d5357d4273fc47fc48d9d7a648c86da9 100644 (file)
@@ -74,6 +74,12 @@ struct ec_parameters_st {
     ASN1_INTEGER *cofactor;
 } /* ECPARAMETERS */ ;
 
+typedef enum {
+    ECPKPARAMETERS_TYPE_NAMED = 0,
+    ECPKPARAMETERS_TYPE_EXPLICIT,
+    ECPKPARAMETERS_TYPE_IMPLICIT
+} ecpk_parameters_type_t;
+
 struct ecpk_parameters_st {
     int type;
     union {
@@ -472,9 +478,10 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group,
             return NULL;
         }
     } else {
-        if (ret->type == 0)
+        if (ret->type == ECPKPARAMETERS_TYPE_NAMED)
             ASN1_OBJECT_free(ret->value.named_curve);
-        else if (ret->type == 1 && ret->value.parameters)
+        else if (ret->type == ECPKPARAMETERS_TYPE_EXPLICIT
+                 && ret->value.parameters != NULL)
             ECPARAMETERS_free(ret->value.parameters);
     }
 
@@ -491,7 +498,7 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group,
                 ECerr(EC_F_EC_GROUP_GET_ECPKPARAMETERS, EC_R_MISSING_OID);
                 ok = 0;
             } else {
-                ret->type = 0;
+                ret->type = ECPKPARAMETERS_TYPE_NAMED;
                 ret->value.named_curve = asn1obj;
             }
         } else
@@ -499,7 +506,7 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group,
             ok = 0;
     } else {
         /* use the ECPARAMETERS structure */
-        ret->type = 1;
+        ret->type = ECPKPARAMETERS_TYPE_EXPLICIT;
         if ((ret->value.parameters =
              EC_GROUP_get_ecparameters(group, NULL)) == NULL)
             ok = 0;
@@ -841,7 +848,8 @@ EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params)
         return NULL;
     }
 
-    if (params->type == 0) {    /* the curve is given by an OID */
+    if (params->type == ECPKPARAMETERS_TYPE_NAMED) {
+        /* the curve is given by an OID */
         tmp = OBJ_obj2nid(params->value.named_curve);
         if ((ret = EC_GROUP_new_by_curve_name(tmp)) == NULL) {
             ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS,
@@ -849,15 +857,16 @@ EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params)
             return NULL;
         }
         EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_NAMED_CURVE);
-    } else if (params->type == 1) { /* the parameters are given by a
-                                     * ECPARAMETERS structure */
+    } else if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT) {
+        /* the parameters are given by an ECPARAMETERS structure */
         ret = EC_GROUP_new_from_ecparameters(params->value.parameters);
         if (!ret) {
             ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, ERR_R_EC_LIB);
             return NULL;
         }
         EC_GROUP_set_asn1_flag(ret, OPENSSL_EC_EXPLICIT_CURVE);
-    } else if (params->type == 2) { /* implicitlyCA */
+    } else if (params->type == ECPKPARAMETERS_TYPE_IMPLICIT) {
+        /* implicit parameters inherited from CA - unsupported */
         return NULL;
     } else {
         ECerr(EC_F_EC_GROUP_NEW_FROM_ECPKPARAMETERS, EC_R_ASN1_ERROR);
@@ -887,6 +896,9 @@ EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
         return NULL;
     }
 
+    if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT)
+        group->decoded_from_explicit_params = 1;
+
     if (a) {
         EC_GROUP_free(*a);
         *a = group;
@@ -938,6 +950,9 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
     if (priv_key->parameters) {
         EC_GROUP_free(ret->group);
         ret->group = EC_GROUP_new_from_ecpkparameters(priv_key->parameters);
+        if (ret->group != NULL
+            && priv_key->parameters->type == ECPKPARAMETERS_TYPE_EXPLICIT)
+            ret->group->decoded_from_explicit_params = 1;
     }
 
     if (ret->group == NULL) {
index 84e1b96c480762bf26a48ad1bdbd0fa828b5c976..f1f325237eb6d50d7c714d1be6fda3932dfb98b8 100644 (file)
@@ -822,6 +822,13 @@ void EC_KEY_clear_flags(EC_KEY *key, int flags)
     key->dirty_cnt++;
 }
 
+int EC_KEY_decoded_from_explicit_params(const EC_KEY *key)
+{
+    if (key == NULL || key->group == NULL)
+        return -1;
+    return key->group->decoded_from_explicit_params;
+}
+
 size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
                         unsigned char **pbuf, BN_CTX *ctx)
 {
index d7752e953f66a0d17f2c4a94829d6722deb6564c..222df5563214cee05669508d88c3e380aec160d5 100644 (file)
@@ -243,6 +243,7 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
 
     dest->asn1_flag = src->asn1_flag;
     dest->asn1_form = src->asn1_form;
+    dest->decoded_from_explicit_params = src->decoded_from_explicit_params;
 
     if (src->seed) {
         OPENSSL_free(dest->seed);
index aa040b54d105994130ce695f7b58d789a191bb77..11fab6b985a46bf4e12a78727c142b2f75c2b96b 100644 (file)
@@ -213,6 +213,8 @@ struct ec_group_st {
     BIGNUM *order, *cofactor;
     int curve_name;             /* optional NID for named curve */
     int asn1_flag;              /* flag to control the asn1 encoding */
+    int decoded_from_explicit_params; /* set if decoded from explicit
+                                       * curve parameters encoding */
     point_conversion_form_t asn1_form;
     unsigned char *seed;        /* optional seed for parameters (appears in
                                  * ASN1) */
index a907435153097b145fefc3baeed571749a8e7f65..c3e90a247495f1bb51ee797269583c58ab4e01d5 100644 (file)
@@ -9,7 +9,8 @@ EC_KEY_copy, EC_KEY_dup, EC_KEY_up_ref, EC_KEY_get0_engine,
 EC_KEY_get0_group, EC_KEY_set_group, EC_KEY_get0_private_key,
 EC_KEY_set_private_key, EC_KEY_get0_public_key, EC_KEY_set_public_key,
 EC_KEY_get_conv_form,
-EC_KEY_set_conv_form, EC_KEY_set_asn1_flag, EC_KEY_precompute_mult,
+EC_KEY_set_conv_form, EC_KEY_set_asn1_flag,
+EC_KEY_decoded_from_explicit_params, EC_KEY_precompute_mult,
 EC_KEY_generate_key, EC_KEY_check_key, EC_KEY_set_public_key_affine_coordinates,
 EC_KEY_oct2key, EC_KEY_key2buf, EC_KEY_oct2priv, EC_KEY_priv2oct,
 EC_KEY_priv2buf - Functions for creating, destroying and manipulating
@@ -41,6 +42,7 @@ EC_KEY objects
  point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
  void EC_KEY_set_conv_form(EC_KEY *eckey, point_conversion_form_t cform);
  void EC_KEY_set_asn1_flag(EC_KEY *eckey, int asn1_flag);
+ int EC_KEY_decoded_from_explicit_params(const EC_KEY *key);
  int EC_KEY_generate_key(EC_KEY *key);
  int EC_KEY_check_key(const EC_KEY *key);
  int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y);
@@ -142,6 +144,10 @@ EC_KEY_set_asn1_flag() sets the asn1_flag on the underlying EC_GROUP object
 (if set). Refer to L<EC_GROUP_copy(3)> for further information on the
 asn1_flag.
 
+EC_KEY_decoded_from_explicit_params() returns 1 if the group of the I<key> was
+decoded from data with explicitly encoded group parameters, -1 if the I<key>
+is NULL or the group parameters are missing, and 0 otherwise.
+
 Although deprecated in OpenSSL 3.0 and should no longer be used,
 EC_KEY_precompute_mult() stores multiples of the underlying EC_GROUP generator
 for faster point multiplication. See also L<EC_POINT_add(3)>.
index aca52e6923ea3cc4826740cf665690249cc6dc26..ed83e3bcb0a7cb11bb49686000b6ab40e7edbc58 100644 (file)
@@ -896,6 +896,8 @@ void EC_KEY_set_flags(EC_KEY *key, int flags);
 
 void EC_KEY_clear_flags(EC_KEY *key, int flags);
 
+int EC_KEY_decoded_from_explicit_params(const EC_KEY *key);
+
 /**
  *  Creates a new EC_KEY object using a named curve as underlying
  *  EC_GROUP object.
index 38a6ab5b4af3b2128d86cd295c29a463c837e1d1..d3db698467a7c81b2deb70340c6ac28b557e17b4 100644 (file)
@@ -259,6 +259,106 @@ static int underflow_test(void)
 }
 #endif
 
+/*
+ * Tests behavior of the decoded_from_explicit_params flag and API
+ */
+static int decoded_flag_test(void)
+{
+    EC_GROUP *grp;
+    EC_GROUP *grp_copy = NULL;
+    ECPARAMETERS *ecparams = NULL;
+    ECPKPARAMETERS *ecpkparams = NULL;
+    EC_KEY *key = NULL;
+    unsigned char *encodedparams = NULL;
+    const unsigned char *encp;
+    int encodedlen;
+    int testresult = 0;
+
+    /* Test EC_GROUP_new not setting the flag */
+    grp = EC_GROUP_new(EC_GFp_simple_method());
+    if (!TEST_ptr(grp)
+        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
+        goto err;
+    EC_GROUP_free(grp);
+
+    /* Test EC_GROUP_new_by_curve_name not setting the flag */
+    grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+    if (!TEST_ptr(grp)
+        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
+        goto err;
+
+    /* Test EC_GROUP_new_from_ecparameters not setting the flag */
+    if (!TEST_ptr(ecparams = EC_GROUP_get_ecparameters(grp, NULL))
+        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecparameters(ecparams))
+        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
+        goto err;
+    EC_GROUP_free(grp_copy);
+    grp_copy = NULL;
+    ECPARAMETERS_free(ecparams);
+    ecparams = NULL;
+
+    /* Test EC_GROUP_new_from_ecpkparameters not setting the flag */
+    if (!TEST_int_eq(EC_GROUP_get_asn1_flag(grp), OPENSSL_EC_NAMED_CURVE)
+        || !TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
+        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
+        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)
+        || !TEST_ptr(key = EC_KEY_new())
+    /* Test EC_KEY_decoded_from_explicit_params on key without a group */
+        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), -1)
+        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
+    /* Test EC_KEY_decoded_from_explicit_params negative case */
+        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 0))
+        goto err;
+    EC_GROUP_free(grp_copy);
+    grp_copy = NULL;
+    ECPKPARAMETERS_free(ecpkparams);
+    ecpkparams = NULL;
+
+    /* Test d2i_ECPKParameters with named params not setting the flag */
+    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
+        || !TEST_ptr(encp = encodedparams)
+        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
+        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
+        goto err;
+    EC_GROUP_free(grp_copy);
+    grp_copy = NULL;
+    OPENSSL_free(encodedparams);
+    encodedparams = NULL;
+
+    /* Asn1 flag stays set to explicit with EC_GROUP_new_from_ecpkparameters */
+    EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE);
+    if (!TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
+        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
+        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
+        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
+        goto err;
+    EC_GROUP_free(grp_copy);
+    grp_copy = NULL;
+
+    /* Test d2i_ECPKParameters with explicit params setting the flag */
+    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
+        || !TEST_ptr(encp = encodedparams)
+        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
+        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
+        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 1)
+        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
+    /* Test EC_KEY_decoded_from_explicit_params positive case */
+        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 1))
+        goto err;
+
+    testresult = 1;
+
+ err:
+    EC_KEY_free(key);
+    EC_GROUP_free(grp);
+    EC_GROUP_free(grp_copy);
+    ECPARAMETERS_free(ecparams);
+    ECPKPARAMETERS_free(ecpkparams);
+    OPENSSL_free(encodedparams);
+
+    return testresult;
+}
+
 int setup_tests(void)
 {
     crv_len = EC_get_builtin_curves(NULL, 0);
@@ -275,6 +375,7 @@ int setup_tests(void)
 #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
     ADD_TEST(underflow_test);
 #endif
+    ADD_TEST(decoded_flag_test);
     return 1;
 }
 
index a1b8ce0be12dda0e9c902249b03e15161610cbca..e9f6e5669095e07b3751f358257c93d5493dae0b 100644 (file)
@@ -5282,3 +5282,4 @@ CMS_AuthEnvelopedData_create_with_libctx ?        3_0_0   EXIST::FUNCTION:CMS
 EVP_PKEY_CTX_set_ec_param_enc           ?      3_0_0   EXIST::FUNCTION:EC
 EVP_PKEY_get0_first_alg_name            ?      3_0_0   EXIST::FUNCTION:
 EVP_KEYMGMT_get0_first_name             ?      3_0_0   EXIST::FUNCTION:
+EC_KEY_decoded_from_explicit_params     ?      3_0_0   EXIST::FUNCTION:EC