PROV: Implement EC param / key generation
authorRichard Levitte <levitte@openssl.org>
Thu, 19 Mar 2020 13:02:28 +0000 (14:02 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 15 Apr 2020 09:03:59 +0000 (11:03 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/11328)

crypto/err/openssl.txt
providers/common/include/prov/providercommonerr.h
providers/common/provider_err.c
providers/implementations/keymgmt/ec_kmgmt.c

index cf6b9cd8931912ec4bd90aaa20b43b802c122fbf..12826beb0b683ff20d0004aee90b5f986b8a1d46 100644 (file)
@@ -2819,6 +2819,7 @@ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE:165:\
 PROV_R_INAVLID_UKM_LENGTH:146:inavlid ukm length
 PROV_R_INVALID_AAD:108:invalid aad
 PROV_R_INVALID_CONSTANT_LENGTH:157:invalid constant length
+PROV_R_INVALID_CURVE:176:invalid curve
 PROV_R_INVALID_CUSTOM_LENGTH:111:invalid custom length
 PROV_R_INVALID_DATA:115:invalid data
 PROV_R_INVALID_DIGEST:122:invalid digest
@@ -2858,6 +2859,7 @@ PROV_R_MISSING_XCGHASH:135:missing xcghash
 PROV_R_NOT_SUPPORTED:136:not supported
 PROV_R_NOT_XOF_OR_INVALID_LENGTH:113:not xof or invalid length
 PROV_R_NO_KEY_SET:114:no key set
+PROV_R_NO_PARAMETERS_SET:177:no parameters set
 PROV_R_OUTPUT_BUFFER_TOO_SMALL:106:output buffer too small
 PROV_R_PSS_SALTLEN_TOO_SMALL:172:pss saltlen too small
 PROV_R_READ_KEY:159:read key
index f834a713474e01717a93164a130a85bb7db46b12..5b3bcbb6a0545fa172f73c18f816126c8f11a260 100644 (file)
@@ -69,6 +69,7 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_INAVLID_UKM_LENGTH                        146
 # define PROV_R_INVALID_AAD                               108
 # define PROV_R_INVALID_CONSTANT_LENGTH                   157
+# define PROV_R_INVALID_CURVE                             176
 # define PROV_R_INVALID_CUSTOM_LENGTH                     111
 # define PROV_R_INVALID_DATA                              115
 # define PROV_R_INVALID_DIGEST                            122
@@ -108,6 +109,7 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_NOT_SUPPORTED                             136
 # define PROV_R_NOT_XOF_OR_INVALID_LENGTH                 113
 # define PROV_R_NO_KEY_SET                                114
+# define PROV_R_NO_PARAMETERS_SET                         177
 # define PROV_R_OUTPUT_BUFFER_TOO_SMALL                   106
 # define PROV_R_PSS_SALTLEN_TOO_SMALL                     172
 # define PROV_R_READ_KEY                                  159
index 1a65e2cc870bd7b2c4cdd7c40245b33138800cf3..1018fa31ea0e05222f10e4e82c0a3362fa4d8a2e 100644 (file)
@@ -47,6 +47,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_AAD), "invalid aad"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CONSTANT_LENGTH),
     "invalid constant length"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CURVE), "invalid curve"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CUSTOM_LENGTH),
     "invalid custom length"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DATA), "invalid data"},
@@ -99,6 +100,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NOT_XOF_OR_INVALID_LENGTH),
     "not xof or invalid length"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_KEY_SET), "no key set"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_PARAMETERS_SET), "no parameters set"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_OUTPUT_BUFFER_TOO_SMALL),
     "output buffer too small"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_PSS_SALTLEN_TOO_SMALL),
index 661aa2de9fc7f5824f7c98d38334b3da3ca33eeb..0e310ecbae3612539981821fde5bc0040605db4a 100644 (file)
 #include <openssl/core_numbers.h>
 #include <openssl/core_names.h>
 #include <openssl/bn.h>
+#include <openssl/err.h>
 #include <openssl/objects.h>
 #include "crypto/bn.h"
 #include "crypto/ec.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
+#include "prov/providercommonerr.h"
 #include "prov/provider_ctx.h"
 #include "internal/param_build_set.h"
 
 static OSSL_OP_keymgmt_new_fn ec_newdata;
+static OSSL_OP_keymgmt_gen_init_fn ec_gen_init;
+static OSSL_OP_keymgmt_gen_set_template_fn ec_gen_set_template;
+static OSSL_OP_keymgmt_gen_set_params_fn ec_gen_set_params;
+static OSSL_OP_keymgmt_gen_settable_params_fn ec_gen_settable_params;
+static OSSL_OP_keymgmt_gen_get_params_fn ec_gen_get_params;
+static OSSL_OP_keymgmt_gen_gettable_params_fn ec_gen_gettable_params;
+static OSSL_OP_keymgmt_gen_fn ec_gen;
+static OSSL_OP_keymgmt_gen_cleanup_fn ec_gen_cleanup;
 static OSSL_OP_keymgmt_free_fn ec_freedata;
 static OSSL_OP_keymgmt_get_params_fn ec_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn ec_gettable_params;
@@ -558,8 +568,195 @@ int ec_validate(void *keydata, int selection)
     return ok;
 }
 
