The branch master has been updated via 3f96b687f7d27a32f37f7c6b4fdee45dae685b38 (commit) via 7fc6168b6f5d0f696b610a88004ef79ed0eaa2ba (commit) via d8025f4ac002f6de775a8c3c7936036d0722eed6 (commit) via b0002eb09ac744d0c702c85648b2517e214580ea (commit) via b8e5622809d3b3f61c4a615e51f5a8fd492ee23f (commit) from 067a3057c3aab0cdd9a3cdb13c2e0000f69a4170 (commit)
- Log ----------------------------------------------------------------- commit 3f96b687f7d27a32f37f7c6b4fdee45dae685b38 Author: Matt Caswell <m...@openssl.org> Date: Mon Sep 14 16:30:50 2020 +0100 Document 2 newly added functions Adds documentation for EVP_PKEY_get0_first_alg_name() and EVP_KEYMGMT_get0_first_name(). Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/12850) commit 7fc6168b6f5d0f696b610a88004ef79ed0eaa2ba Author: Matt Caswell <m...@openssl.org> Date: Mon Sep 14 16:13:54 2020 +0100 Test HMAC output from the dgst CLI We run two HMAC operations on the same file and confirm that both provide us with the expected values. Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/12850) commit d8025f4ac002f6de775a8c3c7936036d0722eed6 Author: Matt Caswell <m...@openssl.org> Date: Sun Sep 13 11:09:20 2020 +0100 Correctly display the signing/hmac algorithm in the dgst app In OpenSSL 1.1.1 doing an HMAC operation with (say) SHA1 would produce output like this: HMAC-SHA1(README.md)= 553154e4c0109ddc320bb495735906ad7135c2f1 Prior to this change master would instead display this like so: SHA1(README.md)= 553154e4c0109ddc320bb495735906ad7135c2f1 The problem is that dgst was using EVP_PKEY_asn1_get0_info() to get the algorithm name from the EVP_PKEY. This doesn't work with provider based keys. Instead we introduce a new EVP_PKEY_get0_first_alg_name() function, and an equivalent EVP_KEYMGMT_get0_first_name() function. Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/12850) commit b0002eb09ac744d0c702c85648b2517e214580ea Author: Matt Caswell <m...@openssl.org> Date: Fri Sep 11 16:47:53 2020 +0100 Redirect EVP_DigestInit to EVP_DigestSignInit_ex if appropriate Prior to OpenSSL 3.0 calling EVP_DigestInit_ex() on an mdctx previously initialised with EVP_DigestSignInit() would retain information about the key, and re-initialise for another sign operation. To emulate that we redirect calls to EVP_DigestInit() to EVP_DigestSignInit_ex() if appropriate. Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/12850) commit b8e5622809d3b3f61c4a615e51f5a8fd492ee23f Author: Matt Caswell <m...@openssl.org> Date: Thu Sep 10 14:46:41 2020 +0100 Don't send -1 as the length of the hmac key The dgst app was using an undocumented behaviour in the EVP_PKEY_new_raw_private_key() function when setting a key length for a MAC. The old EVP_PKEY to MAC bridge, probably by accident, converts a -1 length to a strlen() call, by virtue of the fact that it eventually calls ASN1_STRING_set() which has this feature. As noted above this is undocumented, and unexpected since the len parameter to EVP_PKEY_new_raw_private_key() is an unsigned value (size_t). In the old bridge it was later (silently) cast to an int, and therefore the original -1 value was restored. This only works because sizeof(int) <= sizeof(size_t). If we ever run on a platform where sizeof(int) > sizeof(size_t) then it would have failed. The behaviour also doesn't hold for EVP_PKEY_new_raw_private_key() in general - only when the old MAC bridge was in use. Rather than restore the original behaviour I think it is best to simply fix the dgst app to not assume it exists. We should not bake in this backwards and inconsistent behaviour. Fixes #12837 Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/12850) ----------------------------------------------------------------------- Summary of changes: apps/dgst.c | 12 ++++-------- crypto/evp/digest.c | 19 +++++++++++++++++++ crypto/evp/evp_pkey.c | 17 +++++++++++++++++ crypto/evp/keymgmt_meth.c | 5 +++++ doc/man3/EVP_KEYMGMT.pod | 11 +++++++++++ doc/man3/EVP_PKEY_is_a.pod | 16 +++++++++++++++- include/openssl/evp.h | 3 +++ test/recipes/20-test_dgst.t | 16 +++++++++++++++- util/libcrypto.num | 2 ++ 9 files changed, 91 insertions(+), 10 deletions(-) diff --git a/apps/dgst.c b/apps/dgst.c index 0bbde71d4b..650115b468 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -319,7 +319,8 @@ int dgst_main(int argc, char **argv) if (hmac_key != NULL) { sigkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, impl, - (unsigned char *)hmac_key, -1); + (unsigned char *)hmac_key, + strlen(hmac_key)); if (sigkey == NULL) goto end; } @@ -405,13 +406,8 @@ int dgst_main(int argc, char **argv) } else { const char *sig_name = NULL; if (!out_bin) { - if (sigkey != NULL) { - const EVP_PKEY_ASN1_METHOD *ameth; - ameth = EVP_PKEY_get0_asn1(sigkey); - if (ameth) - EVP_PKEY_asn1_get0_info(NULL, NULL, - NULL, NULL, &sig_name, ameth); - } + if (sigkey != NULL) + sig_name = EVP_PKEY_get0_first_alg_name(sigkey); } ret = 0; for (i = 0; i < argc; i++) { diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index a177abdb67..fb29ab5f08 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -140,6 +140,25 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) ENGINE *tmpimpl = NULL; #endif +#if !defined(FIPS_MODULE) + if (ctx->pctx != NULL + && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx) + && ctx->pctx->op.sig.sigprovctx != NULL) { + /* + * Prior to OpenSSL 3.0 calling EVP_DigestInit_ex() on an mdctx + * previously initialised with EVP_DigestSignInit() would retain + * information about the key, and re-initialise for another sign + * operation. So in that case we redirect to EVP_DigestSignInit() + */ + if (ctx->pctx->operation == EVP_PKEY_OP_SIGNCTX) + return EVP_DigestSignInit(ctx, NULL, type, impl, NULL); + if (ctx->pctx->operation == EVP_PKEY_OP_VERIFYCTX) + return EVP_DigestVerifyInit(ctx, NULL, type, impl, NULL); + EVPerr(0, EVP_R_UPDATE_ERROR); + return 0; + } +#endif + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); if (ctx->provctx != NULL) { diff --git a/crypto/evp/evp_pkey.c b/crypto/evp/evp_pkey.c index d435c86087..f31d1d68f8 100644 --- a/crypto/evp/evp_pkey.c +++ b/crypto/evp/evp_pkey.c @@ -163,3 +163,20 @@ int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, return 1; return 0; } + +const char *EVP_PKEY_get0_first_alg_name(const EVP_PKEY *key) +{ + const EVP_PKEY_ASN1_METHOD *ameth; + const char *name = NULL; + + if (key->keymgmt != NULL) + return EVP_KEYMGMT_get0_first_name(key->keymgmt); + + /* Otherwise fallback to legacy */ + ameth = EVP_PKEY_get0_asn1(key); + if (ameth != NULL) + EVP_PKEY_asn1_get0_info(NULL, NULL, + NULL, NULL, &name, ameth); + + return name; +} diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c index 1459b64f0e..5453ceadda 100644 --- a/crypto/evp/keymgmt_meth.c +++ b/crypto/evp/keymgmt_meth.c @@ -249,6 +249,11 @@ int EVP_KEYMGMT_number(const EVP_KEYMGMT *keymgmt) return keymgmt->name_id; } +const char *EVP_KEYMGMT_get0_first_name(const EVP_KEYMGMT *keymgmt) +{ + return evp_first_name(keymgmt->prov, keymgmt->name_id); +} + int EVP_KEYMGMT_is_a(const EVP_KEYMGMT *keymgmt, const char *name) { return evp_is_a(keymgmt->prov, keymgmt->name_id, NULL, name); diff --git a/doc/man3/EVP_KEYMGMT.pod b/doc/man3/EVP_KEYMGMT.pod index 8e7afc6a22..d06b9ba369 100644 --- a/doc/man3/EVP_KEYMGMT.pod +++ b/doc/man3/EVP_KEYMGMT.pod @@ -9,6 +9,7 @@ EVP_KEYMGMT_free, EVP_KEYMGMT_provider, EVP_KEYMGMT_is_a, EVP_KEYMGMT_number, +EVP_KEYMGMT_get0_first_name, EVP_KEYMGMT_do_all_provided, EVP_KEYMGMT_names_do_all, EVP_KEYMGMT_gettable_params, @@ -29,6 +30,8 @@ EVP_KEYMGMT_gen_settable_params const OSSL_PROVIDER *EVP_KEYMGMT_provider(const EVP_KEYMGMT *keymgmt); int EVP_KEYMGMT_is_a(const EVP_KEYMGMT *keymgmt, const char *name); int EVP_KEYMGMT_number(const EVP_KEYMGMT *keymgmt); + const char *EVP_KEYMGMT_get0_first_name(const EVP_KEYMGMT *keymgmt); + void EVP_KEYMGMT_do_all_provided(OPENSSL_CTX *libctx, void (*fn)(EVP_KEYMGMT *keymgmt, void *arg), void *arg); @@ -69,6 +72,12 @@ algorithm that's identifiable with I<name>. EVP_KEYMGMT_number() returns the internal dynamic number assigned to the I<keymgmt>. +EVP_KEYMGMT_get0_first_name() returns the first algorithm name that is found for +the given I<keymgmt>. Note that the I<keymgmt> may have multiple synonyms +associated with it. In this case it is undefined which one will be returned. +Ownership of the returned string is retained by the I<keymgmt> object and should +not be freed by the caller. + EVP_KEYMGMT_names_do_all() traverses all names for the I<keymgmt>, and calls I<fn> with each name and I<data>. @@ -111,6 +120,8 @@ otherwise 0. EVP_KEYMGMT_number() returns an integer. +EVP_KEYMGMT_get0_first_name() returns the name that is found or NULL on error. + EVP_KEYMGMT_gettable_params(), EVP_KEYMGMT_settable_params() and EVP_KEYMGMT_gen_settable_params() return a constant B<OSSL_PARAM> array or NULL on error. diff --git a/doc/man3/EVP_PKEY_is_a.pod b/doc/man3/EVP_PKEY_is_a.pod index cfce3de5da..efc72ea110 100644 --- a/doc/man3/EVP_PKEY_is_a.pod +++ b/doc/man3/EVP_PKEY_is_a.pod @@ -2,7 +2,7 @@ =head1 NAME -EVP_PKEY_is_a, EVP_PKEY_can_sign +EVP_PKEY_is_a, EVP_PKEY_can_sign, EVP_PKEY_get0_first_alg_name - key type and capabilities functions =head1 SYNOPSIS @@ -11,6 +11,8 @@ EVP_PKEY_is_a, EVP_PKEY_can_sign int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name); int EVP_PKEY_can_sign(const EVP_PKEY *pkey); + const char *EVP_PKEY_get0_first_alg_name(const EVP_PKEY *key); + =head1 DESCRIPTION @@ -20,6 +22,12 @@ EVP_PKEY_can_sign() checks if the functionality for the key type of I<pkey> supports signing. No other check is done, such as whether I<pkey> contains a private key. +EVP_PKEY_get0_first_alg_name() returns the first algorithm name that is found +for the given I<pkey>. Note that the I<pkey> may have multiple synonyms +associated with it. In this case it is undefined which one will be returned. +Ownership of the returned string is retained by the I<pkey> object and should +not be freed by the caller. + =head1 RETURN VALUES EVP_PKEY_is_a() returns 1 if I<pkey> has the key type I<name>, @@ -28,6 +36,8 @@ otherwise 0. EVP_PKEY_can_sign() returns 1 if the I<pkey> key type functionality supports signing, otherwise 0. +EVP_PKEY_get0_first_alg_name() returns the name that is found or NULL on error. + =head1 EXAMPLES =head2 EVP_PKEY_is_a() @@ -60,6 +70,10 @@ this as an crude example: } /* Sign something... */ +=head1 HISTORY + +The functions described here were added in OpenSSL 3.0. + =head1 COPYRIGHT Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 4d0cc9d560..ff97198542 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1496,6 +1496,8 @@ int EVP_PKEY_CTX_set1_id(EVP_PKEY_CTX *ctx, const void *id, int len); int EVP_PKEY_CTX_get1_id(EVP_PKEY_CTX *ctx, void *id); int EVP_PKEY_CTX_get1_id_len(EVP_PKEY_CTX *ctx, size_t *id_len); +const char *EVP_PKEY_get0_first_alg_name(const EVP_PKEY *key); + # define EVP_PKEY_OP_UNDEFINED 0 # define EVP_PKEY_OP_PARAMGEN (1<<1) # define EVP_PKEY_OP_KEYGEN (1<<2) @@ -1573,6 +1575,7 @@ EVP_KEYMGMT *EVP_KEYMGMT_fetch(OPENSSL_CTX *ctx, const char *algorithm, 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); +const char *EVP_KEYMGMT_get0_first_name(const EVP_KEYMGMT *keymgmt); int EVP_KEYMGMT_number(const EVP_KEYMGMT *keymgmt); int EVP_KEYMGMT_is_a(const EVP_KEYMGMT *keymgmt, const char *name); void EVP_KEYMGMT_do_all_provided(OPENSSL_CTX *libctx, diff --git a/test/recipes/20-test_dgst.t b/test/recipes/20-test_dgst.t index 0b7ab2d5d1..9dcf6d31a2 100644 --- a/test/recipes/20-test_dgst.t +++ b/test/recipes/20-test_dgst.t @@ -17,7 +17,7 @@ use OpenSSL::Test::Utils; setup("test_dgst"); -plan tests => 5; +plan tests => 6; sub tsignverify { my $testtext = shift; @@ -102,3 +102,17 @@ SKIP: { srctop_file("test","tested448pub.pem")); }; } + +subtest "HMAC generation with `dgst` CLI" => sub { + plan tests => 2; + + my $testdata = srctop_file('test', 'data.txt'); + #HMAC the data twice to check consistency + my @hmacdata = run(app(['openssl', 'dgst', '-sha256', '-hmac', '123456', + $testdata, $testdata]), capture => 1); + chomp(@hmacdata); + my $expected = qr/HMAC-SHA256\([^\)]*data.txt\)= 6f12484129c4a761747f13d8234a1ff0e074adb34e9e9bf3a155c391b97b9a7c/; + ok($hmacdata[0] =~ $expected, "HMAC: Check HMAC value is as expected ($hmacdata[0]) vs ($expected)"); + ok($hmacdata[1] =~ $expected, + "HMAC: Check second HMAC value is consistent with the first ($hmacdata[1]) vs ($expected)"); +}; diff --git a/util/libcrypto.num b/util/libcrypto.num index 6070b570a5..a1b8ce0be1 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5280,3 +5280,5 @@ EVP_PKEY_CTX_get1_id_len ? 3_0_0 EXIST::FUNCTION: CMS_AuthEnvelopedData_create ? 3_0_0 EXIST::FUNCTION:CMS CMS_AuthEnvelopedData_create_with_libctx ? 3_0_0 EXIST::FUNCTION:CMS EVP_PKEY_CTX_set_ec_param_enc ? 3_0_0 EXIST::FUNCTION:EC +EVP_PKEY_get0_first_alg_name ? 3_0_0 EXIST::FUNCTION: +EVP_KEYMGMT_get0_first_name ? 3_0_0 EXIST::FUNCTION: