Extended EC_METHOD customisation support.
authorDr. Stephen Henson <steve@openssl.org>
Mon, 1 Feb 2016 18:15:57 +0000 (18:15 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 28 Feb 2016 22:54:53 +0000 (22:54 +0000)
Add support for optional overrides of various private key operations
in EC_METHOD.

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Emilia Käsper <emilia@openssl.org>
crypto/ec/ec_asn1.c
crypto/ec/ec_check.c
crypto/ec/ec_curve.c
crypto/ec/ec_key.c
crypto/ec/ec_lib.c
crypto/ec/ecdh_ossl.c

index d56e6cdc2e1facc1a2b4531cd82fbccca717cf48..f033613993f3abf680aef64aac156fa54c8a4ffd 100644 (file)
@@ -342,7 +342,7 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
             ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
             goto err;
         }
             ECerr(EC_F_EC_ASN1_GROUP2FIELDID, ERR_R_ASN1_LIB);
             goto err;
         }
-    } else                      /* nid == NID_X9_62_characteristic_two_field */
+    } else if (nid == NID_X9_62_characteristic_two_field)
 #ifdef OPENSSL_NO_EC2M
     {
         ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
 #ifdef OPENSSL_NO_EC2M
     {
         ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_GF2M_NOT_SUPPORTED);
@@ -417,6 +417,10 @@ static int ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field)
         }
     }
 #endif
         }
     }
 #endif
+    else {
+        ECerr(EC_F_EC_ASN1_GROUP2FIELDID, EC_R_UNSUPPORTED_FIELD);
+        goto err;
+    }
 
     ok = 1;
 
 
     ok = 1;
 
@@ -1050,9 +1054,11 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
             goto err;
         }
     } else {
             goto err;
         }
     } else {
-        if (!EC_POINT_mul
-            (ret->group, ret->pub_key, ret->priv_key, NULL, NULL, NULL)) {
-            ECerr(EC_F_D2I_ECPRIVATEKEY, ERR_R_EC_LIB);
+        if (ret->group->meth->keygenpub != NULL) {
+            if (ret->group->meth->keygenpub(ret) == 0)
+                goto err;
+        } else if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL,
+                                 NULL, NULL)) {
             goto err;
         }
         /* Remember the original private-key-only encoding. */
             goto err;
         }
         /* Remember the original private-key-only encoding. */
index aa3532235577118dc3147e824a0ceea48ccdaec3..601559f4c488c5e3e0d353561df177b9fa0585a9 100644 (file)
@@ -62,6 +62,10 @@ int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx)
     BN_CTX *new_ctx = NULL;
     EC_POINT *point = NULL;
 
     BN_CTX *new_ctx = NULL;
     EC_POINT *point = NULL;
 
+    /* Custom curves assumed to be correct */
+    if ((group->meth->flags & EC_FLAGS_CUSTOM_CURVE) != 0)
+        return 1;
+
     if (ctx == NULL) {
         ctx = new_ctx = BN_CTX_new();
         if (ctx == NULL) {
     if (ctx == NULL) {
         ctx = new_ctx = BN_CTX_new();
         if (ctx == NULL) {
index 107beb5fb319646fe197f7235c2649b67e77341a..befe59d2bcde55d7853045a19348d35284658489 100644 (file)
@@ -3037,6 +3037,10 @@ static EC_GROUP *ec_group_new_from_data(const ec_list_element curve)
     const EC_CURVE_DATA *data;
     const unsigned char *params;
 
     const EC_CURVE_DATA *data;
     const unsigned char *params;
 
+    /* If no curve data curve method must handle everything */
+    if (curve.data == NULL)
+        return EC_GROUP_new(curve.meth != NULL ? curve.meth() : NULL);
+
     if ((ctx = BN_CTX_new()) == NULL) {
         ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE);
         goto err;
     if ((ctx = BN_CTX_new()) == NULL) {
         ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE);
         goto err;
index c382e7e41e5f8d92478b55f07f58dbd835365661..e48852365457fd738d2aa39dfe019812a20b9d8e 100644 (file)
@@ -111,6 +111,9 @@ void EC_KEY_free(EC_KEY *r)
     ENGINE_finish(r->engine);
 #endif
 
     ENGINE_finish(r->engine);
 #endif
 
+    if (r->group && r->group->meth->keyfinish)
+        r->group->meth->keyfinish(r);
+
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data);
     EC_GROUP_free(r->group);
     EC_POINT_free(r->pub_key);
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data);
     EC_GROUP_free(r->group);
     EC_POINT_free(r->pub_key);
@@ -128,6 +131,8 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, EC_KEY *src)
     if (src->meth != dest->meth) {
         if (dest->meth->finish != NULL)
             dest->meth->finish(dest);
     if (src->meth != dest->meth) {
         if (dest->meth->finish != NULL)
             dest->meth->finish(dest);
+        if (dest->group && dest->group->meth->keyfinish)
+            dest->group->meth->keyfinish(dest);
 #ifndef OPENSSL_NO_ENGINE
         if (ENGINE_finish(dest->engine) == 0)
             return 0;
 #ifndef OPENSSL_NO_ENGINE
         if (ENGINE_finish(dest->engine) == 0)
             return 0;
@@ -163,8 +168,12 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, EC_KEY *src)
         }
         if (!BN_copy(dest->priv_key, src->priv_key))
             return NULL;
         }
         if (!BN_copy(dest->priv_key, src->priv_key))
             return NULL;
+        if (src->group->meth->keycopy
+            && src->group->meth->keycopy(dest, src) == 0)
+            return NULL;
     }
 
     }
 
