EVP: make EVP_PKEY_{bits,security_bits,size} work with provider only keys
authorRichard Levitte <levitte@openssl.org>
Wed, 8 Jan 2020 02:44:28 +0000 (03:44 +0100)
committerRichard Levitte <levitte@openssl.org>
Fri, 17 Jan 2020 08:04:04 +0000 (09:04 +0100)
These functions relied entirely on the presence of 'pkey->pmeth',
which is NULL on provider only keys.  This adds an interface to get
domparam and key data from a provider, given corresponding provider
data (the actual domparam or key).

The retrieved data is cached in the EVP_PKEY structure (lending the
idea from provided EVP_CIPHER).

Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/10778)

crypto/evp/evp_local.h
crypto/evp/keymgmt_lib.c
crypto/evp/keymgmt_meth.c
crypto/evp/p_lib.c
doc/man7/provider-keymgmt.pod
include/crypto/evp.h
include/openssl/core_names.h
include/openssl/core_numbers.h

index de73267..0feace2 100644 (file)
@@ -80,6 +80,8 @@ struct evp_keymgmt_st {
     OSSL_OP_keymgmt_exportdomparams_fn *exportdomparams;
     OSSL_OP_keymgmt_importdomparam_types_fn *importdomparam_types;
     OSSL_OP_keymgmt_exportdomparam_types_fn *exportdomparam_types;
+    OSSL_OP_keymgmt_get_domparam_params_fn *get_domparam_params;
+    OSSL_OP_keymgmt_gettable_domparam_params_fn *gettable_domparam_params;
 
     /* Key routines */
     OSSL_OP_keymgmt_importkey_fn *importkey;
@@ -89,6 +91,9 @@ struct evp_keymgmt_st {
     OSSL_OP_keymgmt_exportkey_fn *exportkey;
     OSSL_OP_keymgmt_importkey_types_fn *importkey_types;
     OSSL_OP_keymgmt_exportkey_types_fn *exportkey_types;
+    OSSL_OP_keymgmt_get_key_params_fn *get_key_params;
+    OSSL_OP_keymgmt_gettable_key_params_fn *gettable_key_params;
+
     OSSL_OP_keymgmt_query_operation_name_fn *query_operation_name;
 } /* EVP_KEYMGMT */ ;
 
index 4163bca..53610d3 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/core_names.h>
 #include "internal/cryptlib.h"
 #include "internal/nelem.h"
 #include "crypto/evp.h"
@@ -132,12 +133,7 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
      */
     j = ossl_assert(i < OSSL_NELEM(pk->pkeys));
 
-    if (provdata != NULL) {
-        EVP_KEYMGMT_up_ref(keymgmt);
-        pk->pkeys[i].keymgmt = keymgmt;
-        pk->pkeys[i].provdata = provdata;
-        pk->pkeys[i].domainparams = want_domainparams;
-    }
+    evp_keymgmt_cache_pkey(pk, i, keymgmt, provdata, want_domainparams);
 
     return provdata;
 }
@@ -161,6 +157,49 @@ void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk)
                 keymgmt->freekey(provdata);
             EVP_KEYMGMT_free(keymgmt);
         }
+
+        pk->cache.size = 0;
+        pk->cache.bits = 0;
+        pk->cache.security_bits = 0;
+    }
+}
+
+void evp_keymgmt_cache_pkey(EVP_PKEY *pk, size_t index, EVP_KEYMGMT *keymgmt,
+                            void *provdata, int domainparams)
+{
+    if (provdata != NULL) {
+        EVP_KEYMGMT_up_ref(keymgmt);
+        pk->pkeys[index].keymgmt = keymgmt;
+        pk->pkeys[index].provdata = provdata;
+        pk->pkeys[index].domainparams = domainparams;
+
+        /*
+         * Cache information about the domain parameters or key.  Only needed
+         * for the "original" provider side key.
+         *
+         * This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc
+         */
+        if (index == 0) {
+            int ok;
+            int bits = 0;
+            int security_bits = 0;
+            int size = 0;
+            OSSL_PARAM params[4];
+
+            params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits);
+            params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS,
+                                                 &security_bits);
+            params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size);
+            params[3] = OSSL_PARAM_construct_end();
+            ok = domainparams
+                ? evp_keymgmt_get_domparam_params(keymgmt, provdata, params)
+                : evp_keymgmt_get_key_params(keymgmt, provdata, params);
+            if (ok) {
+                pk->cache.size = size;
+                pk->cache.bits = bits;
+                pk->cache.security_bits = security_bits;
+            }
+        }
     }
 }
 
