From a9b28c79e92f6194ea52c7d33213f2a0dc9bd013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Fri, 28 Jul 2023 16:15:12 +0200 Subject: [PATCH] core: Prevent wrong plaintext when verifying clearsigned signature * src/engine-gpg.c (gpg_verify): Use a separate pipe instead of stdout for reading the plaintext. * tests/gpg/t-support.h (PGM): Define if undefined. (print_data): Undefine BUF_SIZE. (check_data): New. * tests/gpg/t-verify.c (clearsigned_plus_key_block): New. (main): Add test. -- Reading the plaintext from stdout is a bad idea because gpg can also print other stuff on stdout, e.g. the keys contained in a public key block. This is fixed by reading the plaintext via a special pipe. GnuPG-bug-id: 6622 --- src/engine-gpg.c | 4 +--- tests/gpg/t-support.h | 44 +++++++++++++++++++++++++++++++++++ tests/gpg/t-verify.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 355d42fd..4314938e 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -3726,15 +3726,13 @@ gpg_verify (void *engine, gpgme_verify_flags_t flags, gpgme_data_t sig, /* Normal or cleartext signature. */ err = add_arg (gpg, "--output"); if (!err) - err = add_arg (gpg, "-"); + err = add_data (gpg, plaintext, -1, 1); if (!err) err = add_input_size_hint (gpg, sig); if (!err) err = add_arg (gpg, "--"); if (!err) err = add_file_name_arg_or_data (gpg, sig, -1, 0); - if (!err) - err = add_data (gpg, plaintext, 1, 1); } else { diff --git a/tests/gpg/t-support.h b/tests/gpg/t-support.h index b3f54e57..0c1a73ed 100644 --- a/tests/gpg/t-support.h +++ b/tests/gpg/t-support.h @@ -32,6 +32,10 @@ #include +#ifndef PGM +#define PGM "unknown program; define PGM before including t-support.h" +#endif + #ifndef DIM #define DIM(v) (sizeof(v)/sizeof((v)[0])) #endif @@ -99,6 +103,46 @@ print_data (gpgme_data_t dh) fwrite (buf, ret, 1, stdout); if (ret < 0) fail_if_err (gpgme_err_code_from_errno (errno)); +#undef BUF_SIZE +} + + +void +check_data (gpgme_data_t dh, const char *expected) +{ +#define BUF_SIZE 512 + char buf[BUF_SIZE + 1]; + int expectedlen; + int ret; + + if (!expected) + { + fprintf (stderr, "%s:%i: Expected data must not be NULL.\n", + PGM, __LINE__); + exit (1); + } + expectedlen = strlen (expected); + if (expectedlen > BUF_SIZE) + { + fprintf (stderr, "%s:%i: Size of expected data (%d) is greater than " + "BUF_SIZE (%d).\n", PGM, __LINE__, expectedlen, BUF_SIZE); + exit (1); + } + + ret = gpgme_data_seek (dh, 0, SEEK_SET); + if (ret) + fail_if_err (gpgme_err_code_from_errno (errno)); + if ((ret = gpgme_data_read (dh, buf, BUF_SIZE)) < 0) + fail_if_err (gpgme_err_code_from_errno (errno)); + buf[ret] = 0; + if (ret != expectedlen || strncmp (buf, expected, expectedlen)) + { + fprintf (stderr, "%s:%i: Got unexpected data\n", PGM, __LINE__); + fprintf (stderr, "Expected data:\n---\n%s---\n", expected); + fprintf (stderr, "Actual data:\n---\n%s---\n", buf); + exit (1); + } +#undef BUF_SIZE } diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index c89e4973..84afa9a3 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -86,6 +86,44 @@ static const char double_plaintext_sig[] = "=6+AK\n" "-----END PGP MESSAGE-----\n"; +/* A clear-signed message followed by a public key block. */ +static const char clearsigned_plus_key_block[] = +"-----BEGIN PGP SIGNED MESSAGE-----\n" +"Hash: SHA256\n" +"\n" +"bar\n" +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iQEzBAEBCAAdFiEE0MFuEqOl54V/b8HTD1vkKiPJHOMFAmTBMWMACgkQD1vkKiPJ\n" +"HONzdQf/aty0AjMuKRbI7s9oN2fTMzKglnopBBsJH/ozravsHt3NzW6qeI+JN8Ga\n" +"yMgwu7991di2q3+dHzLylL/uLxomh3TQnQTsak3kfzVJt8fKgY3lpFZamgpGQlme\n" +"r0xioe5ylaIipItt06XIeZMnwrS+dfDhAW1G6x98nSOCN+SlqmrPpVrf2+J3hLXq\n" +"4oRZExYD3WIQAOl5a6LBJ7nKxal7Y+ZzLNKo1Fdv0BSeaClVXTeUFCivZiw0zcEI\n" +"eguDK8fk7kx3MDuwQxV3+juWaMDCNNVV4QBIMZjXusv2i7vHkfTWrPy+m+CmkIJz\n" +"MEHj/W7d30v2HqNYtrwOSmMhv1+wOg==\n" +"=vlPl\n" +"-----END PGP SIGNATURE-----\n" +"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +"\n" +"mDMEYg5XKRYJKwYBBAHaRw8BAQdAoiviwSeMJbcbE8t9mHgrSqgT5F4LQyLzUckU\n" +"E6Sx5aiIgwQgFgoAKxYhBIHOfS+ZLzoe/uBZMa7qmxcSWxd7BQJiQaR2DR0BbGlu\n" +"ZTEKbGluZTIACgkQruqbFxJbF3uT1wD/UzkNkMwK/kDHxT4xxwY6OeRZdeZauGtv\n" +"vKnvcyM16V0A/0IEIlQmSKyp/OEFZy45VBunJZJkReRMS9pA0Y+ouBgKtB9KYW5l\n" +"IERvZSA8amFuZS5kb2VAZXhhbXBsZS5uZXQ+iJoEExYKAEICGwMFCQAosgcFCwkI\n" +"BwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAFiEEgc59L5kvOh7+4FkxruqbFxJbF3sF\n" +"AmLyVRUACgkQruqbFxJbF3s/cgEAqwbErDdIhKudkFrk8wY6VkNBDf4jf2SGyDz1\n" +"BL9pJt0A/0IkhlpHU6rtqylJuuCFpLmKbFlXdXdrCoEwisFrY8QJtAZibGFibGGI\n" +"nAQTFgoARAIbAwUJACiyBwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgBYhBIHO\n" +"fS+ZLzoe/uBZMa7qmxcSWxd7BQJi8lUWAhkBAAoJEK7qmxcSWxd7H+UBAP/y1phn\n" +"ojnKvF72jm7uaLN+mTVKjt71nxPi8TvBASC1AP0bt5vAiAqlCOYACvm2mg8pw18f\n" +"1YXXOBkcbTLUimkyD7g4BGIOVykSCisGAQQBl1UBBQEBB0DkecMMBdYTabaTqAbV\n" +"GlWplsf68h+uv8N78t0bEjVmGAMBCAeIfgQYFgoAJhYhBIHOfS+ZLzoe/uBZMa7q\n" +"mxcSWxd7BQJiDlcpAhsMBQkAKLIHAAoJEK7qmxcSWxd7GgsBAMvJUPcHIs4dHlqS\n" +"o2P7NfJvkFpqFUeGaP8upALUiijRAQDz13cloc0StTGn5uWPZCGQkzn8MzX+yiPZ\n" +"mxnjHfafCg==\n" +"=+jHe\n" +"-----END PGP PUBLIC KEY BLOCK-----\n"; + @@ -361,6 +399,22 @@ main (int argc, char *argv[]) exit (1); } + gpgme_data_release (sig); + gpgme_data_release (text); + + /* Checking clear-signed message followed by public key block. */ + err = gpgme_data_new_from_mem (&sig, clearsigned_plus_key_block, + strlen (clearsigned_plus_key_block), 0); + fail_if_err (err); + err = gpgme_data_new (&text); + fail_if_err (err); + err = gpgme_op_verify (ctx, sig, NULL, text); + fail_if_err (err); + result = gpgme_op_verify_result (ctx); + check_result (result, 1, 0, GPGME_SIGSUM_KEY_MISSING, + "D0C16E12A3A5E7857F6FC1D30F5BE42A23C91CE3", + GPG_ERR_NO_PUBKEY, 0, GPGME_VALIDITY_UNKNOWN); + check_data (text, "bar\n"); gpgme_data_release (sig); gpgme_data_release (text);