EVP: Add new domparams and key generation functionality
authorRichard Levitte <levitte@openssl.org>
Sun, 27 Oct 2019 14:09:26 +0000 (15:09 +0100)
committerRichard Levitte <levitte@openssl.org>
Thu, 12 Mar 2020 09:44:01 +0000 (10:44 +0100)
The following functions are added:

EVP_PKEY_gen_set_params(), replacing the older EVP_PKEY_CTX_ctrl()
EVP_PKEY_gen(), replacing both EVP_PKEY_keygen() and EVP_PKEY_paramgen()

These functions are made to work together with already existing domparams
and key generation functionality: EVP_PKEY_CTX_new_provided(),
EVP_PKEY_paramgen_init(), EVP_PKEY_keygen_init(), etc.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/10289)

crypto/evp/keymgmt_lib.c
crypto/evp/p_lib.c
crypto/evp/pmeth_gn.c
crypto/evp/pmeth_lib.c
doc/man3/EVP_PKEY_gen.pod [new file with mode: 0644]
doc/man3/EVP_PKEY_keygen.pod [deleted file]
include/crypto/evp.h
include/openssl/core_names.h
include/openssl/evp.h
util/libcrypto.num

index 68ccdbb8ee90d21b5f661be1cce7178945341589..94be3c2a9c93216996d7203bc800dc30d87d2ca1 100644 (file)
@@ -350,3 +350,23 @@ int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
 
     return 1;
 }
+
+void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
+                           void *genctx, OSSL_CALLBACK *cb, void *cbarg)
+{
+    void *keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg);
+
+    if (keydata != NULL) {
+        if (!EVP_KEYMGMT_up_ref(keymgmt)) {
+            evp_keymgmt_freedata(keymgmt, keydata);
+            return NULL;
+        }
+
+        evp_keymgmt_util_clear_operation_cache(target);
+        target->keymgmt = keymgmt;
+        target->keydata = keydata;
+        evp_keymgmt_util_cache_keyinfo(target);
+    }
+
+    return keydata;
+}
index 586ffaf0417f14c69b131843380be11ec644e830..3012790cee77a4016d772a0951d8b5130af0bddb 100644 (file)
@@ -1012,7 +1012,7 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
 }
 
 #ifndef FIPS_MODE