+struct ec_gen_ctx {
+    OPENSSL_CTX *libctx;
+
+    EC_GROUP *gen_group;
+    int selection;
+};
+
+static void *ec_gen_init(void *provctx, int selection)
+{
+    OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    struct ec_gen_ctx *gctx = NULL;
+
+    if ((selection & (EC_POSSIBLE_SELECTIONS)) == 0)
+        return NULL;
+
+    if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
+        gctx->libctx = libctx;
+        gctx->gen_group = NULL;
+        gctx->selection = selection;
+    }
+    return gctx;
+}
+
+static int ec_gen_set_group(void *genctx, int nid)
+{
+    struct ec_gen_ctx *gctx = genctx;
+    EC_GROUP *group;
+
+    group = EC_GROUP_new_by_curve_name_ex(gctx->libctx, nid);
+    if (group == NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE);
+        return 0;
+    }
+    EC_GROUP_free(gctx->gen_group);
+    gctx->gen_group = group;
+    return 1;
+}
+static int ec_gen_set_template(void *genctx, void *templ)
+{
+    struct ec_gen_ctx *gctx = genctx;
+    EC_KEY *ec = templ;
+    const EC_GROUP *ec_group;
+
+    if (gctx == NULL || ec == NULL)
+        return 0;
+    if ((ec_group = EC_KEY_get0_group(ec)) == NULL)
+        return 0;
+    return ec_gen_set_group(gctx, EC_GROUP_get_curve_name(ec_group));
+}
+
+static int ec_gen_set_params(void *genctx, const OSSL_PARAM params[])
+{
+    struct ec_gen_ctx *gctx = genctx;
+    const OSSL_PARAM *p;
+
+    if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_NAME))
+        != NULL) {
+        const char *curve_name = NULL;
+        int ret = 0;
+
+        switch (p->data_type) {
+        case OSSL_PARAM_UTF8_STRING:
+            /* The OSSL_PARAM functions have no support for this */
+            curve_name = p->data;
+            ret = (curve_name != NULL);
+            break;
+        case OSSL_PARAM_UTF8_PTR:
+            ret = OSSL_PARAM_get_utf8_ptr(p, &curve_name);
+            break;
+        }
+
+        if (ret) {
+            int nid = ec_curve_name2nid(curve_name);
+
+            if (nid == NID_undef) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CURVE);
+                ret = 0;
+            } else {
+                ret = ec_gen_set_group(gctx, nid);
+            }
+        }
+        return ret;
+    }
+    return 1;
+}
+
+static const OSSL_PARAM *ec_gen_settable_params(void *provctx)
+{
+    static OSSL_PARAM settable[] = {
+        { OSSL_PKEY_PARAM_EC_NAME, OSSL_PARAM_UTF8_STRING, NULL, 0, 0 },
+        OSSL_PARAM_END
+    };
+
+    return settable;
+}
+
+static int ec_gen_get_params(void *genctx, OSSL_PARAM params[])
+{
+    struct ec_gen_ctx *gctx = genctx;
+    OSSL_PARAM *p;
+
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_NAME)) != NULL) {
+        int nid = EC_GROUP_get_curve_name(gctx->gen_group);
+        int ret = 0;
+        const char *curve_name = ec_curve_nid2name(nid);
+
+        switch (p->data_type) {
+        case OSSL_PARAM_UTF8_STRING:
+            ret = OSSL_PARAM_set_utf8_string(p, curve_name);
+            break;
+        case OSSL_PARAM_UTF8_PTR:
+            ret = OSSL_PARAM_set_utf8_ptr(p, curve_name);
+            break;
+        }
+        return ret;
+    }
+    return 1;
+}
+
+static const OSSL_PARAM *ec_gen_gettable_params(void *provctx)
+{
+    static OSSL_PARAM gettable[] = {
+        { OSSL_PKEY_PARAM_EC_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0, 0 },
+        OSSL_PARAM_END
+    };
+
+    return gettable;
+}
+
+static int ec_gen_assign_group(EC_KEY *ec, EC_GROUP *group)
+{
+    if (group == NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_NO_PARAMETERS_SET);
+        return 0;
+    }
+    return EC_KEY_set_group(ec, group) > 0;
+}
+
+/*
+ * The callback arguments (osslcb & cbarg) are not used by EC_KEY generation
+ */
+static void *ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct ec_gen_ctx *gctx = genctx;
+    EC_KEY *ec = NULL;
+    int ret = 1;                 /* Start optimistically */
+
+    if (gctx == NULL
+        || (ec = EC_KEY_new_ex(gctx->libctx)) == NULL)
+        return NULL;
+
+    /* We must always assign a group, no matter what */
+    ret = ec_gen_assign_group(ec, gctx->gen_group);
+    /* Whether you want it or not, you get a keypair, not just one half */
+    if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+        ret = ret && EC_KEY_generate_key(ec);
+
+    if (ret)
+        return ec;
+
+    /* Something went wrong, throw the key away */
+    EC_KEY_free(ec);
+    return NULL;
+}
+
+static void ec_gen_cleanup(void *genctx)
+{
+    struct ec_gen_ctx *gctx = genctx;
+
+    if (gctx == NULL)
+        return;
+
+    EC_GROUP_free(gctx->gen_group);
+    OPENSSL_free(gctx);
+}
+
 const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))ec_newdata },
+    { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))ec_gen_init },
+    { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE,
+      (void (*)(void))ec_gen_set_template },
+    { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ec_gen_set_params },
+    { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS,
+      (void (*)(void))ec_gen_settable_params },
+    { OSSL_FUNC_KEYMGMT_GEN_GET_PARAMS, (void (*)(void))ec_gen_get_params },
+    { OSSL_FUNC_KEYMGMT_GEN_GETTABLE_PARAMS,
+      (void (*)(void))ec_gen_gettable_params },
+    { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))ec_gen },
+    { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ec_gen_cleanup },
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ec_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))ec_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ec_gettable_params },
@@ -573,6 +770,6 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },
     { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ec_export_types },
     { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME,
-        (void (*)(void))ec_query_operation_name },
+      (void (*)(void))ec_query_operation_name },
     { 0, NULL }
 };