Add EVP functionality to create domain params and keys by user data
authorRichard Levitte <levitte@openssl.org>
Tue, 15 Oct 2019 12:50:35 +0000 (14:50 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 7 Nov 2019 10:50:39 +0000 (11:50 +0100)
This is the EVP operation that corresponds to creating direct RSA, DH
and DSA keys and set their numbers, to then assign them to an EVP_PKEY,
but done entirely using an algorithm agnostic EVP interface.

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

CHANGES
crypto/evp/keymgmt_lib.c
crypto/evp/pmeth_gn.c
doc/man3/EVP_PKEY_fromdata.pod [new file with mode: 0644]
include/crypto/evp.h
include/openssl/evp.h
util/libcrypto.num

diff --git a/CHANGES b/CHANGES
index 23a86dd..f500f2f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,13 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Added functionality to create an EVP_PKEY from user data.  This
+     is effectively the same as creating a RSA, DH or DSA object and
+     then assigning them to an EVP_PKEY, but directly using algorithm
+     agnostic EVP functions.  A benefit is that this should be future
+     proof for public key algorithms to come.
+     [Richard Levitte]
+
   *) Change the interpretation of the '--api' configuration option to
      mean that this is a desired API compatibility level with no
      further meaning.  The previous interpretation, that this would
index 5e9ec73..583e8b3 100644 (file)
@@ -254,6 +254,24 @@ void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk)
     }
 }
 
+void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
+                           const OSSL_PARAM params[], int domainparams)
+{
+    void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt));
+    void *provdata = domainparams
+        ? keymgmt->importdomparams(provctx, params)
+        : keymgmt->importkey(provctx, params);
+
+    evp_keymgmt_clear_pkey_cache(target);
+    if (provdata != NULL) {
+        EVP_KEYMGMT_up_ref(keymgmt);
+        target->pkeys[0].keymgmt = keymgmt;
+        target->pkeys[0].provdata = provdata;
+        target->pkeys[0].domainparams = domainparams;
+    }
+
+    return provdata;
+}
 
 /* internal functions */
 /* TODO(3.0) decide if these should be public or internal */
index 2564bbd..f872377 100644 (file)
 #include "crypto/bn.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "evp_local.h"
+
+static int fromdata_init(EVP_PKEY_CTX *ctx, int operation)
+{
+    if (ctx == NULL || ctx->algorithm == NULL)
+        goto not_supported;
+
+    evp_pkey_ctx_free_old_ops(ctx);
+    ctx->operation = operation;
+    if (ctx->keymgmt == NULL)
+        ctx->keymgmt = EVP_KEYMGMT_fetch(NULL, ctx->algorithm, ctx->propquery);
+    if (ctx->keymgmt == NULL)
+        goto not_supported;
+
+    return 1;
+
+ not_supported:
+    ctx->operation = EVP_PKEY_OP_UNDEFINED;
+    ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
+}
+
+int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx)
+{
+    return fromdata_init(ctx, EVP_PKEY_OP_PARAMFROMDATA);
+}
+
+int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx)
+{
+    return fromdata_init(ctx, EVP_PKEY_OP_KEYFROMDATA);
+}
+
+int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[])
+{
+    void *provdata = NULL;
+
+    if (ctx == NULL || (ctx->operation & EVP_PKEY_OP_TYPE_FROMDATA) == 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+        return -2;
+    }
+
+    if (ppkey == NULL)
+        return -1;
+
+    if (*ppkey == NULL)
+        *ppkey = EVP_PKEY_new();
+
+    if (*ppkey == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+
+    provdata =
+        evp_keymgmt_fromdata(*ppkey, ctx->keymgmt, params,
+                             ctx->operation == EVP_PKEY_OP_PARAMFROMDATA);
+
+    if (provdata == NULL)
+        return 0;
+    /* provdata is cached in *ppkey, so we need not bother with it further */
+    return 1;
+}
+
+/*
+ * TODO(3.0) Re-evalutate the names, it's possible that we find these to be
+ * better:
+ *
+ * EVP_PKEY_param_settable()
+ * EVP_PKEY_param_gettable()
+ */
+const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx)
+{
+    /* We call fromdata_init to get ctx->keymgmt populated */
+    if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED))
+        return evp_keymgmt_importdomparam_types(ctx->keymgmt);
+    return NULL;
+}
+
+const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx)
+{
+    /* We call fromdata_init to get ctx->keymgmt populated */
+    if (fromdata_init(ctx, EVP_PKEY_OP_UNDEFINED))
+        return evp_keymgmt_importdomparam_types(ctx->keymgmt);
+    return NULL;
+}
 
 int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
 {
diff --git a/doc/man3/EVP_PKEY_fromdata.pod b/doc/man3/EVP_PKEY_fromdata.pod
new file mode 100644 (file)
index 0000000..0e3dc5c
--- /dev/null
@@ -0,0 +1,69 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY_param_fromdata_init, EVP_PKEY_key_fromdata_init, EVP_PKEY_fromdata,
+EVP_PKEY_param_fromdata_settable, EVP_PKEY_key_fromdata_settable
+- functions to create domain parameters and keys from user data
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx);
+ int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM params[]);
+ const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx);
+ const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx);
+
+=head1 DESCRIPTION
+
+EVP_PKEY_param_fromdata_init() initializes a public key algorithm context
+for creating domain parameters from user data.
+
+EVP_PKEY_key_fromdata_init() initializes a public key algorithm context for
+creating a key from user data.
+
+EVP_PKEY_fromdata() creates domain parameters or a key, given data from
+I<params> and a context that's been initialized with
+EVP_PKEY_param_fromdata_init() or EVP_PKEY_key_fromdata_init().  The result is
+written to I<*ppkey>.
+
+EVP_PKEY_param_fromdata_settable() and EVP_PKEY_key_fromdata_settable()
+get a constant B<OSSL_PARAM> array that describes the settable parameters
+that can be used with EVP_PKEY_fromdata().
+See L<OSSL_PARAM(3)> for the use of B<OSSL_PARAM> as parameter descriptor.
+
+=head1 NOTES
+
+These functions only work with key management methods coming from a
+provider.
+
+=for comment We may choose to make this available for legacy methods too... 
+
+=head1 RETURN VALUES
+
+EVP_PKEY_key_fromdata_init(), EVP_PKEY_param_fromdata_init() and
+EVP_PKEY_fromdata() 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 SEE ALSO
+
+L<EVP_PKEY_CTX_new(3)>, L<provider(7)>
+
+=head1 HISTORY
+
+These functions were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 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 8f8def2..7753bc0 100644 (file)
@@ -581,6 +581,9 @@ void evp_app_cleanup_int(void);
 void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
                                      int domainparams);
 void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk);