-static void evp_pkey_free_legacy(EVP_PKEY *x)
+void evp_pkey_free_legacy(EVP_PKEY *x)
 {
     if (x->ameth != NULL) {
         if (x->ameth->pkey_free != NULL)
index 84149fabd7807694250f653467776c49d51c2fef..03f1426d852bc93d6c8a9ac63c069c02e04e35bd 100644 (file)
@@ -9,7 +9,10 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <openssl/core.h>
+#include <openssl/core_names.h>
 #include "internal/cryptlib.h"
+#include "internal/core.h"
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include "crypto/bn.h"
 #include "crypto/evp.h"
 #include "evp_local.h"
 
-#ifndef FIPS_MODE
-int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
+static int gen_init(EVP_PKEY_CTX *ctx, int operation)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
-        EVPerr(EVP_F_EVP_PKEY_PARAMGEN_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
+    int ret = 0;
+
+    if (ctx == NULL)
+        goto not_supported;
+
+    evp_pkey_ctx_free_old_ops(ctx);
+    ctx->operation = operation;
+
+    if (ctx->engine != NULL || ctx->keytype == NULL)
+        goto legacy;
+
+    if (ctx->keymgmt == NULL) {
+        ctx->keymgmt =
+            EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
+        if (ctx->keymgmt == NULL
+            || ctx->keymgmt->gen_init == NULL) {
+            EVP_KEYMGMT_free(ctx->keymgmt);
+            ctx->keymgmt = NULL;
+            goto legacy;
+        }
+    }
+    if (ctx->keymgmt->gen_init == NULL)
+        goto not_supported;
+
+    switch (operation) {
+    case EVP_PKEY_OP_PARAMGEN:
+        ctx->op.keymgmt.genctx =
+            evp_keymgmt_gen_init(ctx->keymgmt,
+                                 OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+        break;
+    case EVP_PKEY_OP_KEYGEN:
+        ctx->op.keymgmt.genctx =
+            evp_keymgmt_gen_init(ctx->keymgmt, OSSL_KEYMGMT_SELECT_KEYPAIR);
+        break;
+    }
+
+    if (ctx->op.keymgmt.genctx == NULL)
+        ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+    else
+        ret = 1;
+    goto end;
+
+ legacy:
+#ifdef FIPS_MODE
+    goto not_supported;
+#else
+    if (ctx->pmeth == NULL
+        || (operation == EVP_PKEY_OP_PARAMGEN
+            && ctx->pmeth->paramgen == NULL)
+        || (operation == EVP_PKEY_OP_KEYGEN
+            && ctx->pmeth->keygen == NULL))
+        goto not_supported;
+
+    ret = 1;
+    switch (operation) {
+    case EVP_PKEY_OP_PARAMGEN:
+        if (ctx->pmeth->paramgen_init != NULL)
+            ret = ctx->pmeth->paramgen_init(ctx);
+        break;
+    case EVP_PKEY_OP_KEYGEN:
+        if (ctx->pmeth->keygen_init != NULL)
+            ret = ctx->pmeth->keygen_init(ctx);
+        break;
     }
-    ctx->operation = EVP_PKEY_OP_PARAMGEN;
-    if (!ctx->pmeth->paramgen_init)
-        return 1;
-    ret = ctx->pmeth->paramgen_init(ctx);
+#endif
+
+ end:
     if (ret <= 0)
         ctx->operation = EVP_PKEY_OP_UNDEFINED;
     return ret;
+
+ not_supported:
+    ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    ret = -2;
+    goto end;
 }
 
-int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
+int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) {
-        EVPerr(EVP_F_EVP_PKEY_PARAMGEN,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
+    return gen_init(ctx, EVP_PKEY_OP_PARAMGEN);
+}
 
-    if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
-        EVPerr(EVP_F_EVP_PKEY_PARAMGEN, EVP_R_OPERATON_NOT_INITIALIZED);
-        return -1;
-    }
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
+{
+    return gen_init(ctx, EVP_PKEY_OP_KEYGEN);
+}
+
+static int ossl_callback_to_pkey_gencb(const OSSL_PARAM params[], void *arg)
+{
+    EVP_PKEY_CTX *ctx = arg;
+    const OSSL_PARAM *param = NULL;
+    int p = -1, n = -1;
+
+    if (ctx->pkey_gencb == NULL)
+        return 1;                /* No callback?  That's fine */
+
+    if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_POTENTIAL))
+        == NULL
+        || !OSSL_PARAM_get_int(param, &p))
+        return 0;
+    if ((param = OSSL_PARAM_locate_const(params, OSSL_GEN_PARAM_ITERATION))
+        == NULL
+        || !OSSL_PARAM_get_int(param, &n))
+        return 0;
+
+    ctx->keygen_info[0] = p;
+    ctx->keygen_info[1] = n;
+
+    return ctx->pkey_gencb(ctx);
+}
+
+int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
+{
+    int ret = 0;
+    OSSL_CALLBACK cb;
+    EVP_PKEY *allocated_pkey = NULL;
 
     if (ppkey == NULL)
         return -1;
 
+    if (ctx == NULL)
+        goto not_supported;
+
+    if ((ctx->operation & EVP_PKEY_OP_TYPE_GEN) == 0)
+        goto not_initialized;
+
     if (*ppkey == NULL)
-        *ppkey = EVP_PKEY_new();
+        *ppkey = allocated_pkey = EVP_PKEY_new();
 
     if (*ppkey == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_PARAMGEN, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
         return -1;
     }
 
-    ret = ctx->pmeth->paramgen(ctx, *ppkey);
+    if (ctx->keymgmt == NULL)
+        goto legacy;
+
+    ret = 1;
+    if (ctx->pkey != NULL) {
+        EVP_KEYMGMT *tmp_keymgmt = ctx->keymgmt;
+        void *keydata =
+            evp_pkey_export_to_provider(ctx->pkey, ctx->libctx,
+                                        &tmp_keymgmt, ctx->propquery);
+
+        if (keydata == NULL)
+            goto not_supported;
+        ret = evp_keymgmt_gen_set_template(ctx->keymgmt,
+                                           ctx->op.keymgmt.genctx, keydata);
+    }
+
+    /*
+     * the returned value from evp_keymgmt_util_gen() is cached in *ppkey,
+     * so we so not need to save it, just check it.
+     */
+    ret = ret
+        && (evp_keymgmt_util_gen(*ppkey, ctx->keymgmt, ctx->op.keymgmt.genctx,
+                                 ossl_callback_to_pkey_gencb, ctx)
+            != NULL);
+
+#ifndef FIPS_MODE
+    /* In case |*ppkey| was originally a legacy key */
+    if (ret)
+        evp_pkey_free_legacy(*ppkey);
+#endif
+
+    goto end;
+
+ legacy:
+#ifdef FIPS_MODE
+    goto not_supported;
+#else
+    switch (ctx->operation) {
+    case EVP_PKEY_OP_PARAMGEN:
+        ret = ctx->pmeth->paramgen(ctx, *ppkey);
+        break;
+    case EVP_PKEY_OP_KEYGEN:
+        ret = ctx->pmeth->keygen(ctx, *ppkey);
+        break;
+    default:
+        goto not_supported;
+    }
+#endif
+
+ end:
     if (ret <= 0) {
-        EVP_PKEY_free(*ppkey);
-        *ppkey = NULL;
+        if (allocated_pkey != NULL)
+            *ppkey = NULL;
+        EVP_PKEY_free(allocated_pkey);
     }
     return ret;
+
+ not_supported:
+    ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    ret = -2;
+    goto end;
+ not_initialized:
+    ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
+    ret = -1;
+    goto end;
 }
 
