Add basic EVP_KEYMGMT API and libcrypto <-> provider interface
authorRichard Levitte <levitte@openssl.org>
Thu, 4 Jul 2019 22:31:42 +0000 (00:31 +0200)
committerRichard Levitte <levitte@openssl.org>
Mon, 22 Jul 2019 04:17:38 +0000 (06:17 +0200)
The idea with the key management "operation" is to support the
following set of functionality:

- Key domain parameter generation
- Key domain parameter import
- Key domain parameter export

- Key generation
- Key import
- Key export
- Key loading (HSM / hidden key support)

With that set of function, we can support handling domain parameters
on one provider, key handling on another, and key usage on a third,
with transparent export / import of applicable data.  Of course, if a
provider doesn't offer export / import functionality, then all
operations surrounding a key must be performed with the same
provider.

This method also avoids having to do anything special with legacy
assignment of libcrypto key structures, i.e. EVP_PKEY_assign_RSA().
They will simply be used as keys to be exported from whenever they are
used with provider based operations.

This change only adds the EVP_KEYMGMT API and the libcrypto <->
provider interface.  Further changes will integrate them into existing
libcrypto functionality.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9312)

crypto/evp/build.info
crypto/evp/evp_locl.h
crypto/evp/keymgmt_meth.c [new file with mode: 0644]
crypto/include/internal/evp_int.h
doc/man3/EVP_KEYMGMT.pod [new file with mode: 0644]
include/openssl/core_numbers.h
include/openssl/evp.h
include/openssl/ossl_typ.h
util/libcrypto.num
util/private.num

index 5030f3f..d889897 100644 (file)
@@ -1,5 +1,6 @@
 LIBS=../../libcrypto
-$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c
+$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c keymgmt_meth.c \
+        evp_utils.c
 SOURCE[../../libcrypto]=$COMMON\
         encode.c evp_key.c evp_cnf.c \
         e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\
index 8aeb5d4..740c159 100644 (file)
@@ -62,6 +62,32 @@ struct evp_kdf_ctx_st {
     EVP_KDF_IMPL *impl;          /* Algorithm-specific data */
 } /* EVP_KDF_CTX */ ;
 