+void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
+                           const OSSL_PARAM params[], int domainparams);
+
 
 /* KEYMGMT provider interface functions */
 void *evp_keymgmt_importdomparams(const EVP_KEYMGMT *keymgmt,
index 06f8b1f..05bf871 100644 (file)
@@ -1375,14 +1375,16 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
 # define EVP_PKEY_OP_UNDEFINED           0
 # define EVP_PKEY_OP_PARAMGEN            (1<<1)
 # define EVP_PKEY_OP_KEYGEN              (1<<2)
-# define EVP_PKEY_OP_SIGN                (1<<3)
-# define EVP_PKEY_OP_VERIFY              (1<<4)
-# define EVP_PKEY_OP_VERIFYRECOVER       (1<<5)
-# define EVP_PKEY_OP_SIGNCTX             (1<<6)
-# define EVP_PKEY_OP_VERIFYCTX           (1<<7)
-# define EVP_PKEY_OP_ENCRYPT             (1<<8)
-# define EVP_PKEY_OP_DECRYPT             (1<<9)
-# define EVP_PKEY_OP_DERIVE              (1<<10)
+# define EVP_PKEY_OP_PARAMFROMDATA       (1<<3)
+# define EVP_PKEY_OP_KEYFROMDATA         (1<<4)
+# define EVP_PKEY_OP_SIGN                (1<<5)
+# define EVP_PKEY_OP_VERIFY              (1<<6)
+# define EVP_PKEY_OP_VERIFYRECOVER       (1<<7)
+# define EVP_PKEY_OP_SIGNCTX             (1<<8)
+# define EVP_PKEY_OP_VERIFYCTX           (1<<9)
+# define EVP_PKEY_OP_ENCRYPT             (1<<10)
+# define EVP_PKEY_OP_DECRYPT             (1<<11)
+# define EVP_PKEY_OP_DERIVE              (1<<12)
 
 # define EVP_PKEY_OP_TYPE_SIG    \
         (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER \
@@ -1395,7 +1397,10 @@ int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
         (EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT | EVP_PKEY_OP_DERIVE)
 
 # define EVP_PKEY_OP_TYPE_GEN \
-                (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
+        (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
+
+# define EVP_PKEY_OP_TYPE_FROMDATA \
+        (EVP_PKEY_OP_PARAMFROMDATA | EVP_PKEY_OP_KEYFROMDATA)
 
 # define  EVP_PKEY_CTX_set_mac_key(ctx, key, len)        \
                 EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN,  \
@@ -1553,6 +1558,11 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
 
 typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
 
+int EVP_PKEY_param_fromdata_init(EVP_PKEY_CTX *ctx);
+int EVP_PKEY_key_fromdata_init(EVP_PKEY_CTX *ctx);
+int EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, OSSL_PARAM param[]);
+const OSSL_PARAM *EVP_PKEY_param_fromdata_settable(EVP_PKEY_CTX *ctx);
+const OSSL_PARAM *EVP_PKEY_key_fromdata_settable(EVP_PKEY_CTX *ctx);
 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);
index ac28f86..69e245e 100644 (file)
@@ -4857,3 +4857,8 @@ X509_LOOKUP_store                       ? 3_0_0   EXIST::FUNCTION:
 X509_STORE_load_file                    ?      3_0_0   EXIST::FUNCTION:
 X509_STORE_load_path                    ?      3_0_0   EXIST::FUNCTION:
 X509_STORE_load_store                   ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_param_fromdata_init            ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_key_fromdata_init              ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_fromdata                       ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_param_fromdata_settable        ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_key_fromdata_settable          ?      3_0_0   EXIST::FUNCTION: