From aa4c32ebefacdad250b192b5ebd7560f4015f641 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 9 Oct 2017 15:21:11 +0100 Subject: [PATCH] Add EVP_PKEY_set1_engine() function. Add an ENGINE to EVP_PKEY structure which can be used for cryptographic operations: this will typically be used by an HSM key to redirect calls to a custom EVP_PKEY_METHOD. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/4503) (cherry picked from commit d19b01ad79f9e2aac5c87496b5ca5f80016daeb7) --- crypto/evp/p_lib.c | 26 ++++++++++++++++++++++++-- crypto/evp/pmeth_lib.c | 2 +- crypto/include/internal/evp_int.h | 1 + include/openssl/evp.h | 3 +++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 9828620552..d7372aa129 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -187,9 +187,11 @@ static int pkey_set_type(EVP_PKEY *pkey, int type, const char *str, int len) if ((type == pkey->save_type) && pkey->ameth) return 1; #ifndef OPENSSL_NO_ENGINE - /* If we have an ENGINE release it */ + /* If we have ENGINEs release them */ ENGINE_finish(pkey->engine); pkey->engine = NULL; + ENGINE_finish(pkey->pmeth_engine); + pkey->pmeth_engine = NULL; #endif } if (str) @@ -223,7 +225,25 @@ int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len) { return pkey_set_type(pkey, EVP_PKEY_NONE, str, len); } - +#ifndef OPENSSL_NO_ENGINE +int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *e) +{ + if (e != NULL) { + if (!ENGINE_init(e)) { + EVPerr(EVP_F_EVP_PKEY_SET1_ENGINE, ERR_R_ENGINE_LIB); + return 0; + } + if (ENGINE_get_pkey_meth(e, pkey->type) == NULL) { + ENGINE_finish(e); + EVPerr(EVP_F_EVP_PKEY_SET1_ENGINE, EVP_R_UNSUPPORTED_ALGORITHM); + return 0; + } + } + ENGINE_finish(pkey->pmeth_engine); + pkey->pmeth_engine = e; + return 1; +} +#endif int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { if (pkey == NULL || !EVP_PKEY_set_type(pkey, type)) @@ -413,6 +433,8 @@ static void EVP_PKEY_free_it(EVP_PKEY *x) #ifndef OPENSSL_NO_ENGINE ENGINE_finish(x->engine); x->engine = NULL; + ENGINE_finish(x->pmeth_engine); + x->pmeth_engine = NULL; #endif } diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 77e17dbd17..5e650a9db3 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -90,7 +90,7 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) } #ifndef OPENSSL_NO_ENGINE if (e == NULL && pkey != NULL) - e = pkey->engine; + e = pkey->pmeth_engine != NULL ? pkey->pmeth_engine : pkey->engine; /* Try to find an ENGINE which implements this method */ if (e) { if (!ENGINE_init(e)) { diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index c9ef58279a..6cc2f9255f 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -356,6 +356,7 @@ struct evp_pkey_st { int references; const EVP_PKEY_ASN1_METHOD *ameth; ENGINE *engine; + ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */ union { void *ptr; # ifndef OPENSSL_NO_RSA diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 01f51b7be3..6bc283c2a5 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -900,6 +900,9 @@ int EVP_PKEY_security_bits(const EVP_PKEY *pkey); int EVP_PKEY_size(EVP_PKEY *pkey); int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len); +# ifndef OPENSSL_NO_ENGINE +int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *e); +# endif int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); void *EVP_PKEY_get0(const EVP_PKEY *pkey); const unsigned char *EVP_PKEY_get0_hmac(const EVP_PKEY *pkey, size_t *len); -- 2.25.1