The branch master has been updated via c39f43534d4f359bdfee617f70f89b114c9f2cca (commit) from b03da688a223c18b5a10b5a66abe229bbb590133 (commit)
- Log ----------------------------------------------------------------- commit c39f43534d4f359bdfee617f70f89b114c9f2cca Author: Daiki Ueno <du...@redhat.com> Date: Mon Oct 26 13:23:14 2020 +0100 openssl dgst: add option to specify output length for XOF This adds the -xoflen option to control the output length of the XOF algorithms, such as SHAKE128 and SHAKE256. Reviewed-by: Matt Caswell <m...@openssl.org> Reviewed-by: Tomas Mraz <tm...@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/13245) ----------------------------------------------------------------------- Summary of changes: apps/dgst.c | 54 +++++++++++++++++++++++++++++++++++--------- doc/man1/openssl-dgst.pod.in | 5 ++++ test/recipes/20-test_dgst.t | 18 +++++++++++++-- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/apps/dgst.c b/apps/dgst.c index badcfdf0e2..4adf9cd9b4 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -24,7 +24,7 @@ #undef BUFSIZE #define BUFSIZE 1024*8 -int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, +int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, const char *file); @@ -40,7 +40,7 @@ typedef enum OPTION_choice { OPT_C, OPT_R, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY, OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL, OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT, - OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, + OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT, OPT_XOFLEN, OPT_DIGEST, OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; @@ -65,6 +65,7 @@ const OPTIONS dgst_options[] = { {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"}, {"hex", OPT_HEX, '-', "Print as hex dump"}, {"binary", OPT_BINARY, '-', "Print in binary form"}, + {"xoflen", OPT_XOFLEN, 'p', "Output length for XOF algorithms"}, {"d", OPT_DEBUG, '-', "Print debug info"}, {"debug", OPT_DEBUG, '-', "Print debug info"}, @@ -105,6 +106,7 @@ int dgst_main(int argc, char **argv) OPTION_CHOICE o; int separator = 0, debug = 0, keyform = FORMAT_PEM, siglen = 0; int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = 0; + int xoflen = 0; unsigned char *buf = NULL, *sigbuf = NULL; int engine_impl = 0; struct doall_dgst_digests dec; @@ -180,6 +182,9 @@ int dgst_main(int argc, char **argv) case OPT_BINARY: out_bin = 1; break; + case OPT_XOFLEN: + xoflen = atoi(opt_arg()); + break; case OPT_DEBUG: debug = 1; break; @@ -399,9 +404,20 @@ int dgst_main(int argc, char **argv) if (md != NULL) md_name = EVP_MD_name(md); + if (xoflen > 0) { + if (!(EVP_MD_flags(md) & EVP_MD_FLAG_XOF)) { + BIO_printf(bio_err, "Length can only be specified for XOF\n"); + goto end; + } + if (sigkey != NULL) { + BIO_printf(bio_err, "Signing key cannot be specified for XOF\n"); + goto end; + } + } + if (argc == 0) { BIO_set_fp(in, stdin, BIO_NOCLOSE); - ret = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, + ret = do_fp(out, buf, inp, separator, out_bin, xoflen, sigkey, sigbuf, siglen, NULL, md_name, "stdin"); } else { const char *sig_name = NULL; @@ -417,8 +433,8 @@ int dgst_main(int argc, char **argv) ret++; continue; } else { - r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, - siglen, sig_name, md_name, argv[i]); + r = do_fp(out, buf, inp, separator, out_bin, xoflen, + sigkey, sigbuf, siglen, sig_name, md_name, argv[i]); } if (r) ret = r; @@ -504,14 +520,14 @@ static const char *newline_escape_filename(const char *file, int * backslash) } -int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, +int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, int xoflen, EVP_PKEY *key, unsigned char *sigin, int siglen, const char *sig_name, const char *md_name, const char *file) { size_t len = BUFSIZE; int i, backslash = 0, ret = 1; - unsigned char *sigbuf = NULL; + unsigned char *allocated_buf = NULL; while (BIO_pending(bp) || !BIO_eof(bp)) { i = BIO_read(bp, (char *)buf, BUFSIZE); @@ -552,14 +568,30 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, } if (tmplen > BUFSIZE) { len = tmplen; - sigbuf = app_malloc(len, "Signature buffer"); - buf = sigbuf; + allocated_buf = app_malloc(len, "Signature buffer"); + buf = allocated_buf; } if (!EVP_DigestSignFinal(ctx, buf, &len)) { BIO_printf(bio_err, "Error Signing Data\n"); ERR_print_errors(bio_err); goto end; } + } else if (xoflen > 0) { + EVP_MD_CTX *ctx; + + len = xoflen; + if (len > BUFSIZE) { + allocated_buf = app_malloc(len, "Digest buffer"); + buf = allocated_buf; + } + + BIO_get_md_ctx(bp, &ctx); + + if (!EVP_DigestFinalXOF(ctx, buf, len)) { + BIO_printf(bio_err, "Error Digesting Data\n"); + ERR_print_errors(bio_err); + goto end; + } } else { len = BIO_gets(bp, (char *)buf, BUFSIZE); if ((int)len < 0) { @@ -602,8 +634,8 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, ret = 0; end: - if (sigbuf != NULL) - OPENSSL_clear_free(sigbuf, len); + if (allocated_buf != NULL) + OPENSSL_clear_free(allocated_buf, len); return ret; } diff --git a/doc/man1/openssl-dgst.pod.in b/doc/man1/openssl-dgst.pod.in index 4667aeea34..533f30725c 100644 --- a/doc/man1/openssl-dgst.pod.in +++ b/doc/man1/openssl-dgst.pod.in @@ -16,6 +16,7 @@ B<openssl> B<dgst>|I<digest> [B<-list>] [B<-hex>] [B<-binary>] +[B<-xoflen> I<length>] [B<-r>] [B<-out> I<filename>] [B<-sign> I<filename>] @@ -84,6 +85,10 @@ signatures using B<-hex>. Output the digest or signature in binary form. +=item B<-xoflen> I<length> + +Set the output length for XOF algorithms, such as B<shake128>. + =item B<-r> =for openssl foreign manual sha1sum(1) diff --git a/test/recipes/20-test_dgst.t b/test/recipes/20-test_dgst.t index 4c29877e62..0c19c029a0 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 => 6; +plan tests => 7; sub tsignverify { my $testtext = shift; @@ -111,8 +111,22 @@ subtest "HMAC generation with `dgst` CLI" => sub { my @hmacdata = run(app(['openssl', 'dgst', '-sha256', '-hmac', '123456', $testdata, $testdata]), capture => 1); chomp(@hmacdata); - my $expected = qr/HMAC-SHA256\([^\)]*data.bin\)= 6f12484129c4a761747f13d8234a1ff0e074adb34e9e9bf3a155c391b97b9a7c/; + my $expected = qr/HMAC-SHA256\(\Q$testdata\E\)= 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)"); }; + +subtest "Custom length XOF digest generation with `dgst` CLI" => sub { + plan tests => 2; + + my $testdata = srctop_file('test', 'data.bin'); + #Digest the data twice to check consistency + my @xofdata = run(app(['openssl', 'dgst', '-shake128', '-xoflen', '64', + $testdata, $testdata]), capture => 1); + chomp(@xofdata); + my $expected = qr/SHAKE128\(\Q$testdata\E\)= bb565dac72640109e1c926ef441d3fa64ffd0b3e2bf8cd73d5182dfba19b6a8a2eab96d2df854b647b3795ef090582abe41ba4e0717dc4df40bc4e17d88e4677/; + ok($xofdata[0] =~ $expected, "XOF: Check digest value is as expected ($xofdata[0]) vs ($expected)"); + ok($xofdata[1] =~ $expected, + "XOF: Check second digest value is consistent with the first ($xofdata[1]) vs ($expected)"); +};