+struct evp_keymgmt_st {
+    int id;                      /* libcrypto internal */
+
+    const char *name;
+    OSSL_PROVIDER *prov;
+    CRYPTO_REF_COUNT refcnt;
+    CRYPTO_RWLOCK *lock;
+
+    /* Domain parameter routines */
+    OSSL_OP_keymgmt_importdomparams_fn *importdomparams;
+    OSSL_OP_keymgmt_gendomparams_fn *gendomparams;
+    OSSL_OP_keymgmt_freedomparams_fn *freedomparams;
+    OSSL_OP_keymgmt_exportdomparams_fn *exportdomparams;
+    OSSL_OP_keymgmt_importdomparam_types_fn *importdomparam_types;
+    OSSL_OP_keymgmt_exportdomparam_types_fn *exportdomparam_types;
+
+    /* Key routines */
+    OSSL_OP_keymgmt_importkey_fn *importkey;
+    OSSL_OP_keymgmt_genkey_fn *genkey;
+    OSSL_OP_keymgmt_loadkey_fn *loadkey;
+    OSSL_OP_keymgmt_freekey_fn *freekey;
+    OSSL_OP_keymgmt_exportkey_fn *exportkey;
+    OSSL_OP_keymgmt_importkey_types_fn *importkey_types;
+    OSSL_OP_keymgmt_exportkey_types_fn *exportkey_types;
+} /* EVP_KEYMGMT */ ;
+
 struct evp_keyexch_st {
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
@@ -76,7 +102,6 @@ struct evp_keyexch_st {
     OSSL_OP_keyexch_set_params_fn *set_params;
 } /* EVP_KEYEXCH */;
 
-
 int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
                              int passlen, ASN1_TYPE *param,
                              const EVP_CIPHER *c, const EVP_MD *md,
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
new file mode 100644 (file)
index 0000000..9723820
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_numbers.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include "internal/provider.h"
+#include "internal/refcount.h"
+#include "internal/evp_int.h"
+#include "evp_locl.h"
+
+
+static void *keymgmt_new(void)
+{
+    EVP_KEYMGMT *keymgmt = NULL;
+
+    if ((keymgmt = OPENSSL_zalloc(sizeof(*keymgmt))) == NULL
+        || (keymgmt->lock = CRYPTO_THREAD_lock_new()) == NULL) {
+        EVP_KEYMGMT_free(keymgmt);
+        return NULL;
+    }
+
+    keymgmt->refcnt = 1;
+
+    return keymgmt;
+}
+
+static void *keymgmt_from_dispatch(const OSSL_DISPATCH *fns,
+                                   OSSL_PROVIDER *prov)
+{
+    EVP_KEYMGMT *keymgmt = NULL;
+
+    if ((keymgmt = keymgmt_new()) == NULL)
+        return NULL;
+
+    for (; fns->function_id != 0; fns++) {
+        switch (fns->function_id) {
+        case OSSL_FUNC_KEYMGMT_IMPORTDOMPARAMS:
+            if (keymgmt->importdomparams != NULL)
+                break;
+            keymgmt->importdomparams =
+                OSSL_get_OP_keymgmt_importdomparams(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_GENDOMPARAMS:
+            if (keymgmt->gendomparams != NULL)
+                break;
+            keymgmt->gendomparams = OSSL_get_OP_keymgmt_gendomparams(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_FREEDOMPARAMS:
+            if (keymgmt->freedomparams != NULL)
+                break;
+            keymgmt->freedomparams = OSSL_get_OP_keymgmt_freedomparams(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS:
+            if (keymgmt->exportdomparams != NULL)
+                break;
+            keymgmt->exportdomparams =
+                OSSL_get_OP_keymgmt_exportdomparams(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_IMPORTDOMPARAM_TYPES:
+            if (keymgmt->importdomparam_types != NULL)
+                break;
+            keymgmt->importdomparam_types =
+                OSSL_get_OP_keymgmt_importdomparam_types(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_EXPORTDOMPARAM_TYPES:
+            if (keymgmt->exportdomparam_types != NULL)
+                break;
+            keymgmt->exportdomparam_types =
+                OSSL_get_OP_keymgmt_exportdomparam_types(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_IMPORTKEY:
+            if (keymgmt->importkey != NULL)
+                break;
+            keymgmt->importkey = OSSL_get_OP_keymgmt_importkey(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_GENKEY:
+            if (keymgmt->genkey != NULL)
+                break;
+            keymgmt->genkey = OSSL_get_OP_keymgmt_genkey(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_LOADKEY:
+            if (keymgmt->loadkey != NULL)
+                break;
+            keymgmt->loadkey = OSSL_get_OP_keymgmt_loadkey(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_FREEKEY:
+            if (keymgmt->freekey != NULL)
+                break;
+            keymgmt->freekey = OSSL_get_OP_keymgmt_freekey(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_EXPORTKEY:
+            if (keymgmt->exportkey != NULL)
+                break;
+            keymgmt->exportkey = OSSL_get_OP_keymgmt_exportkey(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_IMPORTKEY_TYPES:
+            if (keymgmt->importkey_types != NULL)
+                break;
+            keymgmt->importkey_types =
+                OSSL_get_OP_keymgmt_importkey_types(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_EXPORTKEY_TYPES:
+            if (keymgmt->exportkey_types != NULL)
+                break;
+            keymgmt->exportkey_types =
+                OSSL_get_OP_keymgmt_exportkey_types(fns);
+            break;
+        }
+    }
+    /*
+     * Try to check that the method is sensible.
+     * It makes no sense being able to free stuff if you can't create it.
+     * It makes no sense providing OSSL_PARAM descriptors for import and
+     * export if you can't import or export.
+     */
+    if ((keymgmt->freedomparams != NULL
+         && (keymgmt->importdomparams == NULL
+             && keymgmt->gendomparams == NULL))
+        || (keymgmt->freekey != NULL
+            && (keymgmt->importkey == NULL
+                && keymgmt->genkey == NULL
+                && keymgmt->loadkey == NULL))
+        || (keymgmt->importdomparam_types != NULL
+            && keymgmt->importdomparams == NULL)
+        || (keymgmt->exportdomparam_types != NULL
+            && keymgmt->exportdomparams == NULL)
+        || (keymgmt->importkey_types != NULL
+            && keymgmt->importkey == NULL)
+        || (keymgmt->exportkey_types != NULL
+            && keymgmt->exportkey == NULL)) {
+        EVP_KEYMGMT_free(keymgmt);
+        EVPerr(0, EVP_R_INVALID_PROVIDER_FUNCTIONS);
+        return NULL;
+    }
+    keymgmt->prov = prov;
+    if (prov != NULL)
+        ossl_provider_up_ref(prov);
+
+    return keymgmt;
+}
+
+EVP_KEYMGMT *EVP_KEYMGMT_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                               const char *properties)
+{
+    EVP_KEYMGMT *keymgmt =
+        evp_generic_fetch(ctx, OSSL_OP_KEYMGMT, algorithm, properties,
+                          keymgmt_from_dispatch,
+                          (int (*)(void *))EVP_KEYMGMT_up_ref,
+                          (void (*)(void *))EVP_KEYMGMT_free);
+
+    return keymgmt;
+}
+
+int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt)
+{
+    int ref = 0;
+
+    CRYPTO_UP_REF(&keymgmt->refcnt, &ref, keymgmt->lock);
+    return 1;
+}
+
+void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt)
+{
+    int ref = 0;
+
+    if (keymgmt == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref, keymgmt->lock);
+    if (ref > 0)
+        return;
+    ossl_provider_free(keymgmt->prov);
+    CRYPTO_THREAD_lock_free(keymgmt->lock);
+    OPENSSL_free(keymgmt);
+}
+
+const OSSL_PROVIDER *EVP_KEYMGMT_provider(const EVP_KEYMGMT *keymgmt)
+{
+    return keymgmt->prov;
+}
+
index 71833fa..359d561 100644 (file)
@@ -504,9 +504,9 @@ typedef struct {
  * method, as in, can it do arbitrary encryption....
  */
 struct evp_pkey_st {
+    /* == Legacy attributes == */
     int type;
     int save_type;
-    CRYPTO_REF_COUNT references;
     const EVP_PKEY_ASN1_METHOD *ameth;
     ENGINE *engine;
     ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */
@@ -526,9 +526,25 @@ struct evp_pkey_st {
         ECX_KEY *ecx;           /* X25519, X448, Ed25519, Ed448 */
 # endif
     } pkey;
-    int save_parameters;
-    STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
+
+    /* == Common attributes == */
+    CRYPTO_REF_COUNT references;
     CRYPTO_RWLOCK *lock;
+    STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
+    int save_parameters;
+
+    /* == Provider attributes == */
+    /*
+     * To support transparent export/import between providers that
+     * support the methods for it, and still not having to do the
+     * export/import every time a key is used, we maintain a cache
+     * of imported key, indexed by provider address.
+     * pkeys[0] is *always* the "original" key.
+     */
+    struct {
+        EVP_KEYMGMT *keymgmt;
+        void *provkey;
+    } pkeys[10];
 } /* EVP_PKEY */ ;
 
 
diff --git a/doc/man3/EVP_KEYMGMT.pod b/doc/man3/EVP_KEYMGMT.pod
new file mode 100644 (file)
index 0000000..ab209da
--- /dev/null
@@ -0,0 +1,84 @@
+=pod
+
+=head1 NAME
+
+EVP_KEYMGMT,
+EVP_KEYMGMT_fetch,
+EVP_KEYMGMT_up_ref,
+EVP_KEYMGMT_free,
+EVP_KEYMGMT_provider
+- EVP key management routines
+
+=head1 SYNOPSIS
+
+ #include <openssl/evp.h>
+
+ typedef struct evp_keymgmt_st EVP_KEYMGMT;
+
+ EVP_KEYMGMT *EVP_KEYMGMT_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                                const char *properties);
+ int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt);
+ void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt);
+ const OSSL_PROVIDER *EVP_KEYMGMT_provider(const EVP_KEYMGMT *keymgmt);
+
+=head1 DESCRIPTION
+
+B<EVP_KEYMGMT> is a method object that represents key management
+implementations for different cryptographic algorithms.
+This method object provides functionality to have providers import key
+material from the outside, as well as export key material to the
+outside.
+Most of the functionality can only be used internally and has no
+public interface, this object is simply passed into other functions
+when needed.
+
+EVP_KEYMGMT_fetch() looks for an algorithm within the provider that
+has been loaded into the B<OPENSSL_CTX> given by I<ctx>, having the
+name given by I<algorithm> and the properties given by I<properties>.
+
+EVP_KEYMGMT_up_ref() increments the reference count for the given
+B<EVP_KEYMGMT> I<keymgmt>.
+
+EVP_KEYMGMT_free() decrements the reference count for the given
+B<EVP_KEYMGMT> I<keymgmt>, and when the count reaches zero, frees it.
+
+EVP_KEYMGMT_provider() returns the provider that has this particular
+implementation.
+
+=head1 NOTES
+
+EVP_KEYMGMT_fetch() may be called implicitly by other fetching
+functions, using the same library context and properties.
+Any other API that uses keys will typically do this.
+
+=head1 RETURN VALUES
+
+EVP_KEYMGMT_fetch() returns a pointer to the key management
+implementation represented by an EVP_KEYMGMT object, or NULL on
+error.
+
+EVP_KEYMGMT_up_ref() returns 1 on success, or 0 on error.
+
+EVP_KEYMGMT_free() doesn't return any value.
+
+EVP_KEYMGMT_provider() returns a pointer to a provider object, or NULL
+on error.
+
+=head1 SEE ALSO
+
+L<EVP_MD_fetch(3)>, L<OPENSSL_CTX(3)>
+
+=head1 HISTORY
+
+The functions described here 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 c589243..f45b8f1 100644 (file)
@@ -229,9 +229,80 @@ OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_get_params, (void *cctx,
 OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_set_params, (void *cctx,
                                                     const OSSL_PARAM params[]))
 
+/*-
+ * Key management
+ *
+ * Key domain parameter references can be created in several manners:
+ * - by importing the domain parameter material via an OSSL_PARAM array.
+ * - by generating key domain parameters, given input via an OSSL_PARAM
+ *   array.
+ *
+ * Key references can be created in several manners:
+ * - by importing the key material via an OSSL_PARAM array.
+ * - by generating a key, given optional domain parameters and
+ *   additional keygen parameters.
+ *   If domain parameters are given, they must have been generated using
+ *   the domain parameter generator functions.
+ *   If the domain parameters comes from a different provider, results
+ *   are undefined.
+ *   THE CALLER MUST ENSURE THAT CORRECT DOMAIN PARAMETERS ARE USED.
+ * - by loading an internal key, given a binary blob that forms an identity.
+ *   THE CALLER MUST ENSURE THAT A CORRECT IDENTITY IS USED.
+ */
+
+# define OSSL_OP_KEYMGMT                           10
+
+/* Key domain parameter creation and destruction */
+# define OSSL_FUNC_KEYMGMT_IMPORTDOMPARAMS          1
+# define OSSL_FUNC_KEYMGMT_GENDOMPARAMS             2
+# define OSSL_FUNC_KEYMGMT_FREEDOMPARAMS            3
+OSSL_CORE_MAKE_FUNC(void *, OP_keymgmt_importdomparams,
+                    (void *provctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(void *, OP_keymgmt_gendomparams,
+                    (void *provctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(void, OP_keymgmt_freedomparams, (void *domparams))
+
+/* Key domain parameter export */
+# define OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS          4
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_exportdomparams,
+                    (void *domparams, OSSL_PARAM params[]))
+
+/* Key domain parameter discovery */
+# define OSSL_FUNC_KEYMGMT_IMPORTDOMPARAM_TYPES     5
+# define OSSL_FUNC_KEYMGMT_EXPORTDOMPARAM_TYPES     6
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_importdomparam_types,
+                    (void))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_exportdomparam_types,
+                    (void))
+
+/* Key creation and destruction */
+# define OSSL_FUNC_KEYMGMT_IMPORTKEY               10
+# define OSSL_FUNC_KEYMGMT_GENKEY                  11
+# define OSSL_FUNC_KEYMGMT_LOADKEY                 12
+# define OSSL_FUNC_KEYMGMT_FREEKEY                 13
+OSSL_CORE_MAKE_FUNC(void *, OP_keymgmt_importkey,
+                    (void *provctx, const OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(void *, OP_keymgmt_genkey,
+                    (void *provctx,
+                     void *domparams, const OSSL_PARAM genkeyparams[]))
+OSSL_CORE_MAKE_FUNC(void *, OP_keymgmt_loadkey,
+                    (void *provctx, void *id, size_t idlen))
+OSSL_CORE_MAKE_FUNC(void, OP_keymgmt_freekey, (void *key))
+
+/* Key export */
+# define OSSL_FUNC_KEYMGMT_EXPORTKEY               14
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_exportkey,
+                    (void *key, OSSL_PARAM params[]))
+
+/* Key discovery */
+# define OSSL_FUNC_KEYMGMT_IMPORTKEY_TYPES         15
+# define OSSL_FUNC_KEYMGMT_EXPORTKEY_TYPES         16
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_importkey_types, (void))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_exportkey_types, (void))
+
 /* Key Exchange */
 
-# define OSSL_OP_KEYEXCH                               3
+# define OSSL_OP_KEYEXCH                              11
 
 # define OSSL_FUNC_KEYEXCH_NEWCTX                      1
 # define OSSL_FUNC_KEYEXCH_INIT                        2
index 377b4b1..d014a2e 100644 (file)
@@ -1411,6 +1411,12 @@ int EVP_PKEY_meth_remove(const EVP_PKEY_METHOD *pmeth);
 size_t EVP_PKEY_meth_get_count(void);
 const EVP_PKEY_METHOD *EVP_PKEY_meth_get0(size_t idx);
 
+EVP_KEYMGMT *EVP_KEYMGMT_fetch(OPENSSL_CTX *ctx, const char *algorithm,
+                               const char *properties);
+int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt);
+void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt);
+const OSSL_PROVIDER *EVP_KEYMGMT_provider(const EVP_KEYMGMT *keymgmt);
+
 EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
 EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
 EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *ctx);
index 76a9bee..7eec053 100644 (file)
@@ -101,6 +101,8 @@ typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
 typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
 typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
 
+typedef struct evp_keymgmt_st EVP_KEYMGMT;
+
 typedef struct evp_kdf_st EVP_KDF;
 typedef struct evp_kdf_ctx_st EVP_KDF_CTX;
 
index 648aed9..1992504 100644 (file)
@@ -4685,3 +4685,7 @@ EVP_KEYEXCH_up_ref                      4790      3_0_0   EXIST::FUNCTION:
 EVP_KEYEXCH_fetch                       4791   3_0_0   EXIST::FUNCTION:
 EVP_PKEY_CTX_set_dh_pad                 4792   3_0_0   EXIST::FUNCTION:DH
 EVP_PKEY_CTX_set_params                 4793   3_0_0   EXIST::FUNCTION:
+EVP_KEYMGMT_fetch                       4794   3_0_0   EXIST::FUNCTION:
+EVP_KEYMGMT_up_ref                      4795   3_0_0   EXIST::FUNCTION:
+EVP_KEYMGMT_free                        4796   3_0_0   EXIST::FUNCTION:
+EVP_KEYMGMT_provider                    4797   3_0_0   EXIST::FUNCTION:
index f63319d..3307e3e 100644 (file)
@@ -24,6 +24,7 @@ CRYPTO_EX_new                           datatype
 DTLS_timer_cb                           datatype
 EVP_KDF                                 datatype
 EVP_KDF_CTX                             datatype
+EVP_KEYMGMT                             datatype
 EVP_MAC                                 datatype
 EVP_MAC_CTX                             datatype
 EVP_PKEY_gen_cb                         datatype