The branch master has been updated via 8e826a339f8cda20a4311fa88a1de782972cf40d (commit) via e3662075c3bf3db9b1d2dbf7e165b820873a55b4 (commit) via 3f8b368a270c928e92c6b06cbe8002c343aedfcf (commit) via d19b01ad79f9e2aac5c87496b5ca5f80016daeb7 (commit) via 918a27facd3558444c69b1edbedb49478e82dff5 (commit) via c2976edf4b22691d8bebb0e3ca2db18b3d0c71c6 (commit) from e913d11f444e0b46ec1ebbf3340813693f4d869d (commit)
- Log ----------------------------------------------------------------- commit 8e826a339f8cda20a4311fa88a1de782972cf40d Author: Dr. Stephen Henson <st...@openssl.org> Date: Tue Oct 10 13:42:24 2017 +0100 Document EVP_PKEY_set1_engine() Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) commit e3662075c3bf3db9b1d2dbf7e165b820873a55b4 Author: Dr. Stephen Henson <st...@openssl.org> Date: Mon Oct 9 23:24:51 2017 +0100 Add EVP_PKEY_METHOD redirection test Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) commit 3f8b368a270c928e92c6b06cbe8002c343aedfcf Author: Dr. Stephen Henson <st...@openssl.org> Date: Tue Oct 10 13:31:04 2017 +0100 make update Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) commit d19b01ad79f9e2aac5c87496b5ca5f80016daeb7 Author: Dr. Stephen Henson <st...@openssl.org> Date: Mon Oct 9 15:21:11 2017 +0100 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 <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) commit 918a27facd3558444c69b1edbedb49478e82dff5 Author: Dr. Stephen Henson <st...@openssl.org> Date: Mon Oct 9 23:24:26 2017 +0100 Fix memory leak on lookup failure Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) commit c2976edf4b22691d8bebb0e3ca2db18b3d0c71c6 Author: Dr. Stephen Henson <st...@openssl.org> Date: Mon Oct 9 14:37:21 2017 +0100 Don't ignore passed ENGINE. If we are passed an ENGINE to use in int_ctx_new e.g. via EVP_PKEY_CTX_new() use it instead of the default. Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4503) ----------------------------------------------------------------------- Summary of changes: crypto/err/openssl.txt | 1 + crypto/evp/evp_err.c | 2 + crypto/evp/p_lib.c | 26 +++++- crypto/evp/pmeth_lib.c | 10 ++- crypto/include/internal/evp_int.h | 1 + doc/man3/EVP_PKEY_set1_RSA.pod | 19 ++++- include/openssl/evp.h | 3 + include/openssl/evperr.h | 1 + test/enginetest.c | 170 ++++++++++++++++++++++++++++++++++++++ util/libcrypto.num | 1 + 10 files changed, 225 insertions(+), 9 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 58b9019..f711dac 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -689,6 +689,7 @@ EVP_F_EVP_PKEY_KEYGEN_INIT:147:EVP_PKEY_keygen_init EVP_F_EVP_PKEY_NEW:106:EVP_PKEY_new EVP_F_EVP_PKEY_PARAMGEN:148:EVP_PKEY_paramgen EVP_F_EVP_PKEY_PARAMGEN_INIT:149:EVP_PKEY_paramgen_init +EVP_F_EVP_PKEY_SET1_ENGINE:187:EVP_PKEY_set1_engine EVP_F_EVP_PKEY_SIGN:140:EVP_PKEY_sign EVP_F_EVP_PKEY_SIGN_INIT:141:EVP_PKEY_sign_init EVP_F_EVP_PKEY_VERIFY:142:EVP_PKEY_verify diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index cc32a3b..bb3abe3 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -95,6 +95,8 @@ static const ERR_STRING_DATA EVP_str_functs[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN, 0), "EVP_PKEY_paramgen"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_PARAMGEN_INIT, 0), "EVP_PKEY_paramgen_init"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_SET1_ENGINE, 0), + "EVP_PKEY_set1_engine"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_SIGN, 0), "EVP_PKEY_sign"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_SIGN_INIT, 0), "EVP_PKEY_sign_init"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_VERIFY, 0), "EVP_PKEY_verify"}, diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 7453937..f0c3075 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -188,9 +188,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) @@ -224,7 +226,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)) @@ -443,6 +463,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 2b9b8a9..37c5e85 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -105,16 +105,17 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) id = pkey->ameth->pkey_id; } #ifndef OPENSSL_NO_ENGINE - if (pkey && pkey->engine) - e = pkey->engine; + if (e == NULL && pkey != NULL) + 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)) { EVPerr(EVP_F_INT_CTX_NEW, ERR_R_ENGINE_LIB); return NULL; } - } else + } else { e = ENGINE_get_pkey_meth_engine(id); + } /* * If an ENGINE handled this method look it up. Otherwise use internal @@ -128,6 +129,9 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) pmeth = EVP_PKEY_meth_find(id); if (pmeth == NULL) { +#ifndef OPENSSL_NO_ENGINE + ENGINE_finish(e); +#endif EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM); return NULL; } diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index ccfa97c..f409400 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -369,6 +369,7 @@ struct evp_pkey_st { CRYPTO_REF_COUNT 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/doc/man3/EVP_PKEY_set1_RSA.pod b/doc/man3/EVP_PKEY_set1_RSA.pod index e1b7110..884cf91 100644 --- a/doc/man3/EVP_PKEY_set1_RSA.pod +++ b/doc/man3/EVP_PKEY_set1_RSA.pod @@ -5,10 +5,9 @@ EVP_PKEY_set1_RSA, EVP_PKEY_set1_DSA, EVP_PKEY_set1_DH, EVP_PKEY_set1_EC_KEY, EVP_PKEY_get1_RSA, EVP_PKEY_get1_DSA, EVP_PKEY_get1_DH, EVP_PKEY_get1_EC_KEY, EVP_PKEY_get0_RSA, EVP_PKEY_get0_DSA, EVP_PKEY_get0_DH, EVP_PKEY_get0_EC_KEY, -EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH, EVP_PKEY_assign_EC_KEY, -EVP_PKEY_get0_hmac, -EVP_PKEY_type, EVP_PKEY_id, EVP_PKEY_base_id -- EVP_PKEY assignment functions +EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH, +EVP_PKEY_assign_EC_KEY, EVP_PKEY_get0_hmac, EVP_PKEY_type, EVP_PKEY_id, +EVP_PKEY_base_id, EVP_PKEY_set1_engine - EVP_PKEY assignment functions =head1 SYNOPSIS @@ -39,6 +38,8 @@ EVP_PKEY_type, EVP_PKEY_id, EVP_PKEY_base_id int EVP_PKEY_base_id(const EVP_PKEY *pkey); int EVP_PKEY_type(int type); + int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *engine); + =head1 DESCRIPTION EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and @@ -72,6 +73,11 @@ often seen in practice. EVP_PKEY_type() returns the underlying type of the NID B<type>. For example EVP_PKEY_type(EVP_PKEY_RSA2) will return B<EVP_PKEY_RSA>. +EVP_PKEY_set1_engine() sets the ENGINE handling B<pkey> to B<engine>. It +must be called after the key algorithm and components are set up. +If B<engine> does not include an B<EVP_PKEY_METHOD> for B<pkey> an +error occurs. + =head1 NOTES In accordance with the OpenSSL naming convention the key obtained @@ -89,6 +95,9 @@ Previous versions of this document suggested using EVP_PKEY_type(pkey->type) to determine the type of a key. Since B<EVP_PKEY> is now opaque this is no longer possible: the equivalent is EVP_PKEY_base_id(pkey). +EVP_PKEY_set1_engine() is typically used by an ENGINE returning an HSM +key as part of its routine to load a private key. + =head1 RETURN VALUES EVP_PKEY_set1_RSA(), EVP_PKEY_set1_DSA(), EVP_PKEY_set1_DH() and @@ -104,6 +113,8 @@ and EVP_PKEY_assign_EC_KEY() return 1 for success and 0 for failure. EVP_PKEY_base_id(), EVP_PKEY_id() and EVP_PKEY_type() return a key type or B<NID_undef> (equivalently B<EVP_PKEY_NONE>) on error. +EVP_PKEY_set1_engine() returns 1 for success and 0 for failure. + =head1 SEE ALSO L<EVP_PKEY_new(3)> diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 34c009a..40ed8d2 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -978,6 +978,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); diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 9bb2bca..222ba3f 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -82,6 +82,7 @@ int ERR_load_EVP_strings(void); # define EVP_F_EVP_PKEY_NEW 106 # define EVP_F_EVP_PKEY_PARAMGEN 148 # define EVP_F_EVP_PKEY_PARAMGEN_INIT 149 +# define EVP_F_EVP_PKEY_SET1_ENGINE 187 # define EVP_F_EVP_PKEY_SIGN 140 # define EVP_F_EVP_PKEY_SIGN_INIT 141 # define EVP_F_EVP_PKEY_VERIFY 142 diff --git a/test/enginetest.c b/test/enginetest.c index 4e78277..be57f16 100644 --- a/test/enginetest.c +++ b/test/enginetest.c @@ -18,6 +18,7 @@ # include <openssl/buffer.h> # include <openssl/crypto.h> # include <openssl/engine.h> +# include <openssl/rsa.h> # include <openssl/err.h> static void display_engine_list(void) @@ -175,6 +176,174 @@ static int test_engines(void) ENGINE_free(block[loop]); return to_return; } + +/* Test EVP_PKEY method */ +static EVP_PKEY_METHOD *test_rsa = NULL; + +static int called_encrypt = 0; + +/* Test function to check operation has been redirected */ +static int test_encrypt(EVP_PKEY_CTX *ctx, unsigned char *sig, + size_t *siglen, const unsigned char *tbs, size_t tbslen) +{ + called_encrypt = 1; + return 1; +} + +static int test_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth, + const int **pnids, int nid) +{ + static const int rnid = EVP_PKEY_RSA; + if (pmeth == NULL) { + *pnids = &rnid; + return 1; + } + + if (nid == EVP_PKEY_RSA) { + *pmeth = test_rsa; + return 1; + } + + *pmeth = NULL; + return 0; +} + +/* Return a test EVP_PKEY value */ + +static EVP_PKEY *get_test_pkey(void) +{ + static unsigned char n[] = + "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F" + "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5" + "\xAD\xB3\x00\xA0\x28\x5E\x53\x01\x93\x0E\x0C\x70\xFB\x68\x76\x93" + "\x9C\xE6\x16\xCE\x62\x4A\x11\xE0\x08\x6D\x34\x1E\xBC\xAC\xA0\xA1" + "\xF5"; + static unsigned char e[] = "\x11"; + + RSA *rsa = RSA_new(); + EVP_PKEY *pk = EVP_PKEY_new(); + + if (rsa == NULL || pk == NULL || !EVP_PKEY_assign_RSA(pk, rsa)) { + RSA_free(rsa); + EVP_PKEY_free(pk); + return NULL; + } + + if (!RSA_set0_key(rsa, BN_bin2bn(n, sizeof(n)-1, NULL), + BN_bin2bn(e, sizeof(e)-1, NULL), NULL)) { + EVP_PKEY_free(pk); + return NULL; + } + + return pk; +} + +static int test_redirect(void) +{ + const unsigned char pt[] = "Hello World\n"; + unsigned char *tmp = NULL; + size_t len; + EVP_PKEY_CTX *ctx = NULL; + ENGINE *e = NULL; + EVP_PKEY *pkey = NULL; + + int to_return = 0; + + if (!TEST_ptr(pkey = get_test_pkey())) + goto err; + + len = EVP_PKEY_size(pkey); + if (!TEST_ptr(tmp = OPENSSL_malloc(len))) + goto err; + + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, NULL))) + goto err; + TEST_info("EVP_PKEY_encrypt test: no redirection"); + /* Encrypt some data: should succeed but not be redirected */ + if (!TEST_int_gt(EVP_PKEY_encrypt_init(ctx), 0) + || !TEST_int_gt(EVP_PKEY_encrypt(ctx, tmp, &len, pt, sizeof(pt)), 0) + || !TEST_false(called_encrypt)) + goto err; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + /* Create a test ENGINE */ + if (!TEST_ptr(e = ENGINE_new()) + || !TEST_true(ENGINE_set_id(e, "Test redirect engine")) + || !TEST_true(ENGINE_set_name(e, "Test redirect engine"))) + goto err; + + /* + * Try to create a context for this engine and test key. + * Try setting test key engine. Both should fail because the + * engine has no public key methods. + */ + if (!TEST_ptr_null(EVP_PKEY_CTX_new(pkey, e)) + || !TEST_int_le(EVP_PKEY_set1_engine(pkey, e), 0)) + goto err; + + /* Setup an empty test EVP_PKEY_METHOD and set callback to return it */ + if (!TEST_ptr(test_rsa = EVP_PKEY_meth_new(EVP_PKEY_RSA, 0))) + goto err; + ENGINE_set_pkey_meths(e, test_pkey_meths); + + /* Getting a context for test ENGINE should now succeed */ + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, e))) + goto err; + /* Encrypt should fail because operation is not supported */ + if (!TEST_int_le(EVP_PKEY_encrypt_init(ctx), 0)) + goto err; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + /* Add test encrypt operation to method */ + EVP_PKEY_meth_set_encrypt(test_rsa, 0, test_encrypt); + + TEST_info("EVP_PKEY_encrypt test: redirection via EVP_PKEY_CTX_new()"); + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, e))) + goto err; + /* Encrypt some data: should succeed and be redirected */ + if (!TEST_int_gt(EVP_PKEY_encrypt_init(ctx), 0) + || !TEST_int_gt(EVP_PKEY_encrypt(ctx, tmp, &len, pt, sizeof(pt)), 0) + || !TEST_true(called_encrypt)) + goto err; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + called_encrypt = 0; + + /* Create context with default engine: should not be redirected */ + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, NULL)) + || !TEST_int_gt(EVP_PKEY_encrypt_init(ctx), 0) + || !TEST_int_gt(EVP_PKEY_encrypt(ctx, tmp, &len, pt, sizeof(pt)), 0) + || !TEST_false(called_encrypt)) + goto err; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + /* Set engine explicitly for test key */ + if (!TEST_true(EVP_PKEY_set1_engine(pkey, e))) + goto err; + + TEST_info("EVP_PKEY_encrypt test: redirection via EVP_PKEY_set1_engine()"); + + /* Create context with default engine: should be redirected now */ + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new(pkey, NULL)) + || !TEST_int_gt(EVP_PKEY_encrypt_init(ctx), 0) + || !TEST_int_gt(EVP_PKEY_encrypt(ctx, tmp, &len, pt, sizeof(pt)), 0) + || !TEST_true(called_encrypt)) + goto err; + + to_return = 1; + + err: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + ENGINE_free(e); + OPENSSL_free(tmp); + return to_return; +} #endif int setup_tests(void) @@ -183,6 +352,7 @@ int setup_tests(void) TEST_note("No ENGINE support"); #else ADD_TEST(test_engines); + ADD_TEST(test_redirect); #endif return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 5343aed..548716d 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4400,3 +4400,4 @@ EVP_PKEY_meth_remove 4343 1_1_1 EXIST::FUNCTION: OPENSSL_sk_reserve 4344 1_1_1 EXIST::FUNCTION: CRYPTO_atomic_read 4345 1_1_1 EXIST::FUNCTION: CRYPTO_atomic_write 4346 1_1_1 EXIST::FUNCTION: +EVP_PKEY_set1_engine 4347 1_1_0g EXIST::FUNCTION:ENGINE _____ openssl-commits mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-commits