diff options
author | Richard Levitte <levitte@openssl.org> | 2019-07-05 00:31:42 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2019-07-22 06:17:38 +0200 |
commit | a94a3e0d91378b5c478f687a0dbc51914d4ed497 (patch) | |
tree | a649885fc1d6560a2928c610d9adaaf4ec6dbfcc /crypto | |
parent | 7312ef3fc4a7d391272f3ba8075eabf81a229ad2 (diff) |
Add basic EVP_KEYMGMT API and libcrypto <-> provider interface
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)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/evp/build.info | 3 | ||||
-rw-r--r-- | crypto/evp/evp_locl.h | 27 | ||||
-rw-r--r-- | crypto/evp/keymgmt_meth.c | 189 | ||||
-rw-r--r-- | crypto/include/internal/evp_int.h | 22 |
4 files changed, 236 insertions, 5 deletions
diff --git a/crypto/evp/build.info b/crypto/evp/build.info index 5030f3f68d..d889897b18 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -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\ diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 8aeb5d4003..740c159f05 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -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 index 0000000000..9723820203 --- /dev/null +++ b/crypto/evp/keymgmt_meth.c @@ -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; +} + diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index 71833fa49e..359d561342 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -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 */ ; |