+
     /* copy the rest */
     dest->enc_flag = src->enc_flag;
     dest->conv_form = src->conv_form;
     /* copy the rest */
     dest->enc_flag = src->enc_flag;
     dest->conv_form = src->conv_form;
@@ -231,6 +240,9 @@ int ossl_ec_key_gen(EC_KEY *eckey)
     const BIGNUM *order = NULL;
     EC_POINT *pub_key = NULL;
 
     const BIGNUM *order = NULL;
     EC_POINT *pub_key = NULL;
 
+    if (eckey->group->meth->keygen != NULL)
+        return eckey->group->meth->keygen(eckey);
+
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
 
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
 
@@ -286,6 +298,9 @@ int EC_KEY_check_key(const EC_KEY *eckey)
         return 0;
     }
 
         return 0;
     }
 
+    if (eckey->group->meth->keycheck)
+        return eckey->group->meth->keycheck(eckey);
+
     if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
         ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_AT_INFINITY);
         goto err;
     if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
         ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_AT_INFINITY);
         goto err;
@@ -442,6 +457,11 @@ const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key)
 
 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
 {
 
 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
 {
+    if (key->group == NULL || key->group->meth == NULL)
+        return 0;
+    if (key->group->meth->set_private
+        && key->meth->set_private(key, priv_key) == 0)
+        return 0;
     if (key->meth->set_private != NULL
         && key->meth->set_private(key, priv_key) == 0)
         return 0;
     if (key->meth->set_private != NULL
         && key->meth->set_private(key, priv_key) == 0)
         return 0;
@@ -540,6 +560,8 @@ size_t EC_KEY_priv2oct(const EC_KEY *eckey, unsigned char *buf, size_t len)
     size_t buf_len;
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
     size_t buf_len;
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
+    if (eckey->group->meth->priv2oct)
+        return eckey->group->meth->priv2oct(eckey, buf, len);
 
     buf_len = (EC_GROUP_get_degree(eckey->group) + 7) / 8;
     if (eckey->priv_key == NULL)
 
     buf_len = (EC_GROUP_get_degree(eckey->group) + 7) / 8;
     if (eckey->priv_key == NULL)
@@ -563,6 +585,8 @@ int EC_KEY_oct2priv(EC_KEY *eckey, unsigned char *buf, size_t len)
 {
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
 {
     if (eckey->group == NULL || eckey->group->meth == NULL)
         return 0;
+    if (eckey->group->meth->oct2priv)
+        return eckey->group->meth->oct2priv(eckey, buf, len);
 
     if (eckey->priv_key == NULL)
         eckey->priv_key = BN_secure_new();
 
     if (eckey->priv_key == NULL)
         eckey->priv_key = BN_secure_new();
index a34113c95342d367f4729e7d0ab65026262e09d8..b7bbc41cdf924d45e7b527af2741b55a72ca10d7 100644 (file)
@@ -89,12 +89,14 @@ EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
     }
 
     ret->meth = meth;
     }
 
     ret->meth = meth;
-    ret->order = BN_new();
-    if (ret->order == NULL)
-        goto err;
-    ret->cofactor = BN_new();
-    if (ret->cofactor == NULL)
-        goto err;
+    if ((ret->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
+        ret->order = BN_new();
+        if (ret->order == NULL)
+            goto err;
+        ret->cofactor = BN_new();
+        if (ret->cofactor == NULL)
+            goto err;
+    }
     ret->asn1_flag = OPENSSL_EC_NAMED_CURVE;
     ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
     if (!meth->group_init(ret))
     ret->asn1_flag = OPENSSL_EC_NAMED_CURVE;
     ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
     if (!meth->group_init(ret))
@@ -240,10 +242,12 @@ int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
         dest->generator = NULL;
     }
 
         dest->generator = NULL;
     }
 
-    if (!BN_copy(dest->order, src->order))
-        return 0;
-    if (!BN_copy(dest->cofactor, src->cofactor))
-        return 0;
+    if ((src->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) {
+        if (!BN_copy(dest->order, src->order))
+            return 0;
+        if (!BN_copy(dest->cofactor, src->cofactor))
+            return 0;
+    }
 
     dest->curve_name = src->curve_name;
     dest->asn1_flag = src->asn1_flag;
 
     dest->curve_name = src->curve_name;
     dest->asn1_flag = src->asn1_flag;
@@ -527,6 +531,8 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ctx)
     if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) &&
         EC_GROUP_get_curve_name(a) != EC_GROUP_get_curve_name(b))
         return 1;
     if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) &&
         EC_GROUP_get_curve_name(a) != EC_GROUP_get_curve_name(b))
         return 1;
+    if (a->meth->flags & EC_FLAGS_CUSTOM_CURVE)
+        return 0;
 
     if (ctx == NULL)
         ctx_new = ctx = BN_CTX_new();
 
     if (ctx == NULL)
         ctx_new = ctx = BN_CTX_new();
index 15a179fbc67a48d8ec06f1b36cf44a1d6e08f36a..fadc007e14d5bef6ad900bbd365fec2558a917b2 100644 (file)
@@ -103,6 +103,10 @@ int ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
         return -1;
     }
 
         return -1;
     }
 
+    if (ecdh->group->meth->ecdh_compute_key != 0)
+        return ecdh->group->meth->ecdh_compute_key(out, outlen, pub_key, ecdh,
+                                                   KDF);
+
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
     BN_CTX_start(ctx);
     if ((ctx = BN_CTX_new()) == NULL)
         goto err;
     BN_CTX_start(ctx);