-int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
+int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
 {
-    int ret;
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
-        EVPerr(EVP_F_EVP_PKEY_KEYGEN_INIT,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
+    if (ctx->operation != EVP_PKEY_OP_PARAMGEN) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
+        return -1;
     }
-    ctx->operation = EVP_PKEY_OP_KEYGEN;
-    if (!ctx->pmeth->keygen_init)
-        return 1;
-    ret = ctx->pmeth->keygen_init(ctx);
-    if (ret <= 0)
-        ctx->operation = EVP_PKEY_OP_UNDEFINED;
-    return ret;
+    return EVP_PKEY_gen(ctx, ppkey);
 }
 
 int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
 {
-    int ret;
-
-    if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
-        EVPerr(EVP_F_EVP_PKEY_KEYGEN,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
     if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
-        EVPerr(EVP_F_EVP_PKEY_KEYGEN, EVP_R_OPERATON_NOT_INITIALIZED);
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATON_NOT_INITIALIZED);
         return -1;
     }
-
-    if (ppkey == NULL)
-        return -1;
-
-    if (*ppkey == NULL)
-        *ppkey = EVP_PKEY_new();
-    if (*ppkey == NULL)
-        return -1;
-
-    ret = ctx->pmeth->keygen(ctx, *ppkey);
-    if (ret <= 0) {
-        EVP_PKEY_free(*ppkey);
-        *ppkey = NULL;
-    }
-    return ret;
+    return EVP_PKEY_gen(ctx, ppkey);
 }
 
 void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb)
@@ -152,6 +278,8 @@ int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx)
     return ctx->keygen_info[idx];
 }
 
+#ifndef FIPS_MODE
+
 EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
                                const unsigned char *key, int keylen)
 {
index 906b08156fb5cad57cdb12cd20b4ee3b3821b24c..f7bdbebbc170b51df5fbca5ee0a85593e0b35029 100644 (file)
@@ -292,6 +292,9 @@ void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx)
         EVP_ASYM_CIPHER_free(ctx->op.ciph.cipher);
         ctx->op.ciph.ciphprovctx = NULL;
         ctx->op.ciph.cipher = NULL;
+    } else if (EVP_PKEY_CTX_IS_GEN_OP(ctx)) {
+        if (ctx->op.keymgmt.genctx != NULL && ctx->keymgmt != NULL)
+            evp_keymgmt_gen_cleanup(ctx->keymgmt, ctx->op.keymgmt.genctx);
     }
 #endif
 }
@@ -569,6 +572,12 @@ int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params)
             && ctx->op.ciph.cipher->set_ctx_params != NULL)
         return ctx->op.ciph.cipher->set_ctx_params(ctx->op.ciph.ciphprovctx,
                                                      params);
