From 6b83d032a64848a66b60ca54729bcd79493f36ef Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Wed, 23 Sep 2020 10:19:50 +0200 Subject: [PATCH] apps/cms.c: Make -sign and -verify handle binary input Fixes #8940 Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/12959) --- apps/cms.c | 55 ++++++++++++++++++++++++++++--------- test/recipes/80-test_cms.t | 47 +++++++++++++++++++++++++++++-- test/smcont.bin | Bin 0 -> 8000 bytes 3 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 test/smcont.bin diff --git a/apps/cms.c b/apps/cms.c index f40049edac..64867e3702 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -159,7 +159,7 @@ const OPTIONS cms_options[] = { {"nodetach", OPT_NODETACH, '-', "Use opaque signing"}, {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"}, {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"}, - {"binary", OPT_BINARY, '-', "Don't translate message to text"}, + {"binary", OPT_BINARY, '-', "Treat input as binary: do not translate to canonical form"}, {"keyid", OPT_KEYID, '-', "Use subject key identifier"}, {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"}, {"nocerts", OPT_NOCERTS, '-', @@ -227,7 +227,7 @@ const OPTIONS cms_options[] = { {NULL} }; -static CMS_ContentInfo *load_content_info(int informat, BIO *in, BIO **indata, +static CMS_ContentInfo *load_content_info(int informat, BIO *in, int flags, BIO **indata, const char *name, OSSL_LIB_CTX *libctx, const char *propq) @@ -241,7 +241,7 @@ static CMS_ContentInfo *load_content_info(int informat, BIO *in, BIO **indata, } switch (informat) { case FORMAT_SMIME: - ci = SMIME_read_CMS_ex(in, indata, &ret); + ci = SMIME_read_CMS_ex(in, flags, indata, &ret); break; case FORMAT_PEM: ci = PEM_read_bio_CMS(in, &ret, NULL, NULL); @@ -263,6 +263,29 @@ err: return NULL; } +static void warn_binary(const char *file) +{ + BIO *bio; + unsigned char linebuf[1024], *cur, *end; + int len; + + if ((bio = bio_open_default(file, 'r', FORMAT_BINARY)) == NULL) + return; /* cannot give a proper warning since there is an error */ + while ((len = BIO_read(bio, linebuf, sizeof(linebuf))) > 0) { + end = linebuf + len; + for (cur = linebuf; cur < end; cur++) { + if (*cur == '\0' || *cur >= 0x80) { + BIO_printf(bio_err, "Warning: input file '%s' contains %s" + " character; better use -binary option\n", + file, *cur == '\0' ? "NUL" : "8-bit"); + break; + } + } + } + BIO_free(bio); +} + + int cms_main(int argc, char **argv) { CONF *conf = NULL; @@ -452,7 +475,7 @@ int cms_main(int argc, char **argv) OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat)) goto opthelp; } else { - rcms = load_content_info(rctformat, rctin, NULL, "recipient", + rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient", libctx, app_get0_propq()); } break; @@ -784,13 +807,12 @@ int cms_main(int argc, char **argv) if (!(operation & SMIME_SIGNERS)) flags &= ~CMS_DETACHED; - if (!(operation & SMIME_OP)) - if (flags & CMS_BINARY) + if ((flags & CMS_BINARY) != 0) { + if (!(operation & SMIME_OP)) outformat = FORMAT_BINARY; - - if (!(operation & SMIME_IP)) - if (flags & CMS_BINARY) + if (!(operation & SMIME_IP)) informat = FORMAT_BINARY; + } if (operation == SMIME_ENCRYPT) { if (!cipher) { @@ -867,16 +889,22 @@ int cms_main(int argc, char **argv) goto end; } - in = bio_open_default(infile, 'r', informat); + if ((flags & CMS_BINARY) == 0) + warn_binary(infile); + in = bio_open_default(infile, 'r', + (flags & CMS_BINARY) != 0 ? FORMAT_BINARY : informat); if (in == NULL) goto end; if (operation & SMIME_IP) { - cms = load_content_info(informat, in, &indata, "SMIME", libctx, app_get0_propq()); + cms = load_content_info(informat, in, flags, &indata, "SMIME", + libctx, app_get0_propq()); if (cms == NULL) goto end; if (contfile != NULL) { BIO_free(indata); + if ((flags & CMS_BINARY) == 0) + warn_binary(contfile); if ((indata = BIO_new_file(contfile, "rb")) == NULL) { BIO_printf(bio_err, "Can't read content file %s\n", contfile); goto end; @@ -897,13 +925,14 @@ int cms_main(int argc, char **argv) if (rctfile != NULL) { char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; + if ((rctin = BIO_new_file(rctfile, rctmode)) == NULL) { BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile); goto end; } - rcms = load_content_info(rctformat, rctin, NULL, "recipient", libctx, - app_get0_propq()); + rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient", libctx, + app_get0_propq); if (rcms == NULL) goto end; } diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index a371f21ad8..0e20b807c8 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -12,7 +12,7 @@ use warnings; use POSIX; use File::Spec::Functions qw/catfile/; -use File::Compare qw/compare_text/; +use File::Compare qw/compare_text compare/; use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/; use OpenSSL::Test::Utils; @@ -50,8 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) $no_rc2 = 1 if disabled("legacy"); -plan tests => - + 10; +plan tests => 11; unless ($no_fips) { @config = ( "-config", srctop_file("test", "fips-and-base.cnf") ); @@ -812,6 +811,48 @@ subtest "CAdES ko tests\n" => sub { } }; +subtest "CMS binary input tests\n" => sub { + my $input = srctop_file("test", "smcont.bin"); + my $signed = "smcont.signed"; + my $verified = "smcont.verified"; + my $cert = srctop_file("test", "certs", "ee-self-signed.pem"); + my $key = srctop_file("test", "certs", "ee-key.pem"); + + plan tests => 11; + + ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", + "-signer", $cert, "-inkey", $key, + "-binary", "-in", $input, "-out", $signed])), + "sign binary input with -binary"); + ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert, + "-binary", "-in", $signed, "-out", $verified])), + "verify binary input with -binary"); + is(compare($input, $verified), 0, "binary input retained with -binary"); + ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", + "-signer", $cert, "-inkey", $key, + "-in", $input, "-out", $signed])), + "sign binary input without -binary"); + ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert, + "-in", $signed, "-out", $verified])), + "verify binary input without -binary"); + is(compare($input, $verified), 1, "binary input not retained without -binary"); + ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $cert, "-crlfeol", + "-binary", "-in", $signed, "-out", $verified])), + "verify binary input wrong crlfeol"); + + ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-crlfeol", + "-signer", $cert, "-inkey", $key, + "-binary", "-in", $input, "-out", $signed.".crlf"])), + "sign binary input crlfeol"); + ok(run(app(["openssl", "cms", "-verify", "-CAfile", $cert, "-crlfeol", + "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])), + "verify binary input crlfeol"); + is(compare($input, $verified.".crlf"), 0); + ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $cert, + "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])), + "verify binary input missing crlfeol"); +}; + sub check_availability { my $tnam = shift; diff --git a/test/smcont.bin b/test/smcont.bin new file mode 100644 index 0000000000000000000000000000000000000000..2a5ce10224ce2b98b481273ef8a04cc4557a9e26 GIT binary patch literal 8000 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 literal 0 HcmV?d00001