@@ -173,12 +212,7 @@ void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
         : 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;
-    }
+    evp_keymgmt_cache_pkey(target, 0, keymgmt, provdata, domainparams);
 
     return provdata;
 }
@@ -228,6 +262,22 @@ const OSSL_PARAM *evp_keymgmt_exportdomparam_types(const EVP_KEYMGMT *keymgmt)
     return keymgmt->exportdomparam_types();
 }
 
+int evp_keymgmt_get_domparam_params(const EVP_KEYMGMT *keymgmt,
+                                     void *provdomparams, OSSL_PARAM params[])
+{
+    if (keymgmt->get_domparam_params == NULL)
+        return 1;
+    return keymgmt->get_domparam_params(provdomparams, params);
+}
+
+const OSSL_PARAM *
+evp_keymgmt_gettable_domparam_params(const EVP_KEYMGMT *keymgmt)
+{
+    if (keymgmt->gettable_domparam_params == NULL)
+        return NULL;
+    return keymgmt->gettable_domparam_params();
+}
+
 
 void *evp_keymgmt_importkey(const EVP_KEYMGMT *keymgmt,
                             const OSSL_PARAM params[])
@@ -277,3 +327,18 @@ const OSSL_PARAM *evp_keymgmt_exportkey_types(const EVP_KEYMGMT *keymgmt)
 {
     return keymgmt->exportkey_types();
 }