+    if (EVP_PKEY_CTX_IS_GEN_OP(ctx)
+        && ctx->op.keymgmt.genctx != NULL
+        && ctx->keymgmt != NULL
+        && ctx->keymgmt->gen_set_params != NULL)
+        return evp_keymgmt_gen_set_params(ctx->keymgmt, ctx->op.keymgmt.genctx,
+                                          params);
     return 0;
 }
 
@@ -629,6 +638,10 @@ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx)
             && ctx->op.ciph.cipher != NULL
             && ctx->op.ciph.cipher->settable_ctx_params != NULL)
         return ctx->op.ciph.cipher->settable_ctx_params();
+    if (EVP_PKEY_CTX_IS_GEN_OP(ctx)
+            && ctx->keymgmt != NULL
+            && ctx->keymgmt->gen_settable_params != NULL)
+        return evp_keymgmt_gen_settable_params(ctx->keymgmt);
 
     return NULL;
 }
@@ -859,6 +872,12 @@ static int legacy_ctrl_to_param(EVP_PKEY_CTX *ctx, int keytype, int optype,
             ERR_raise(ERR_LIB_EVP,
                       EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
             return -2;
+        case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
+            return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, p1);
+        case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
+            return EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, p2);
+        case EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES:
+            return EVP_PKEY_CTX_set_rsa_keygen_primes(ctx, p1);
         }
     }
     return 0;
@@ -878,7 +897,9 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
             || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
                 && ctx->op.sig.sigprovctx != NULL)
             || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
-                && ctx->op.ciph.ciphprovctx != NULL))
+                && ctx->op.ciph.ciphprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_GEN_OP(ctx)
+                && ctx->op.keymgmt.genctx != NULL))
         return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2);
 
     if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) {
@@ -979,7 +1000,9 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx,
             || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx)
                 && ctx->op.sig.sigprovctx != NULL)
             || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)
-                && ctx->op.ciph.ciphprovctx != NULL))
+                && ctx->op.ciph.ciphprovctx != NULL)
+            || (EVP_PKEY_CTX_IS_GEN_OP(ctx)
+                && ctx->op.keymgmt.genctx != NULL))
         return legacy_ctrl_str_to_param(ctx, name, value);
 
     if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