+
+int evp_keymgmt_get_key_params(const EVP_KEYMGMT *keymgmt,
+                               void *provkey, OSSL_PARAM params[])
+{
+    if (keymgmt->get_key_params == NULL)
+        return 1;
+    return keymgmt->get_key_params(provkey, params);
+}
+
+const OSSL_PARAM *evp_keymgmt_gettable_key_params(const EVP_KEYMGMT *keymgmt)
+{
+    if (keymgmt->gettable_key_params == NULL)
+        return NULL;
+    return keymgmt->gettable_key_params();
+}
index 03d1686..ae1f10e 100644 (file)
@@ -81,6 +81,16 @@ static void *keymgmt_from_dispatch(int name_id,
             keymgmt->exportdomparam_types =
                 OSSL_get_OP_keymgmt_exportdomparam_types(fns);
             break;
+        case OSSL_FUNC_KEYMGMT_GET_DOMPARAM_PARAMS:
+            if (keymgmt->get_domparam_params == NULL)
+                keymgmt->get_domparam_params =
+                    OSSL_get_OP_keymgmt_get_domparam_params(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_GETTABLE_DOMPARAM_PARAMS:
+            if (keymgmt->gettable_domparam_params == NULL)
+                keymgmt->gettable_domparam_params =
+                    OSSL_get_OP_keymgmt_gettable_domparam_params(fns);
+            break;
         case OSSL_FUNC_KEYMGMT_IMPORTKEY:
             if (keymgmt->importkey != NULL)
                 break;
@@ -118,6 +128,16 @@ static void *keymgmt_from_dispatch(int name_id,
             keymgmt->exportkey_types =
                 OSSL_get_OP_keymgmt_exportkey_types(fns);
             break;
+        case OSSL_FUNC_KEYMGMT_GET_KEY_PARAMS:
+            if (keymgmt->get_key_params == NULL)
+                keymgmt->get_key_params =
+                    OSSL_get_OP_keymgmt_get_key_params(fns);
+            break;
+        case OSSL_FUNC_KEYMGMT_GETTABLE_KEY_PARAMS:
+            if (keymgmt->gettable_key_params == NULL)
+                keymgmt->gettable_key_params =
+                    OSSL_get_OP_keymgmt_gettable_key_params(fns);
+            break;
         case OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME:
             if (keymgmt->query_operation_name != NULL)
                 break;
@@ -143,10 +163,14 @@ static void *keymgmt_from_dispatch(int name_id,
             && keymgmt->importdomparams == NULL)
         || (keymgmt->exportdomparam_types != NULL
             && keymgmt->exportdomparams == NULL)
+        || (keymgmt->gettable_domparam_params != NULL
+            && keymgmt->get_domparam_params == NULL)
         || (keymgmt->importkey_types != NULL
             && keymgmt->importkey == NULL)
         || (keymgmt->exportkey_types != NULL
-            && keymgmt->exportkey == NULL)) {
+            && keymgmt->exportkey == NULL)
+        || (keymgmt->gettable_key_params != NULL
+            && keymgmt->get_key_params == NULL)) {
         EVP_KEYMGMT_free(keymgmt);
         EVPerr(0, EVP_R_INVALID_PROVIDER_FUNCTIONS);
         return NULL;
index 5c11ce1..2e0890c 100644 (file)
@@ -34,8 +34,12 @@ static void evp_pkey_free_it(EVP_PKEY *key);
 
 int EVP_PKEY_bits(const EVP_PKEY *pkey)
 {
-    if (pkey && pkey->ameth && pkey->ameth->pkey_bits)
-        return pkey->ameth->pkey_bits(pkey);
+    if (pkey != NULL) {
+        if (pkey->ameth == NULL)
+            return pkey->cache.bits;
+        else if (pkey->ameth->pkey_bits)
+            return pkey->ameth->pkey_bits(pkey);
+    }
     return 0;
 }
 
@@ -43,7 +47,9 @@ int EVP_PKEY_security_bits(const EVP_PKEY *pkey)
 {
     if (pkey == NULL)
         return 0;
-    if (pkey->ameth == NULL || pkey->ameth->pkey_security_bits == NULL)
+    if (pkey->ameth == NULL)
+        return pkey->cache.security_bits;
+    if (pkey->ameth->pkey_security_bits == NULL)
         return -2;
     return pkey->ameth->pkey_security_bits(pkey);
 }
@@ -811,11 +817,13 @@ void EVP_PKEY_free(EVP_PKEY *x)
     OPENSSL_free(x);
 }
 
-/* TODO (3.0) : Needs to call getparams fo non legacy case */
 int EVP_PKEY_size(const EVP_PKEY *pkey)
 {
-    if (pkey && pkey->ameth && pkey->ameth->pkey_size)
-        return pkey->ameth->pkey_size(pkey);
+    if (pkey != NULL) {
+        if (pkey->ameth == NULL)
+            return pkey->cache.size;
+        else if (pkey->ameth->pkey_size != NULL)
+            return pkey->ameth->pkey_size(pkey);
+    }
     return 0;
 }
-
index 1c868c5..adc1978 100644 (file)
@@ -26,6 +26,10 @@ provider-keymgmt - The KEYMGMT library E<lt>-E<gt> provider functions
  const OSSL_PARAM *OP_keymgmt_importdomparam_types(void);
  const OSSL_PARAM *OP_keymgmt_exportdomparam_types(void);
 
+ /* Key domain parameter information */
+ int OP_keymgmt_get_domparam_params(void *domparams, OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_keymgmt_gettable_domparam_params(void);
+
  /* Key creation and destruction */
  void *OP_keymgmt_importkey(void *provctx, const OSSL_PARAM params[]);
  void *OP_keymgmt_genkey(void *provctx,
@@ -40,6 +44,10 @@ provider-keymgmt - The KEYMGMT library E<lt>-E<gt> provider functions
  const OSSL_PARAM *OP_keymgmt_importkey_types(void);
  const OSSL_PARAM *OP_keymgmt_exportkey_types(void);
 
+ /* Key information */
+ int OP_keymgmt_get_key_params(void *key, OSSL_PARAM params[]);
+ const OSSL_PARAM *OP_keymgmt_gettable_key_params(void);
+
  /* Discovery of supported operations */
  const char *OP_keymgmt_query_operation_name(int operation_id);
 
@@ -84,6 +92,9 @@ macros in L<openssl-core_numbers.h(7)>, as follows:
  OP_keymgmt_exportdomparams      OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS
  OP_keymgmt_importdomparam_types OSSL_FUNC_KEYMGMT_IMPORTDOMPARAM_TYPES
  OP_keymgmt_exportdomparam_types OSSL_FUNC_KEYMGMT_EXPORTDOMPARAM_TYPES
+ OP_keymgmt_get_domparam_params  OSSL_FUNC_KEYMGMT_GET_DOMPARAM_PARAMS
+ OP_keymgmt_gettable_domparam_params
+                                 OSSL_FUNC_KEYMGMT_GETTABLE_DOMPARAM_PARAMS
 
  OP_keymgmt_importkey            OSSL_FUNC_KEYMGMT_IMPORTKEY
  OP_keymgmt_genkey               OSSL_FUNC_KEYMGMT_GENKEY
@@ -92,6 +103,10 @@ macros in L<openssl-core_numbers.h(7)>, as follows:
  OP_keymgmt_exportkey            OSSL_FUNC_KEYMGMT_EXPORTKEY
  OP_keymgmt_importkey_types      OSSL_FUNC_KEYMGMT_IMPORTKEY_TYPES
  OP_keymgmt_exportkey_types      OSSL_FUNC_KEYMGMT_EXPORTKEY_TYPES
+ OP_keymgmt_get_key_params       OSSL_FUNC_KEYMGMT_GET_KEY_PARAMS
+ OP_keymgmt_gettable_key_params  OSSL_FUNC_KEYMGMT_GETTABLE_KEY_PARAMS
+
+ OP_keymgmt_query_operation_name OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME
 
 =head2 Domain Parameter Functions
 
@@ -116,13 +131,18 @@ OP_keymgmt_importdomparam_types() should return a constant array of
 descriptor B<OSSL_PARAM>, for parameters that OP_keymgmt_importdomparams()
 can handle.
 
-=for comment There should be one corresponding to OP_keymgmt_gendomparams()
-as well...
-
 OP_keymgmt_exportdomparam_types() should return a constant array of
 descriptor B<OSSL_PARAM>, for parameters that can be exported with
 OP_keymgmt_exportdomparams().
 
+OP_keymgmt_get_domparam_params() should extract information data
+associated with the given I<domparams>,
+see L</Information Parameters>.
+
+OP_keymgmt_gettable_domparam_params() should return a constant array
+of descriptor B<OSSL_PARAM>, for parameters that
+OP_keymgmt_get_domparam_params() can handle.
+
 =head2 Key functions
 
 OP_keymgmt_importkey() should create a provider side structure
@@ -154,13 +174,17 @@ OP_keymgmt_importkey_types() should return a constant array of
 descriptor B<OSSL_PARAM>, for parameters that OP_keymgmt_importkey()
 can handle.
 
-=for comment There should be one corresponding to OP_keymgmt_genkey()
-as well...
-
 OP_keymgmt_exportkey_types() should return a constant array of
 descriptor B<OSSL_PARAM>, for parameters that can be exported with
 OP_keymgmt_exportkeys().
 
+OP_keymgmt_get_key_params() should extract information data associated
+with the given I<key>, see L</Information Parameters>.
+
+OP_keymgmt_gettable_key_params() should return a constant array of
+descriptor B<OSSL_PARAM>, for parameters that
+OP_keymgmt_get_key_params() can handle.
+
 =head2 Supported operations
 
 OP_keymgmt_query_operation_name() should return the name of the
@@ -171,6 +195,42 @@ returns NULL, the caller is free to assume that there's an algorithm
 from the same provider, of the same name as the one used to fetch the
 keymgmt and try to use that.
 
+=head2 Information Parameters
+
+See L<OSSL_PARAM(3)> for further details on the parameters structure.
+
+Parameters currently recognised by built-in keymgmt algorithms'
+OP_keymgmt_get_domparams_params() and OP_keymgmt_get_key_params()
+are:
+
+=over 4
+
+=item "bits" (B<OSSL_PKEY_PARAM_BITS>) <integer>
+
+The value should be the cryptographic length of the cryptosystem to
+which the key belongs, in bits.  The definition of cryptographic
+length is specific to the key cryptosystem.
+
+=item "max-size" (B<OSSL_PKEY_PARAM_MAX_SIZE>) <integer>
+
+The value should be the maximum size that a caller should allocate to
+safely store a signature (called I<sig> in L<provider-signature(7)>),
+the result of asymmmetric encryption / decryption (I<out> in
+L<provider-asym_cipher(7)>, a derived secret (I<secret> in
+L<provider-keyexch(7)>, and similar data).
+
+Because an EVP_KEYMGMT method is always tightly bound to another method
+(signature, asymmetric cipher, key exchange, ...) and must be of the
+same provider, this number only needs to be synchronised with the
+dimensions handled in the rest of the same provider.
+
+=item "security-bits" (B<OSSL_PKEY_PARAM_SECURITY_BITS>) <integer>
+
+The value should be the number of security bits of the given key.
+Bits of security is defined in SP800-57.
+
+=back
+
 =head1 SEE ALSO
 
 L<provider(7)>
index 91f5350..b3d1f7d 100644 (file)
@@ -565,6 +565,13 @@ struct evp_pkey_st {
      * a copy of that key's dirty count.
      */
     size_t dirty_cnt_copy;
+
+    /* Cache of domain parameter / key information */
+    struct {
+        int bits;
+        int security_bits;
+        int size;
+    } cache;
 } /* EVP_PKEY */ ;
 
 #define EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) \
@@ -590,6 +597,8 @@ 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_cache_pkey(EVP_PKEY *pk, size_t index, EVP_KEYMGMT *keymgmt,
+                            void *provdata, int domainparams);
 void *evp_keymgmt_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
                            const OSSL_PARAM params[], int domainparams);
 
@@ -608,6 +617,10 @@ const OSSL_PARAM *
 evp_keymgmt_importdomparam_types(const EVP_KEYMGMT *keymgmt);
 const OSSL_PARAM *
 evp_keymgmt_exportdomparam_types(const EVP_KEYMGMT *keymgmt);
+int evp_keymgmt_get_domparam_params(const EVP_KEYMGMT *keymgmt,
+                                    void *provdomparam, OSSL_PARAM params[]);
+const OSSL_PARAM *
+evp_keymgmt_gettable_domparam_params(const EVP_KEYMGMT *keymgmt);
 
 void *evp_keymgmt_importkey(const EVP_KEYMGMT *keymgmt,
                             const OSSL_PARAM params[]);
@@ -620,6 +633,9 @@ int evp_keymgmt_exportkey(const EVP_KEYMGMT *keymgmt, void *provkey,
                           OSSL_CALLBACK *param_cb, void *cbarg);
 const OSSL_PARAM *evp_keymgmt_importkey_types(const EVP_KEYMGMT *keymgmt);
 const OSSL_PARAM *evp_keymgmt_exportkey_types(const EVP_KEYMGMT *keymgmt);
+int evp_keymgmt_get_key_params(const EVP_KEYMGMT *keymgmt,
+                               void *provkey, OSSL_PARAM params[]);
+const OSSL_PARAM *evp_keymgmt_gettable_key_params(const EVP_KEYMGMT *keymgmt);
 
 /* Pulling defines out of C source files */
 
index 0bc51b3..a347d96 100644 (file)
@@ -154,6 +154,11 @@ extern "C" {
 #define OSSL_KDF_NAME_KRB5KDF       "KRB5KDF"
 
 /* PKEY parameters */
+/* Common PKEY parameters */
+#define OSSL_PKEY_PARAM_BITS                "bits" /* integer */
+#define OSSL_PKEY_PARAM_MAX_SIZE            "max-size" /* integer */
+#define OSSL_PKEY_PARAM_SECURITY_BITS       "security-bits" /* integer */
+
 /* Diffie-Hellman/DSA Parameters */
 #define OSSL_PKEY_PARAM_FFC_P        "p"
 #define OSSL_PKEY_PARAM_FFC_G        "g"
index f41f7c0..0a809de 100644 (file)
@@ -371,6 +371,14 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_importdomparam_types,
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_exportdomparam_types,
                     (void))
 
+/* Key domain parameter information */
+#define OSSL_FUNC_KEYMGMT_GET_DOMPARAM_PARAMS       7
+#define OSSL_FUNC_KEYMGMT_GETTABLE_DOMPARAM_PARAMS  8
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_get_domparam_params,
+                    (void *domparam, OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_gettable_domparam_params,
+                    (void))
+
 /* Key creation and destruction */
 # define OSSL_FUNC_KEYMGMT_IMPORTKEY               10
 # define OSSL_FUNC_KEYMGMT_GENKEY                  11
@@ -400,8 +408,15 @@ OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_exportkey,
 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 information */
+#define OSSL_FUNC_KEYMGMT_GET_KEY_PARAMS            17
+#define OSSL_FUNC_KEYMGMT_GETTABLE_KEY_PARAMS       18
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_get_key_params,
+                    (void *key, OSSL_PARAM params[]))
+OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_gettable_key_params, (void))
+
 /* Discovery of supported operations */
-# define OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME    17
+# define OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME     20
 OSSL_CORE_MAKE_FUNC(const char *,OP_keymgmt_query_operation_name,
                     (int operation_id))