diff --git a/doc/man3/EVP_PKEY_gen.pod b/doc/man3/EVP_PKEY_gen.pod
new file mode 100644 (file)
index 0000000..212ea2a
--- /dev/null
@@ -0,0 +1,217 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_keygen_init, EVP_PKEY_paramgen_init, EVP_PKEY_gen,
+EVP_PKEY_CTX_set_cb, EVP_PKEY_CTX_get_cb,
+EVP_PKEY_CTX_get_keygen_info, EVP_PKEY_CTX_set_app_data,
+EVP_PKEY_CTX_get_app_data,
+EVP_PKEY_gen_cb,
+EVP_PKEY_paramgen, EVP_PKEY_keygen
+- key and parameter generation and check functions
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+ int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+ int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+
+ typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
+
+ void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb);
+ EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx);
+
+ int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx);
+
+ void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
+ void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
+
+=head1 DESCRIPTION
+
+Generating keys is sometimes straight forward, just generate the key's
+numbers and be done with it.  However, there are certain key types that need
+key parameters, often called domain parameters but not necessarily limited
+to that, that also need to be generated.  In addition to this, the caller
+may want to set user provided generation parameters that further affect key
+parameter or key generation, such as the desired key size.
+
+To flexibly allow all that's just been described, key parameter and key
+generation is divided into an initialization of a key algorithm context,
+functions to set user provided parameters, and finally the key parameter or
+key generation function itself.
+
+The key algorithm context must be created using L<EVP_PKEY_CTX_new(3)> or
+variants thereof, see that manual for details.
+
+EVP_PKEY_keygen_init() initializes a public key algorithm context using key
+I<pkey> for a key generation operation.
+
+EVP_PKEY_paramgen_init() is similar to EVP_PKEY_keygen_init() except key
+parameters are generated.
+
+After initialization, generation parameters may be provided with
+L<EVP_PKEY_CTX_ctrl(3)> or L<EVP_PKEY_CTX_set_params(3)>, or any other
+function described in those manuals.
+
+EVP_PKEY_gen() performs the generation operation, the resulting key
+parameters or key are written to I<*ppkey>.  If I<*ppkey> is NULL when this
+function is called, it will be allocated, and should be freed by the caller
+when no longer useful, using L<EVP_PKEY_free(3)>.
+
+EVP_PKEY_paramgen() and EVP_PKEY_keygen() do exactly the same thing as
+EVP_PKEY_gen(), after checking that the corresponding EVP_PKEY_paramgen_init()
+or EVP_PKEY_keygen_init() was used to initialize I<ctx>.
+These are older functions that are kept for backward compatibility.
+It is safe to use EVP_PKEY_gen() instead.
+
+The function EVP_PKEY_set_cb() sets the key or parameter generation callback
+to I<cb>. The function EVP_PKEY_CTX_get_cb() returns the key or parameter
+generation callback.
+
+The function EVP_PKEY_CTX_get_keygen_info() returns parameters associated
+with the generation operation. If I<idx> is -1 the total number of
+parameters available is returned. Any non negative value returns the value of
+that parameter. EVP_PKEY_CTX_gen_keygen_info() with a non-negative value for
+I<idx> should only be called within the generation callback.
+
+If the callback returns 0 then the key generation operation is aborted and an
+error occurs. This might occur during a time consuming operation where
+a user clicks on a "cancel" button.
+
+The functions EVP_PKEY_CTX_set_app_data() and EVP_PKEY_CTX_get_app_data() set
+and retrieve an opaque pointer. This can be used to set some application
+defined value which can be retrieved in the callback: for example a handle
+which is used to update a "progress dialog".
+
+=head1 RETURN VALUES
+
+EVP_PKEY_keygen_init(), EVP_PKEY_paramgen_init(), EVP_PKEY_keygen() and
+EVP_PKEY_paramgen() return 1 for success and 0 or a negative value for failure.
+In particular a return value of -2 indicates the operation is not supported by
+the public key algorithm.
+
+=head1 NOTES
+
+After the call to EVP_PKEY_keygen_init() or EVP_PKEY_paramgen_init() algorithm
+specific control operations can be performed to set any appropriate parameters
+for the operation.
+
+The functions EVP_PKEY_keygen() and EVP_PKEY_paramgen() can be called more than
+once on the same context if several operations are performed using the same
+parameters.
+
+The meaning of the parameters passed to the callback will depend on the
+algorithm and the specific implementation of the algorithm. Some might not
+give any useful information at all during key or parameter generation. Others
+might not even call the callback.
+
+The operation performed by key or parameter generation depends on the algorithm
+used. In some cases (e.g. EC with a supplied named curve) the "generation"
+option merely sets the appropriate fields in an EVP_PKEY structure.
+
+In OpenSSL an EVP_PKEY structure containing a private key also contains the
+public key components and parameters (if any). An OpenSSL private key is
+equivalent to what some libraries call a "key pair". A private key can be used
+in functions which require the use of a public key or parameters.
+
+=head1 EXAMPLES
+
+Generate a 2048 bit RSA key:
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY *pkey = NULL;
+
+ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+ if (!ctx)
+     /* Error occurred */
+ if (EVP_PKEY_keygen_init(ctx) <= 0)
+     /* Error */
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
+     /* Error */
+
+ /* Generate key */
+ if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+     /* Error */
+
+Generate a key from a set of parameters:
+
+ #include <openssl/evp.h>
+ #include <openssl/rsa.h>
+
+ EVP_PKEY_CTX *ctx;
+ ENGINE *eng;
+ EVP_PKEY *pkey = NULL, *param;
+
+ /* Assumed param, eng are set up already */
+ ctx = EVP_PKEY_CTX_new(param, eng);
+ if (!ctx)
+     /* Error occurred */
+ if (EVP_PKEY_keygen_init(ctx) <= 0)
+     /* Error */
+
+ /* Generate key */
+ if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+     /* Error */
+
+Example of generation callback for OpenSSL public key implementations:
+
+ /* Application data is a BIO to output status to */
+
+ EVP_PKEY_CTX_set_app_data(ctx, status_bio);
+
+ static int genpkey_cb(EVP_PKEY_CTX *ctx)
+ {
+     char c = '*';
+     BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
+     int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
+
+     if (p == 0)
+         c = '.';
+     if (p == 1)
+         c = '+';
+     if (p == 2)
+         c = '*';
+     if (p == 3)
+         c = '\n';
+     BIO_write(b, &c, 1);
+     (void)BIO_flush(b);
+     return 1;
+ }
+
+=head1 SEE ALSO
+
+L<EVP_PKEY_CTX_new(3)>,
+L<EVP_PKEY_encrypt(3)>,
+L<EVP_PKEY_decrypt(3)>,
+L<EVP_PKEY_sign(3)>,
+L<EVP_PKEY_verify(3)>,
+L<EVP_PKEY_verify_recover(3)>,
+L<EVP_PKEY_derive(3)>
+
+=head1 HISTORY
+
+EVP_PKEY_keygen_init(), int EVP_PKEY_paramgen_init(), EVP_PKEY_keygen(),
+EVP_PKEY_paramgen(), EVP_PKEY_gen_cb(), EVP_PKEY_CTX_set_cb(),
+EVP_PKEY_CTX_get_cb(), EVP_PKEY_CTX_get_keygen_info(),
+EVP_PKEY_CTX_set_app_data() and EVP_PKEY_CTX_get_app_data() were added in
+OpenSSL 1.0.0.
+
+EVP_PKEY_gen() was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/EVP_PKEY_keygen.pod b/doc/man3/EVP_PKEY_keygen.pod
deleted file mode 100644 (file)
index e326b82..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-=pod
-
-=head1 NAME
-
-EVP_PKEY_keygen_init, EVP_PKEY_keygen, EVP_PKEY_paramgen_init,
-EVP_PKEY_paramgen, EVP_PKEY_CTX_set_cb, EVP_PKEY_CTX_get_cb,
-EVP_PKEY_CTX_get_keygen_info, EVP_PKEY_CTX_set_app_data,
-EVP_PKEY_CTX_get_app_data,
-EVP_PKEY_gen_cb
-- key and parameter generation and check functions
-
-=head1 SYNOPSIS
-
- #include <openssl/evp.h>
-
- int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
- int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
- int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
- int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
-
- typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
-
- void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb);
- EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx);
-
- int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx);
-
- void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
- void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
-
-=head1 DESCRIPTION
-
-The EVP_PKEY_keygen_init() function initializes a public key algorithm
-context using key B<pkey> for a key generation operation.
-
-The EVP_PKEY_keygen() function performs a key generation operation, the
-generated key is written to B<ppkey>.
-
-The functions EVP_PKEY_paramgen_init() and EVP_PKEY_paramgen() are similar
-except parameters are generated.
-
-The function EVP_PKEY_set_cb() sets the key or parameter generation callback
-to B<cb>. The function EVP_PKEY_CTX_get_cb() returns the key or parameter
-generation callback.
-
-The function EVP_PKEY_CTX_get_keygen_info() returns parameters associated
-with the generation operation. If B<idx> is -1 the total number of
-parameters available is returned. Any non negative value returns the value of
-that parameter. EVP_PKEY_CTX_gen_keygen_info() with a non-negative value for
-B<idx> should only be called within the generation callback.
-
-If the callback returns 0 then the key generation operation is aborted and an
-error occurs. This might occur during a time consuming operation where
-a user clicks on a "cancel" button.
-
-The functions EVP_PKEY_CTX_set_app_data() and EVP_PKEY_CTX_get_app_data() set
-and retrieve an opaque pointer. This can be used to set some application
-defined value which can be retrieved in the callback: for example a handle
-which is used to update a "progress dialog".
-
-=head1 NOTES
-
-After the call to EVP_PKEY_keygen_init() or EVP_PKEY_paramgen_init() algorithm
-specific control operations can be performed to set any appropriate parameters
-for the operation.
-
-The functions EVP_PKEY_keygen() and EVP_PKEY_paramgen() can be called more than
-once on the same context if several operations are performed using the same
-parameters.
-
-The meaning of the parameters passed to the callback will depend on the
-algorithm and the specific implementation of the algorithm. Some might not
-give any useful information at all during key or parameter generation. Others
-might not even call the callback.
-
-The operation performed by key or parameter generation depends on the algorithm
-used. In some cases (e.g. EC with a supplied named curve) the "generation"
-option merely sets the appropriate fields in an EVP_PKEY structure.
-
-In OpenSSL an EVP_PKEY structure containing a private key also contains the
-public key components and parameters (if any). An OpenSSL private key is
-equivalent to what some libraries call a "key pair". A private key can be used
-in functions which require the use of a public key or parameters.
-
-=head1 RETURN VALUES
-
-EVP_PKEY_keygen_init(), EVP_PKEY_paramgen_init(), EVP_PKEY_keygen() and
-EVP_PKEY_paramgen() return 1 for success and 0 or a negative value for failure.
-In particular a return value of -2 indicates the operation is not supported by
-the public key algorithm.
-
-=head1 EXAMPLES
-
-Generate a 2048 bit RSA key:
-
- #include <openssl/evp.h>
- #include <openssl/rsa.h>
-
- EVP_PKEY_CTX *ctx;
- EVP_PKEY *pkey = NULL;
-
- ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
- if (!ctx)
-     /* Error occurred */
- if (EVP_PKEY_keygen_init(ctx) <= 0)
-     /* Error */
- if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
-     /* Error */
-
- /* Generate key */
- if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
-     /* Error */
-
-Generate a key from a set of parameters:
-
- #include <openssl/evp.h>
- #include <openssl/rsa.h>
-
- EVP_PKEY_CTX *ctx;
- ENGINE *eng;
- EVP_PKEY *pkey = NULL, *param;
-
- /* Assumed param, eng are set up already */
- ctx = EVP_PKEY_CTX_new(param, eng);
- if (!ctx)
-     /* Error occurred */
- if (EVP_PKEY_keygen_init(ctx) <= 0)
-     /* Error */
-
- /* Generate key */
- if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
-     /* Error */
-
-Example of generation callback for OpenSSL public key implementations:
-
- /* Application data is a BIO to output status to */
-
- EVP_PKEY_CTX_set_app_data(ctx, status_bio);
-
- static int genpkey_cb(EVP_PKEY_CTX *ctx)
- {
-     char c = '*';
-     BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
-     int p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
-
-     if (p == 0)
-         c = '.';
-     if (p == 1)
-         c = '+';
-     if (p == 2)
-         c = '*';
-     if (p == 3)
-         c = '\n';
-     BIO_write(b, &c, 1);
-     (void)BIO_flush(b);
-     return 1;
- }
-
-=head1 SEE ALSO
-
-L<EVP_PKEY_CTX_new(3)>,
-L<EVP_PKEY_encrypt(3)>,
-L<EVP_PKEY_decrypt(3)>,
-L<EVP_PKEY_sign(3)>,
-L<EVP_PKEY_verify(3)>,
-L<EVP_PKEY_verify_recover(3)>,
-L<EVP_PKEY_derive(3)>
-
-=head1 HISTORY
-
-These functions were added in OpenSSL 1.0.0.
-
-=head1 COPYRIGHT
-
-Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
-
-Licensed under the Apache License 2.0 (the "License").  You may not use
-this file except in compliance with the License.  You can obtain a copy
-in the file LICENSE in the source distribution or at
-L<https://www.openssl.org/source/license.html>.
-
-=cut
index 42ac56a1d550b37ebacef0656b0f64fd21454445..744731aefe2dc8aed9f9a5353c8316207b844b2e 100644 (file)
@@ -34,6 +34,10 @@ struct evp_pkey_ctx_st {
     EVP_KEYMGMT *keymgmt;
 
     union {
+        struct {
+            void *genctx;
+        } keymgmt;
+
         struct {
             EVP_KEYEXCH *exchange;
             void *exchprovctx;
@@ -50,6 +54,14 @@ struct evp_pkey_ctx_st {
         } ciph;
     } op;
 
+    /* Application specific data, usually used by the callback */
+    void *app_data;
+    /* Keygen callback */
+    EVP_PKEY_gen_cb *pkey_gencb;
+    /* implementation specific keygen data */
+    int *keygen_info;
+    int keygen_info_count;
+
     /* Legacy fields below */
 
     /* Method associated with this operation */
@@ -62,13 +74,6 @@ struct evp_pkey_ctx_st {
     EVP_PKEY *peerkey;
     /* Algorithm specific data */
     void *data;
-    /* Application specific data */
-    void *app_data;
-    /* Keygen callback */
-    EVP_PKEY_gen_cb *pkey_gencb;
-    /* implementation specific keygen data */
-    int *keygen_info;
-    int keygen_info_count;
 } /* EVP_PKEY_CTX */ ;
 
 #define EVP_PKEY_FLAG_DYNAMIC   1
@@ -596,6 +601,10 @@ struct evp_pkey_st {
     ((ctx)->operation == EVP_PKEY_OP_ENCRYPT \
      || (ctx)->operation == EVP_PKEY_OP_DECRYPT)
 
+#define EVP_PKEY_CTX_IS_GEN_OP(ctx) \
+    ((ctx)->operation == EVP_PKEY_OP_PARAMGEN \
+     || (ctx)->operation == EVP_PKEY_OP_KEYGEN)
+
 void openssl_add_all_ciphers_int(void);
 void openssl_add_all_digests_int(void);
 void evp_cleanup_int(void);
@@ -606,6 +615,9 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
 void *evp_pkey_upgrade_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
                                    EVP_KEYMGMT **keymgmt,
                                    const char *propquery);
+#ifndef FIPS_MODE
+void evp_pkey_free_legacy(EVP_PKEY *x);
+#endif
 
 /*
  * KEYMGMT utility functions
@@ -622,6 +634,8 @@ void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
 int evp_keymgmt_util_has(EVP_PKEY *pk, int selection);
 int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection);
 int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection);
+void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
+                           void *genctx, OSSL_CALLBACK *cb, void *cbarg);
 
 
 /*
index 5e3a13a34be4502c091948a9939dd52c38158016..e2639ec1fcbb38012ff9e45cde63e00e1335de79 100644 (file)
@@ -220,6 +220,9 @@ extern "C" {
 #define OSSL_PKEY_PARAM_RSA_FACTOR      "rsa-factor"
 #define OSSL_PKEY_PARAM_RSA_EXPONENT    "rsa-exponent"
 #define OSSL_PKEY_PARAM_RSA_COEFFICIENT "rsa-coefficient"
+/* Key generation parameters */
+#define OSSL_PKEY_PARAM_RSA_BITS        "bits"
+#define OSSL_PKEY_PARAM_RSA_PRIMES      "primes"
 
 /* Key Exchange parameters */
 
@@ -279,6 +282,10 @@ extern "C" {
 /* Passphrase callback parameters */
 #define OSSL_PASSPHRASE_PARAM_INFO              "info"
 
+/* Keygen callback parameters, from provider to libcrypto */
+#define OSSL_GEN_PARAM_POTENTIAL            "potential" /* integer */
+#define OSSL_GEN_PARAM_ITERATION            "iteration" /* integer */
+
 # ifdef __cplusplus
 }
 # endif
index 202675cc709973af33b6a35c61d14a470f85b39f..a3e0581913b3898fa7b552eb3e1109695357933a 100644 (file)
@@ -1596,6 +1596,7 @@ int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
 int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+int EVP_PKEY_gen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
 int EVP_PKEY_check(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx);
index 15dd512a49f93445b8bce0196582f47830f6c1dd..9c9213aff425f0aa85f19b0a92d1c7dfea0cd2e2 100644 (file)
@@ -4980,3 +4980,4 @@ OSSL_CMP_SRV_CTX_set_send_unprotected_errors ?    3_0_0   EXIST::FUNCTION:CMP
 OSSL_CMP_SRV_CTX_set_accept_unprotected ?      3_0_0   EXIST::FUNCTION:CMP
 OSSL_CMP_SRV_CTX_set_accept_raverified  ?      3_0_0   EXIST::FUNCTION:CMP
 OSSL_CMP_SRV_CTX_set_grant_implicit_confirm ?  3_0_0   EXIST::FUNCTION:CMP
+EVP_PKEY_gen                            ?      3_0_0   EXIST::FUNCTION: