From f7700a016926f0d8e9cb3c0337837deb7fe01079 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 09:17:27 +0200 Subject: core: Add new context flag "no-symkey-cache". * src/gpgme.c (gpgme_set_ctx_flag): Set flag. (gpgme_get_ctx_flag): Get flag. * src/context.h (struct gpgme_context): Add field no_symkey_cache. * src/engine-gpg.c (struct engine_gpg): Ditto. (gpg_set_engine_flags): Set flag. (build_argv): Pass option --no-symkey-cache to gpg. * tests/run-decrypt.c (print_result): Fix segv for symmetric messages. (main): New option --no-symkey-cache. * tests/run-encrypt.c (main): New option --no-symkey-cache. Signed-off-by: Werner Koch --- tests/run-decrypt.c | 20 +++++++++++++++++++- tests/run-encrypt.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 12 deletions(-) (limited to 'tests') diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index f4c47544..a2e82a0e 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -60,7 +60,7 @@ print_result (gpgme_decrypt_result_t result) if (result->session_key) printf ("Session key: %s\n", result->session_key); - for (recp = result->recipients; recp->next; recp = recp->next) + for (recp = result->recipients; recp && recp->next; recp = recp->next) { printf ("recipient %d\n", count++); printf (" status ....: %s\n", gpgme_strerror (recp->status)); @@ -82,6 +82,7 @@ show_usage (int ex) " --export-session-key show the session key\n" " --override-session-key STRING use STRING as session key\n" " --request-origin STRING use STRING as request origin\n" + " --no-symkey-cache disable the use of that cache\n" " --unwrap remove only the encryption layer\n" , stderr); exit (ex); @@ -104,6 +105,7 @@ main (int argc, char **argv) int export_session_key = 0; const char *override_session_key = NULL; const char *request_origin = NULL; + int no_symkey_cache = 0; int raw_output = 0; if (argc) @@ -160,6 +162,11 @@ main (int argc, char **argv) request_origin = *argv; argc--; argv++; } + else if (!strcmp (*argv, "--no-symkey-cache")) + { + no_symkey_cache = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--unwrap")) { flags |= GPGME_DECRYPT_UNWRAP; @@ -226,6 +233,17 @@ main (int argc, char **argv) } } + if (no_symkey_cache) + { + err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1"); + if (err) + { + fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n", + gpgme_strerror (err)); + exit (1); + } + } + err = gpgme_data_new_from_stream (&in, fp_in); if (err) { diff --git a/tests/run-encrypt.c b/tests/run-encrypt.c index e949d760..51e2d60f 100644 --- a/tests/run-encrypt.c +++ b/tests/run-encrypt.c @@ -80,17 +80,18 @@ show_usage (int ex) { fputs ("usage: " PGM " [options] FILE\n\n" "Options:\n" - " --verbose run in verbose mode\n" - " --status print status lines from the backend\n" - " --progress print progress info\n" - " --openpgp use the OpenPGP protocol (default)\n" - " --cms use the CMS protocol\n" - " --uiserver use the UI server\n" - " --loopback use a loopback pinentry\n" - " --key NAME encrypt to key NAME\n" - " --throw-keyids use this option\n" - " --wrap assume input is valid OpenPGP message\n" - " --symmetric encrypt symmetric (OpenPGP only)\n" + " --verbose run in verbose mode\n" + " --status print status lines from the backend\n" + " --progress print progress info\n" + " --openpgp use the OpenPGP protocol (default)\n" + " --cms use the CMS protocol\n" + " --uiserver use the UI server\n" + " --loopback use a loopback pinentry\n" + " --key NAME encrypt to key NAME\n" + " --throw-keyids use this option\n" + " --no-symkey-cache disable the use of that cache\n" + " --wrap assume input is valid OpenPGP message\n" + " --symmetric encrypt symmetric (OpenPGP only)\n" , stderr); exit (ex); } @@ -115,6 +116,7 @@ main (int argc, char **argv) int i; gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST; gpgme_off_t offset; + int no_symkey_cache = 0; if (argc) { argc--; argv++; } @@ -192,6 +194,11 @@ main (int argc, char **argv) flags |= GPGME_ENCRYPT_SYMMETRIC; argc--; argv++; } + else if (!strcmp (*argv, "--no-symkey-cache")) + { + no_symkey_cache = 1; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -227,6 +234,16 @@ main (int argc, char **argv) gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK); gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); } + if (no_symkey_cache) + { + err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1"); + if (err) + { + fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n", + gpgme_strerror (err)); + exit (1); + } + } for (i=0; i < keycount; i++) { -- cgit From bdf7cd2e28432cf0fa7e0758acdfee03d7bfd45f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 15:39:20 +0200 Subject: tests: Add another check to gpg/t-verify. * tests/gpg/t-verify.c (PGM): New. Use it instead of __FILE__. (test_sig1_plus_unknown_key): New test signature. (check_result): Allow checking of several signatures. (main): Check a signature with a know and an unknown key. Signed-off-by: Werner Koch --- tests/gpg/t-verify.c | 136 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 52 deletions(-) (limited to 'tests') diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index f955cc9d..ffc41eeb 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -31,31 +31,14 @@ #include +#define PGM "t-verify" #include "t-support.h" + static const char test_text1[] = "Just GNU it!\n"; static const char test_text1f[]= "Just GNU it?\n"; static const char test_sig1[] = -#if 0 -"-----BEGIN PGP SIGNATURE-----\n" -"\n" -"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n" -"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n" -"=yku6\n" -"-----END PGP SIGNATURE-----\n" -#elif 0 -"-----BEGIN PGP SIGNATURE-----\n" -"Version: GnuPG v1.0.4-2 (GNU/Linux)\n" -"Comment: For info see http://www.gnupg.org\n" -"\n" -"iJcEABECAFcFAjoS8/E1FIAAAAAACAAkZm9vYmFyLjF0aGlzIGlzIGEgbm90YXRp\n" -"b24gZGF0YSB3aXRoIDIgbGluZXMaGmh0dHA6Ly93d3cuZ3Uub3JnL3BvbGljeS8A\n" -"CgkQLXJ8x2hpdzQLyQCbBW/fgU8ZeWSlWPM1F8umHX17bAAAoIfSNDSp5zM85XcG\n" -"iwxMrf+u8v4r\n" -"=88Zo\n" -"-----END PGP SIGNATURE-----\n" -#elif 1 "-----BEGIN PGP SIGNATURE-----\n" "\n" "iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n" @@ -64,9 +47,24 @@ static const char test_sig1[] = "Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n" "dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==\n" "=nts1\n" -"-----END PGP SIGNATURE-----\n" -#endif -; +"-----END PGP SIGNATURE-----\n"; + +/* The same as test_sig1 but with a second signature for which we do + * not have the public key (deleted after signature creation). */ +static const char test_sig1_plus_unknown_key[] = +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n" +"bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv\n" +"b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw\n" +"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n" +"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaIh1BAAWCAAdFiEENuwqcMZC\n" +"brD85btN+RyY8EnUIEwFAlrPR4cACgkQ+RyY8EnUIEyiuAEAm41LJTGUFDzhavRm\n" +"jNwqUZxGGOySduW+u/X1lEfV+MYA/2lJOo75rHtD1EG+tkFVWt4Ukj0rjhR132vZ\n" +"IOtrYAcG\n" +"=yYwZ\n" +"-----END PGP SIGNATURE-----\n"; + static const char test_sig2[] = "-----BEGIN PGP MESSAGE-----\n" "\n" @@ -91,37 +89,51 @@ static const char double_plaintext_sig[] = +/* NO_OF_SIGS is the expected number of signatures. SKIP_SKIPS is + * which of these signatures to check (0 based). */ static void -check_result (gpgme_verify_result_t result, unsigned int summary, - const char *fpr, +check_result (gpgme_verify_result_t result, int no_of_sigs, int skip_sigs, + unsigned int summary, const char *fpr, gpgme_error_t status, int notation) { gpgme_signature_t sig; + int n; sig = result->signatures; - if (!sig || sig->next) + for (n=0; sig; sig = sig->next) + n++; + if (n != no_of_sigs) { - fprintf (stderr, "%s:%i: Unexpected number of signatures\n", - __FILE__, __LINE__); + fprintf (stderr, "%s:%i: Unexpected number of signatures" + " (got %d expected %d)\n", PGM, __LINE__, n, no_of_sigs); exit (1); } + if (skip_sigs >= n) + { + fprintf (stderr, "%s:%i: oops SKIPP_SIGS to high\n", PGM, __LINE__); + exit (1); + } + + for (n=0, sig = result->signatures; n < skip_sigs; sig = sig->next, n++) + ; + if (sig->summary != summary) { - fprintf (stderr, "%s:%i: Unexpected signature summary: " + fprintf (stderr, "%s:%i:sig-%d: Unexpected signature summary: " "want=0x%x have=0x%x\n", - __FILE__, __LINE__, summary, sig->summary); + PGM, __LINE__, skip_sigs, summary, sig->summary); exit (1); } if (strcmp (sig->fpr, fpr)) { - fprintf (stderr, "%s:%i: Unexpected fingerprint: %s\n", - __FILE__, __LINE__, sig->fpr); + fprintf (stderr, "%s:%i:sig-%d: Unexpected fingerprint: %s\n", + PGM, __LINE__, skip_sigs, sig->fpr); exit (1); } if (gpgme_err_code (sig->status) != status) { - fprintf (stderr, "%s:%i: Unexpected signature status: %s\n", - __FILE__, __LINE__, gpgme_strerror (sig->status)); + fprintf (stderr, "%s:%i:sig-%d: Unexpected signature status: %s\n", + PGM, __LINE__, skip_sigs, gpgme_strerror (sig->status)); exit (1); } if (notation) @@ -166,8 +178,8 @@ check_result (gpgme_verify_result_t result, unsigned int summary, } if (!any) { - fprintf (stderr, "%s:%i: Unexpected notation data\n", - __FILE__, __LINE__); + fprintf (stderr, "%s:%i:sig-%d: Unexpected notation data\n", + PGM, __LINE__, skip_sigs); exit (1); } } @@ -175,28 +187,30 @@ check_result (gpgme_verify_result_t result, unsigned int summary, { if (expected_notations[i].seen != 1) { - fprintf (stderr, "%s:%i: Missing or duplicate notation data\n", - __FILE__, __LINE__); + fprintf (stderr, "%s:%i:sig-%d: " + "Missing or duplicate notation data\n", + PGM, __LINE__, skip_sigs); exit (1); } } } if (sig->wrong_key_usage) { - fprintf (stderr, "%s:%i: Unexpectedly wrong key usage\n", - __FILE__, __LINE__); + fprintf (stderr, "%s:%i:sig-%d: Unexpectedly wrong key usage\n", + PGM, __LINE__, skip_sigs); exit (1); } if (sig->validity != GPGME_VALIDITY_UNKNOWN) { - fprintf (stderr, "%s:%i: Unexpected validity: %i\n", - __FILE__, __LINE__, sig->validity); + fprintf (stderr, "%s:%i:sig-%d: Unexpected validity: %i\n", + PGM, __LINE__, skip_sigs, sig->validity); exit (1); } if (gpgme_err_code (sig->validity_reason) != GPG_ERR_NO_ERROR) { - fprintf (stderr, "%s:%i: Unexpected validity reason: %s\n", - __FILE__, __LINE__, gpgme_strerror (sig->validity_reason)); + fprintf (stderr, "%s:%i:sig-%d: Unexpected validity reason: %s\n", + PGM, __LINE__, skip_sigs, + gpgme_strerror (sig->validity_reason)); exit (1); } } @@ -227,7 +241,7 @@ main (int argc, char *argv[]) err = gpgme_op_verify (ctx, sig, text, NULL); fail_if_err (err); result = gpgme_op_verify_result (ctx); - check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", + check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", GPG_ERR_NO_ERROR, 1); /* Checking a manipulated message. */ @@ -238,9 +252,27 @@ main (int argc, char *argv[]) err = gpgme_op_verify (ctx, sig, text, NULL); fail_if_err (err); result = gpgme_op_verify_result (ctx); - check_result (result, GPGME_SIGSUM_RED, "2D727CC768697734", + check_result (result, 1, 0, GPGME_SIGSUM_RED, "2D727CC768697734", GPG_ERR_BAD_SIGNATURE, 0); + /* Checking a valid message. Bu that one has a second signature + * made by an unknown key. */ + gpgme_data_release (text); + gpgme_data_release (sig); + err = gpgme_data_new_from_mem (&text, test_text1, strlen (test_text1), 0); + fail_if_err (err); + err = gpgme_data_new_from_mem (&sig, test_sig1_plus_unknown_key, + strlen (test_sig1_plus_unknown_key), 0); + fail_if_err (err); + err = gpgme_op_verify (ctx, sig, text, NULL); + fail_if_err (err); + result = gpgme_op_verify_result (ctx); + check_result (result, 2, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", + GPG_ERR_NO_ERROR, 1); + check_result (result, 2, 1, 0, "36EC2A70C6426EB0FCE5BB4DF91C98F049D4204C", + GPG_ERR_NO_ERROR, 0); + + /* Checking a normal signature. */ gpgme_data_release (sig); gpgme_data_release (text); @@ -251,7 +283,7 @@ main (int argc, char *argv[]) err = gpgme_op_verify (ctx, sig, NULL, text); fail_if_err (err); result = gpgme_op_verify_result (ctx); - check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", + check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", GPG_ERR_NO_ERROR, 0); @@ -267,7 +299,7 @@ main (int argc, char *argv[]) if (gpgme_err_code (err) != GPG_ERR_BAD_DATA) { fprintf (stderr, "%s:%i: Double plaintext message not detected\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } @@ -278,7 +310,7 @@ main (int argc, char *argv[]) if (!s || strcmp (s, "foo@example.org")) { fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } @@ -288,7 +320,7 @@ main (int argc, char *argv[]) if (!s || strcmp (s, "bar@example.org")) { fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } @@ -298,7 +330,7 @@ main (int argc, char *argv[]) if (!s || strcmp (s, "foo@example.org")) { fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } @@ -306,7 +338,7 @@ main (int argc, char *argv[]) if (gpgme_err_code (err) != GPG_ERR_INV_VALUE) { fprintf (stderr, "%s:%i: gpgme_set_sender didn't detect bogus address\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } /* (the former address should still be there.) */ @@ -314,7 +346,7 @@ main (int argc, char *argv[]) if (!s || strcmp (s, "foo@example.org")) { fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", - __FILE__, __LINE__); + PGM, __LINE__); exit (1); } -- cgit From ee8fad3ea0cbc82f31c86b3483abd8549df62b69 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 15:59:22 +0200 Subject: tests: Avoid segv in run-verify due to Policy URLs * tests/run-verify.c (print_result): Take care of Policy URLs. Signed-off-by: Werner Koch --- tests/run-verify.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/run-verify.c b/tests/run-verify.c index b22e6446..699bfd1f 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -163,15 +163,22 @@ print_result (gpgme_verify_result_t result) ); for (nt = sig->notations; nt; nt = nt->next) { - printf (" notation ..: '%s'\n", nt->name); - if (strlen (nt->name) != nt->name_len) - printf (" warning : name larger (%d)\n", nt->name_len); - printf (" flags ...:%s%s (0x%02x)\n", - nt->critical? " critical":"", - nt->human_readable? " human":"", - nt->flags); - if (nt->value) - printf (" value ...: '%s'\n", nt->value); + if (nt->name) + { + printf (" notation ..: '%s'\n", nt->name); + if (strlen (nt->name) != nt->name_len) + printf (" warning : name larger (%d)\n", nt->name_len); + printf (" flags ...:%s%s (0x%02x)\n", + nt->critical? " critical":"", + nt->human_readable? " human":"", + nt->flags); + if (nt->value) + printf (" value ...: '%s'\n", nt->value); + } + else + { + printf (" policy ....: '%s'\n", nt->value); + } if ((nt->value?strlen (nt->value):0) != nt->value_len) printf (" warning : value larger (%d)\n", nt->value_len); } -- cgit From b99502274ae5efdf6df0d967900ec3d1e64373d7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 20:36:30 +0200 Subject: core: Tweak STATUS_FAILURE handling. * src/op-support.c (_gpgme_parse_failure): Ignore failures with location "gpg-exit". * tests/gpg/t-verify.c (main): Adjust for the now working checking of the second key. Signed-off-by: Werner Koch --- src/op-support.c | 10 +++++++++- tests/gpg/t-verify.c | 8 +++++--- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/src/op-support.c b/src/op-support.c index 43cb1c76..e55875f9 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -400,7 +400,13 @@ _gpgme_parse_plaintext (char *args, char **filenamep) /* Parse a FAILURE status line and return the error code. ARGS is - modified to contain the location part. */ + * modified to contain the location part. Note that for now we ignore + * failure codes with a location of gpg-exit; they are too trouble + * some. Instead we should eventually record that error in the + * context and provide a function to return a fuller error + * description; this could then also show the location of the error + * (e.g. "option- parser") to make it easier for the user to detect + * the actual error. */ gpgme_error_t _gpgme_parse_failure (char *args) { @@ -418,6 +424,8 @@ _gpgme_parse_failure (char *args) *where = '\0'; where = args; + if (!strcmp (where, "gpg-exit")) + return 0; return atoi (which); } diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index ffc41eeb..7c23406f 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -267,10 +267,12 @@ main (int argc, char *argv[]) err = gpgme_op_verify (ctx, sig, text, NULL); fail_if_err (err); result = gpgme_op_verify_result (ctx); - check_result (result, 2, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734", + check_result (result, 2, 0, 0, + "A0FF4590BB6122EDEF6E3C542D727CC768697734", GPG_ERR_NO_ERROR, 1); - check_result (result, 2, 1, 0, "36EC2A70C6426EB0FCE5BB4DF91C98F049D4204C", - GPG_ERR_NO_ERROR, 0); + check_result (result, 2, 1, GPGME_SIGSUM_KEY_MISSING, + "36EC2A70C6426EB0FCE5BB4DF91C98F049D4204C", + GPG_ERR_NO_PUBKEY, 0); /* Checking a normal signature. */ -- cgit From a1f76b3b54b75a150fe272b804d85ffd40a507a6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 17 Apr 2018 08:33:44 +0200 Subject: core: Add extended versions of the encrypt functions. * src/gpgme.h.in (gpgme_op_encrypt_ext_start) New. (gpgme_op_encrypt_ext): New. (gpgme_op_encrypt_sign_ext_start): New. (gpgme_op_encrypt_sign_ext): New. * src/libgpgme.vers, tests/run-encrypt.c: Add them. * src/encrypt.c (encrypt_start): Add arg recpstring. (gpgme_op_encrypt): Factor code out to ... (gpgme_op_encrypt_ext): new function with new arg recpstring. (gpgme_op_encrypt_start): Factor code out to ... (gpgme_op_encrypt_ext_start): new function with new arg recpstring. * src/encrypt-sign.c (encrypt_sign_start): Add arg recpstring. (gpgme_op_encrypt_sign): Factor code out to ... (gpgme_op_encrypt_sign_ext): new function with new arg recpstring. (gpgme_op_encrypt_sign_start): Factor code out to ... (gpgme_op_encrypt_sign_ext_start): new function with new arg recpstring. * src/engine-backend.h (struct engine_ops): Change fields encrypt and encrypt_sign. * src/engine.c (_gpgme_engine_op_encrypt): Add arg recpstring and pass to engine. (_gpgme_engine_op_encrypt_sign): Ditto. * src/engine-gpg.c (append_args_from_recipients_string): New. (gpg_encrypt): Add arg recpstring and call new function as needed. (gpg_encrypt_sign): Ditto. * src/engine-gpgsm.c (set_recipients_from_string): New. (gpgsm_encrypt): Add arg recpstring and call new function as needed. * src/engine-uiserver.c (set_recipients_from_string): New. (uiserver_encrypt): Add arg recpstring and call new function as needed. * tests/run-encrypt.c (xstrdup): New. (main): Add option --keystring. * src/gpgme-json.c (get_keys): Simplify. (op_encrypt): Modify to make use of the extended encrypt function. -- This new feature can be used to avoid the need for a key lookup and thus several extra calls to the backend. Note that run-test uses a semicolon as delimiter because that make testing the feature on the command line much easier. Signed-off-by: Werner Koch --- NEWS | 11 +++-- doc/gpgme.texi | 77 ++++++++++++++++++++++++++++++++++ src/encrypt-sign.c | 111 ++++++++++++++++++++++++++++++++++---------------- src/encrypt.c | 106 ++++++++++++++++++++++++++++++++--------------- src/engine-backend.h | 2 + src/engine-gpg.c | 70 +++++++++++++++++++++++++++---- src/engine-gpgsm.c | 58 ++++++++++++++++++++++++-- src/engine-uiserver.c | 59 +++++++++++++++++++++++++-- src/engine.c | 10 +++-- src/engine.h | 2 + src/gpgme-json.c | 74 ++++++++++++++++----------------- src/gpgme.def | 5 +++ src/gpgme.h.in | 30 ++++++++++++-- src/libgpgme.vers | 9 +++- tests/run-encrypt.c | 40 +++++++++++++----- 15 files changed, 519 insertions(+), 145 deletions(-) (limited to 'tests') diff --git a/NEWS b/NEWS index a8d73a50..51d79239 100644 --- a/NEWS +++ b/NEWS @@ -5,11 +5,16 @@ Noteworthy changes in version 1.10.1 (unreleased) * Interface changes relative to the 1.10.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys' - cpp: Key::locate NEW. - cpp: Data::toString NEW. + gpgme_op_encrypt_ext NEW. + gpgme_op_encrypt_ext_start NEW. + gpgme_op_encrypt_sign_ext NEW. + gpgme_op_encrypt_sign_ext_start NEW. + gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'. + cpp: Key::locate NEW. + cpp: Data::toString NEW. cpp: ImportResult::numV3KeysSkipped NEW. + Noteworthy changes in version 1.10.0 (2017-12-12) ------------------------------------------------- diff --git a/doc/gpgme.texi b/doc/gpgme.texi index cbb0e649..1df9c46e 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -6154,6 +6154,45 @@ pointer, and @code{GPG_ERR_UNUSABLE_PUBKEY} if @var{rset} does not contain any valid recipients. @end deftypefun +@deftypefun gpgme_error_t gpgme_op_encrypt_ext @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{recp}[]}, @ + @w{const char *@var{recpstring}}, @ + @w{gpgme_encrypt_flags_t @var{flags}}, @ + @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}}) + +@since{1.11.0} + +This is an extended version of @code{gpgme_op_encrypt} with +@var{recpstring} as additional parameter. If @var{recp} is NULL and +@var{recpstring} is not NULL, the latter is expected to be a linefeed +delimited string with the set of key specifications. In contrast to +@var{recp} the keys are given directly as strings and there is no need +to first create key objects. The keys are passed verbatim to the +backend engine. + +@end deftypefun + + +@deftypefun gpgme_error_t gpgme_op_encrypt_ext_start @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{recp}[]}, @ + @w{const char *@var{recpstring}}, @ + @w{gpgme_encrypt_flags_t @var{flags}}, @ + @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}}) + +@since{1.11.0} + +This is an extended version of @code{gpgme_op_encrypt_start} with +@var{recpstring} as additional parameter. If @var{recp} is NULL and +@var{recpstring} is not NULL, the latter is expected to be a linefeed +delimited string with the set of key specifications. In contrast to +@var{recp} the keys are given directly as strings and there is no need +to first create key objects. The keys are passed verbatim to the +backend engine. + +@end deftypefun + @deftp {Data type} {gpgme_encrypt_result_t} This is a pointer to a structure used to store the result of a @code{gpgme_op_encrypt} operation. After successfully encrypting @@ -6203,6 +6242,44 @@ if @var{ctx}, @var{rset}, @var{plain} or @var{cipher} is not a valid pointer. @end deftypefun +@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{recp}[]}, @ + @w{const char *@var{recpstring}}, @ + @w{gpgme_encrypt_flags_t @var{flags}}, @ + @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}}) + +@since{1.11.0} + +This is an extended version of @code{gpgme_op_encrypt_sign} with +@var{recpstring} as additional parameter. If @var{recp} is NULL and +@var{recpstring} is not NULL, the latter is expected to be a linefeed +delimited string with the set of key specifications. In contrast to +@var{recp} the keys are given directly as strings and there is no need +to first create the key objects. The keys are passed verbatim to the +backend engine. + +@end deftypefun + +@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext_start @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{recp}[]}, @ + @w{const char *@var{recpstring}}, @ + @w{gpgme_encrypt_flags_t @var{flags}}, @ + @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}}) + +@since{1.11.0} + +This is an extended version of @code{gpgme_op_encrypt_sign_start} with +@var{recpstring} as additional parameter. If @var{recp} is NULL and +@var{recpstring} is not NULL, the latter is expected to be a linefeed +delimited string with the set of key specifications. In contrast to +@var{recp} the keys are given directly as strings and there is no need +to first create the key objects. The keys are passed verbatim to the +backend engine. + +@end deftypefun + @node Miscellaneous @section Miscellaneous operations diff --git a/src/encrypt-sign.c b/src/encrypt-sign.c index af6de63e..4db46e25 100644 --- a/src/encrypt-sign.c +++ b/src/encrypt-sign.c @@ -62,6 +62,7 @@ encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args) static gpgme_error_t encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) { @@ -72,7 +73,7 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], if (err) return err; - symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC); + symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC); if (!plain) return gpg_error (GPG_ERR_NO_DATA); @@ -103,43 +104,75 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], : encrypt_sign_status_handler, ctx); - return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain, + return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, recpstring, + flags, plain, cipher, ctx->use_armor, ctx /* FIXME */); } -/* Encrypt plaintext PLAIN within CTX for the recipients RECP and - store the resulting ciphertext in CIPHER. Also sign the ciphertext - with the signers in CTX. */ +/* Old version of gpgme_op_encrypt_sign_ext_start w/o RECPSTRING. */ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) +{ + return gpgme_op_encrypt_sign_ext_start (ctx, recp, NULL, + flags, plain, cipher); +} + + +/* Old version of gpgme_op_encrypt_sign_ext w/o RECPSTRING. */ +gpgme_error_t +gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + return gpgme_op_encrypt_sign_ext (ctx, recp, NULL, flags, plain, cipher); +} + + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + * store the resulting ciphertext in CIPHER. Also sign the ciphertext + * with the signers in CTX. */ +gpgme_error_t +gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) { gpgme_error_t err; - TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx, + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx, "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - if (_gpgme_debug_trace () && recp) + if (_gpgme_debug_trace () && (recp || recpstring)) { - int i = 0; - - while (recp[i]) - { - TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], - (recp[i]->subkeys && recp[i]->subkeys->fpr) ? - recp[i]->subkeys->fpr : "invalid"); - i++; - } + if (recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + else + { + TRACE_LOG1 ("recipients = '%s'", recpstring); + } } - err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher); - return err; + err = encrypt_sign_start (ctx, 1, recp, recpstring, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); } @@ -147,33 +180,39 @@ gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[], store the resulting ciphertext in CIPHER. Also sign the ciphertext with the signers in CTX. */ gpgme_error_t -gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], - gpgme_encrypt_flags_t flags, - gpgme_data_t plain, gpgme_data_t cipher) +gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) { gpgme_error_t err; - TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx, + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx, "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - if (_gpgme_debug_trace () && recp) + if (_gpgme_debug_trace () && (recp || recpstring)) { - int i = 0; - - while (recp[i]) - { - TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], - (recp[i]->subkeys && recp[i]->subkeys->fpr) ? - recp[i]->subkeys->fpr : "invalid"); - i++; - } + if (recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + else + { + TRACE_LOG1 ("recipients = '%s'", recpstring); + } } - err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher); - if (!err) - err = _gpgme_wait_one (ctx); - return TRACE_ERR (err); + err = encrypt_sign_start (ctx, 0, recp, recpstring, flags, plain, cipher); + return err; } diff --git a/src/encrypt.c b/src/encrypt.c index 40236544..2318497e 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -214,6 +214,7 @@ _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx) static gpgme_error_t encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) { @@ -228,13 +229,13 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], if (err) return err; - symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC); + symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC); if (!plain) return gpg_error (GPG_ERR_NO_DATA); if (!cipher) return gpg_error (GPG_ERR_INV_VALUE); - if (recp && ! *recp) + if (recp && !*recp) return gpg_error (GPG_ERR_INV_VALUE); if (symmetric && ctx->passphrase_cb) @@ -252,72 +253,111 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], : encrypt_status_handler, ctx); - return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher, - ctx->use_armor); + return _gpgme_engine_op_encrypt (ctx->engine, recp, recpstring, + flags, plain, cipher, ctx->use_armor); } +/* Old version of gpgme_op_encrypt_ext without RECPSTRING. */ +gpgme_error_t +gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + return gpgme_op_encrypt_ext (ctx, recp, NULL, flags, plain, cipher); +} + + +/* Old version of gpgme_op_encrypt_ext_start without RECPSTRING. */ gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) +{ + return gpgme_op_encrypt_ext_start (ctx, recp, NULL, flags, plain, cipher); +} + + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + * store the resulting ciphertext in CIPHER. RECPSTRING can be used + * instead of the RECP array to directly specify recipients as LF + * delimited strings; these may be any kind of recipient specification + * patterns as supported by the backend. */ +gpgme_error_t +gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) { gpgme_error_t err; - TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx, + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx, "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - if (_gpgme_debug_trace () && recp) + if (_gpgme_debug_trace () && (recp || recpstring)) { - int i = 0; + if (recp) + { + int i = 0; - while (recp[i]) - { - TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], (recp[i]->subkeys && recp[i]->subkeys->fpr) ? - recp[i]->subkeys->fpr : "invalid"); - i++; - } + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + else + { + TRACE_LOG1 ("recipients = '%s'", recpstring); + } } - err = encrypt_start (ctx, 0, recp, flags, plain, cipher); + err = encrypt_start (ctx, 1, recp, recpstring, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); return TRACE_ERR (err); } -/* Encrypt plaintext PLAIN within CTX for the recipients RECP and - store the resulting ciphertext in CIPHER. */ gpgme_error_t -gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], - gpgme_encrypt_flags_t flags, - gpgme_data_t plain, gpgme_data_t cipher) +gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) { gpgme_error_t err; - TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx, + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx, "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - if (_gpgme_debug_trace () && recp) + if (_gpgme_debug_trace () && (recp || recpstring)) { - int i = 0; - - while (recp[i]) - { - TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], - (recp[i]->subkeys && recp[i]->subkeys->fpr) ? - recp[i]->subkeys->fpr : "invalid"); - i++; - } + if (recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + else + { + TRACE_LOG1 ("recipients = '%s'", recpstring); + } } - err = encrypt_start (ctx, 1, recp, flags, plain, cipher); - if (!err) - err = _gpgme_wait_one (ctx); + err = encrypt_start (ctx, 0, recp, recpstring, flags, plain, cipher); return TRACE_ERR (err); } diff --git a/src/engine-backend.h b/src/engine-backend.h index 97cf6a10..f6926662 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -72,10 +72,12 @@ struct engine_ops gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key, gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */); gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor); gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor, gpgme_ctx_t ctx /* FIXME */); diff --git a/src/engine-gpg.c b/src/engine-gpg.c index a37d1f7b..809806c4 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1914,17 +1914,64 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[]) } +/* Take recipients from the LF delimited STRING and add -r args. */ +static gpg_error_t +append_args_from_recipients_string (engine_gpg_t gpg, const char *string) +{ + gpg_error_t err = 0; + int any = 0; + const char *s; + int n; + + do + { + /* Skip leading white space */ + while (*string == ' ' || *string == '\t') + string++; + if (!*string) + break; + + /* Look for the LF. */ + s = strchr (string, '\n'); + if (s) + n = s - string; + else + n = strlen (string); + while (n && (string[n-1] == ' ' || string[n-1] == '\t')) + n--; + + /* Add arg if it is not empty. */ + if (n) + { + err = add_arg (gpg, "-r"); + if (!err) + err = add_arg_len (gpg, NULL, string, n); + if (!err) + any = 1; + } + + string += n + !!s; + } + while (!err); + + if (!err && !any) + err = gpg_error (GPG_ERR_MISSING_KEY); + return err; +} + + static gpgme_error_t -gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, +gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring, + gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor) { engine_gpg_t gpg = engine; gpgme_error_t err = 0; - if (recp) + if (recp || recpstring) err = add_arg (gpg, "--encrypt"); - if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp)) + if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring))) err = add_arg (gpg, "--symmetric"); if (!err && use_armor) @@ -1951,7 +1998,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, && have_gpg_version (gpg, "2.1.14")) err = add_arg (gpg, "--mimemode"); - if (recp) + if (recp || recpstring) { /* If we know that all recipients are valid (full or ultimate trust) we can suppress further checks. */ @@ -1961,7 +2008,9 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)) err = add_arg (gpg, "--no-encrypt-to"); - if (!err) + if (!err && !recp && recpstring) + err = append_args_from_recipients_string (gpg, recpstring); + else if (!err) err = append_args_from_recipients (gpg, recp); } @@ -1995,6 +2044,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, static gpgme_error_t gpg_encrypt_sign (void *engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor, gpgme_ctx_t ctx /* FIXME */) @@ -2002,10 +2052,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[], engine_gpg_t gpg = engine; gpgme_error_t err = 0; - if (recp) + if (recp || recpstring) err = add_arg (gpg, "--encrypt"); - if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp)) + if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring))) err = add_arg (gpg, "--symmetric"); if (!err) @@ -2023,7 +2073,7 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[], && have_gpg_version (gpg, "2.1.14")) err = add_arg (gpg, "--mimemode"); - if (recp) + if (recp || recpstring) { /* If we know that all recipients are valid (full or ultimate trust) we can suppress further checks. */ @@ -2033,7 +2083,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[], if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)) err = add_arg (gpg, "--no-encrypt-to"); - if (!err) + if (!err && !recp && recpstring) + err = append_args_from_recipients_string (gpg, recpstring); + else if (!err) err = append_args_from_recipients (gpg, recp); } diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index b8e44e7c..da7e524f 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1327,8 +1327,57 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) } +/* Take recipients from the LF delimited STRING and send RECIPIENT + * commands to gpgsm. */ static gpgme_error_t -gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, +set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string) +{ + gpg_error_t err = 0; + char *line = NULL; + int no_pubkey = 0; + const char *s; + int n; + + for (;;) + { + while (*string == ' ' || *string == '\t') + string++; + if (!*string) + break; + + s = strchr (string, '\n'); + if (s) + n = s - string; + else + n = strlen (string); + while (n && (string[n-1] == ' ' || string[n-1] == '\t')) + n--; + + gpgrt_free (line); + if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0) + { + err = gpg_error_from_syserror (); + break; + } + string += n + !!s; + + err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc, + gpgsm->status.fnc_value); + + /* Fixme: Improve error reporting. */ + if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) + no_pubkey++; + else if (err) + break; + } + gpgrt_free (line); + return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0; +} + + +static gpgme_error_t +gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring, + gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor) { engine_gpgsm_t gpgsm = engine; @@ -1339,7 +1388,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, if (!recp) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO) + if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)) { err = gpgsm_assuan_simple_command (gpgsm, "OPTION no-encrypt-to", NULL, NULL); @@ -1359,7 +1408,10 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgsm_clear_fd (gpgsm, MESSAGE_FD); gpgsm->inline_data = NULL; - err = set_recipients (gpgsm, recp); + if (!recp && recpstring) + err = set_recipients_from_string (gpgsm, recpstring); + else + err = set_recipients (gpgsm, recp); if (!err) err = start (gpgsm, "ENCRYPT"); diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index fd5ac174..d8f4fce3 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1075,8 +1075,58 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[]) } +/* Take recipients from the LF delimited STRING and send RECIPIENT + * commands to gpgsm. */ static gpgme_error_t -uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, +set_recipients_from_string (engine_uiserver_t uiserver, const char *string) +{ + gpg_error_t err = 0; + char *line = NULL; + int no_pubkey = 0; + const char *s; + int n; + + for (;;) + { + while (*string == ' ' || *string == '\t') + string++; + if (!*string) + break; + + s = strchr (string, '\n'); + if (s) + n = s - string; + else + n = strlen (string); + while (n && (string[n-1] == ' ' || string[n-1] == '\t')) + n--; + + gpgrt_free (line); + if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0) + { + err = gpg_error_from_syserror (); + break; + } + string += n + !!s; + + err = uiserver_assuan_simple_command (uiserver, line, + uiserver->status.fnc, + uiserver->status.fnc_value); + + /* Fixme: Improve error reporting. */ + if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) + no_pubkey++; + else if (err) + break; + } + gpgrt_free (line); + return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0; +} + + +static gpgme_error_t +uiserver_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring, + gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor) { engine_uiserver_t uiserver = engine; @@ -1140,9 +1190,12 @@ uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, uiserver->inline_data = NULL; - if (recp) + if (recp || recpstring) { - err = set_recipients (uiserver, recp); + if (recp) + err = set_recipients (uiserver, recp); + else + err = set_recipients_from_string (uiserver, recpstring); if (err) { gpgrt_free (cmd); diff --git a/src/engine.c b/src/engine.c index e51384f0..b716ca24 100644 --- a/src/engine.c +++ b/src/engine.c @@ -721,6 +721,7 @@ _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key, gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor) { @@ -730,13 +731,14 @@ _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[], if (!engine->ops->encrypt) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph, - use_armor); + return (*engine->ops->encrypt) (engine->engine, recp, recpstring, + flags, plain, ciph, use_armor); } gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor, gpgme_ctx_t ctx /* FIXME */) @@ -747,8 +749,8 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[], if (!engine->ops->encrypt_sign) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->encrypt_sign) (engine->engine, recp, flags, - plain, ciph, use_armor, ctx); + return (*engine->ops->encrypt_sign) (engine->engine, recp, recpstring, + flags, plain, ciph, use_armor, ctx); } diff --git a/src/engine.h b/src/engine.h index 34bf8e90..8b692f2e 100644 --- a/src/engine.h +++ b/src/engine.h @@ -98,11 +98,13 @@ gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type, gpgme_ctx_t ctx /* FIXME */); gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, int use_armor); gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[], + const char *recpstring, gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t ciph, diff --git a/src/gpgme-json.c b/src/gpgme-json.c index b54d9a8a..4b1cd5b8 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -354,18 +354,19 @@ get_protocol (cjson_t json, gpgme_protocol_t *r_protocol) } -/* Extract the keys from the KEYS array in the JSON object. CTX is a - * GPGME context object. On success an array with the keys is stored - * at R_KEYS. In failure an error code is returned. */ +/* Extract the keys from the "keys" array in the JSON object. On + * success a string with the keys identifiers is stored at R_KEYS. + * The keys in that string are LF delimited. On failure an error code + * is returned. */ static gpg_error_t -get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys) +get_keys (cjson_t json, char **r_keystring) { - gpg_error_t err; cjson_t j_keys, j_item; int i, nkeys; - gpgme_key_t *keys; + char *p; + size_t length; - *r_keys = NULL; + *r_keystring = NULL; j_keys = cJSON_GetObjectItem (json, "keys"); if (!j_keys) @@ -373,8 +374,15 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys) if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys)) return gpg_error (GPG_ERR_INV_VALUE); + /* Fixme: We should better use a membuf like thing. */ + length = 1; /* For the EOS. */ if (cjson_is_string (j_keys)) - nkeys = 1; + { + nkeys = 1; + length += strlen (j_keys->valuestring); + if (strchr (j_keys->valuestring, '\n')) + return gpg_error (GPG_ERR_INV_USER_ID); + } else { nkeys = cJSON_GetArraySize (j_keys); @@ -385,43 +393,37 @@ get_keys (gpgme_ctx_t ctx, cjson_t json, gpgme_key_t **r_keys) j_item = cJSON_GetArrayItem (j_keys, i); if (!j_item || !cjson_is_string (j_item)) return gpg_error (GPG_ERR_INV_VALUE); + if (i) + length++; /* Space for delimiter. */ + length += strlen (j_item->valuestring); + if (strchr (j_item->valuestring, '\n')) + return gpg_error (GPG_ERR_INV_USER_ID); } } - /* Now allocate an array to store the gpgme key objects. */ - keys = xcalloc (nkeys + 1, sizeof *keys); + p = *r_keystring = xtrymalloc (length); + if (!p) + return gpg_error_from_syserror (); if (cjson_is_string (j_keys)) { - err = gpgme_get_key (ctx, j_keys->valuestring, &keys[0], 0); - if (err) - goto leave; + strcpy (p, j_keys->valuestring); } else { for (i=0; i < nkeys; i++) { j_item = cJSON_GetArrayItem (j_keys, i); - err = gpgme_get_key (ctx, j_item->valuestring, &keys[i], 0); - if (err) - goto leave; + if (i) + *p++ = '\n'; /* Add delimiter. */ + p = stpcpy (p, j_item->valuestring); } } - err = 0; - *r_keys = keys; - keys = NULL; - - leave: - if (keys) - { - for (i=0; keys[i]; i++) - gpgme_key_unref (keys[i]); - xfree (keys); - } - return err; + return 0; } + /* * GPGME support functions. @@ -582,11 +584,11 @@ op_encrypt (cjson_t request, cjson_t result) gpgme_ctx_t ctx = NULL; gpgme_protocol_t protocol; int opt_base64; - gpgme_key_t *keys = NULL; + char *keystring = NULL; cjson_t j_input; gpgme_data_t input = NULL; gpgme_data_t output = NULL; - int abool, i; + int abool; gpgme_encrypt_flags_t encrypt_flags = 0; if ((err = get_protocol (request, &protocol))) @@ -622,7 +624,7 @@ op_encrypt (cjson_t request, cjson_t result) /* Get the keys. */ - err = get_keys (ctx, request, &keys); + err = get_keys (request, &keystring); if (err) { /* Provide a custom error response. */ @@ -674,7 +676,8 @@ op_encrypt (cjson_t request, cjson_t result) } /* Encrypt. */ - err = gpgme_op_encrypt (ctx, keys, encrypt_flags, input, output); + err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags, + input, output); /* encrypt_result = gpgme_op_encrypt_result (ctx); */ if (err) { @@ -713,12 +716,7 @@ op_encrypt (cjson_t request, cjson_t result) } leave: - if (keys) - { - for (i=0; keys[i]; i++) - gpgme_key_unref (keys[i]); - xfree (keys); - } + xfree (keystring); release_context (ctx); gpgme_data_release (input); return err; diff --git a/src/gpgme.def b/src/gpgme.def index cad30f6c..a01d89a2 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -267,5 +267,10 @@ EXPORTS gpgme_op_conf_dir @199 + gpgme_op_encrypt_ext @200 + gpgme_op_encrypt_ext_start @201 + gpgme_op_encrypt_sign_ext @202 + gpgme_op_encrypt_sign_ext_start @203 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index e3198798..8aba5baa 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1274,10 +1274,22 @@ gpgme_encrypt_flags_t; store the resulting ciphertext in CIPHER. */ gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, - gpgme_data_t plain, gpgme_data_t cipher); + gpgme_data_t plain, + gpgme_data_t cipher); gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, - gpgme_data_t plain, gpgme_data_t cipher); + gpgme_data_t plain, + gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t cipher); /* Encrypt plaintext PLAIN within CTX for the recipients RECP and store the resulting ciphertext in CIPHER. Also sign the ciphertext @@ -1289,7 +1301,19 @@ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_data_t cipher); gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, - gpgme_data_t plain, gpgme_data_t cipher); + gpgme_data_t plain, + gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx, + gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *recpstring, + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t cipher); /* diff --git a/src/libgpgme.vers b/src/libgpgme.vers index a95befba..b49c86d9 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -215,10 +215,15 @@ GPGME_1.0 { gpgme_op_edit; gpgme_op_edit_start; gpgme_op_encrypt; - gpgme_op_encrypt_result; + gpgme_op_encrypt_start; + gpgme_op_encrypt_ext; + gpgme_op_encrypt_ext_start; gpgme_op_encrypt_sign; + gpgme_op_encrypt_sign_ext; gpgme_op_encrypt_sign_start; - gpgme_op_encrypt_start; + gpgme_op_encrypt_sign_ext_start; + gpgme_op_encrypt_result; + gpgme_op_export; gpgme_op_export_ext; gpgme_op_export_ext_start; diff --git a/tests/run-encrypt.c b/tests/run-encrypt.c index 51e2d60f..94084694 100644 --- a/tests/run-encrypt.c +++ b/tests/run-encrypt.c @@ -37,6 +37,19 @@ static int verbose; +static char * +xstrdup (const char *string) +{ + char *p = strdup (string); + if (!p) + { + fprintf (stderr, "strdup failed\n"); + exit (2); + } + return p; +} + + static gpg_error_t status_cb (void *opaque, const char *keyword, const char *value) { @@ -88,6 +101,7 @@ show_usage (int ex) " --uiserver use the UI server\n" " --loopback use a loopback pinentry\n" " --key NAME encrypt to key NAME\n" + " --keystring NAMES encrypt to ';' delimited NAMES\n" " --throw-keyids use this option\n" " --no-symkey-cache disable the use of that cache\n" " --wrap assume input is valid OpenPGP message\n" @@ -103,7 +117,6 @@ main (int argc, char **argv) int last_argc = -1; gpgme_error_t err; gpgme_ctx_t ctx; - const char *key_string = NULL; gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; gpgme_data_t in, out; gpgme_encrypt_result_t result; @@ -113,6 +126,7 @@ main (int argc, char **argv) char *keyargs[10]; gpgme_key_t keys[10+1]; int keycount = 0; + char *keystring = NULL; int i; gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST; gpgme_off_t offset; @@ -174,6 +188,17 @@ main (int argc, char **argv) keyargs[keycount++] = *argv; argc--; argv++; } + else if (!strcmp (*argv, "--keystring")) + { + argc--; argv++; + if (!argc) + show_usage (1); + keystring = xstrdup (*argv); + for (i=0; keystring[i]; i++) + if (keystring[i] == ';') + keystring[i] = '\n'; + argc--; argv++; + } else if (!strcmp (*argv, "--throw-keyids")) { flags |= GPGME_ENCRYPT_THROW_KEYIDS; @@ -207,15 +232,6 @@ main (int argc, char **argv) if (argc != 1) show_usage (1); - if (key_string && protocol == GPGME_PROTOCOL_UISERVER) - { - fprintf (stderr, PGM ": ignoring --key in UI-server mode\n"); - key_string = NULL; - } - - if (!key_string) - key_string = "test"; - init_gpgme (protocol); err = gpgme_new (&ctx); @@ -298,7 +314,8 @@ main (int argc, char **argv) err = gpgme_data_new (&out); fail_if_err (err); - err = gpgme_op_encrypt (ctx, keycount ? keys : NULL, flags, in, out); + err = gpgme_op_encrypt_ext (ctx, keycount ? keys : NULL, keystring, + flags, in, out); result = gpgme_op_encrypt_result (ctx); if (result) print_result (result); @@ -318,5 +335,6 @@ main (int argc, char **argv) for (i=0; i < keycount; i++) gpgme_key_unref (keys[i]); gpgme_release (ctx); + free (keystring); return 0; } -- cgit From 01435da498af9f7538d7ee810392d7eaa407957e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 17 Apr 2018 13:48:56 +0200 Subject: core: Extend decryption result with symkey_algo. * src/gpgme.h.in (gpgme_op_decrypt_result_t): Add field 'symkey_algo'. * src/decrypt.c (release_op_data): Free SYMKEY_ALGO. (gpgme_op_decrypt_result): Make sure SYMKEY_ALGO is not NULL. (parse_decryption_info): New. (_gpgme_decrypt_status_handler): Parse DECRYPTION_INFO status. * src/conversion.c (_gpgme_cipher_algo_name): New. (_gpgme_cipher_mode_name): New. * tests/run-decrypt.c (print_result): Print SYMKEY_ALGO * src/util.h (_gpgme_map_gnupg_error): Remove obsolete prototype. -- Signed-off-by: Werner Koch --- NEWS | 1 + doc/gpgme.texi | 7 ++++++ src/conversion.c | 46 +++++++++++++++++++++++++++++++++++ src/decrypt.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++------- src/gpgme.h.in | 4 +++ src/util.h | 5 ++-- tests/run-decrypt.c | 1 + 7 files changed, 123 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/NEWS b/NEWS index 162212cf..92a96732 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ Noteworthy changes in version 1.10.1 (unreleased) gpgme_op_encrypt_sign_ext_start NEW. GPGME_ENCRYPT_WANT_ADDRESS NEW. gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'. + gpgme_decrypt_result_t EXTENDED: New field 'symkey_algo'. cpp: Key::locate NEW. cpp: Data::toString NEW. cpp: ImportResult::numV3KeysSkipped NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index f5efec67..5a09ea0a 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -5399,6 +5399,13 @@ You must not try to access this member of the struct unless or @code{gpgme_get_ctx_flag (ctx, "export-session-key")} returns true (non-empty string). +@item char *symkey_algo +@since{1.11.0} + +A string with the symmetric encryption algorithm and mode using the +format ".". Note that old non-MDC encryption mode of +OpenPGP is given as "PGPCFB". + @end table @end deftp diff --git a/src/conversion.c b/src/conversion.c index 5b84f672..4bfd3d3e 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -575,3 +575,49 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol) return algo; } + + +/* Return a string with a cipher algorithm. */ +const char * +_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol) +{ + if (protocol == GPGME_PROTOCOL_OPENPGP) + { + /* The algo is given according to OpenPGP specs. */ + switch (algo) + { + case 1: return "IDEA"; + case 2: return "3DES"; + case 3: return "CAST5"; + case 4: return "BLOWFISH"; + case 7: return "AES"; + case 8: return "AES192"; + case 9: return "AES256"; + case 10: return "TWOFISH"; + case 11: return "CAMELLIA128"; + case 12: return "CAMELLIA192"; + case 13: return "CAMELLIA256"; + } + } + + return "Unknown"; +} + + +/* Return a string with the cipher mode. */ +const char * +_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol) +{ + if (protocol == GPGME_PROTOCOL_OPENPGP) + { + /* The algo is given according to OpenPGP specs. */ + switch (algo) + { + case 0: return "CFB"; + case 1: return "EAX"; + case 2: return "OCB"; + } + } + + return "Unknown"; +} diff --git a/src/decrypt.c b/src/decrypt.c index 8c2cd4d7..e4de6e41 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -69,14 +69,10 @@ release_op_data (void *hook) op_data_t opd = (op_data_t) hook; gpgme_recipient_t recipient = opd->result.recipients; - if (opd->result.unsupported_algorithm) - free (opd->result.unsupported_algorithm); - - if (opd->result.file_name) - free (opd->result.file_name); - - if (opd->result.session_key) - free (opd->result.session_key); + free (opd->result.unsupported_algorithm); + free (opd->result.file_name); + free (opd->result.session_key); + free (opd->result.symkey_algo); while (recipient) { @@ -104,6 +100,17 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx) return NULL; } + /* Make sure that SYMKEY_ALGO has a value. */ + if (!opd->result.symkey_algo) + { + opd->result.symkey_algo = strdup ("?.?"); + if (!opd->result.symkey_algo) + { + TRACE_SUC0 ("result=(null)"); + return NULL; + } + } + if (_gpgme_debug_trace ()) { gpgme_recipient_t rcp; @@ -263,6 +270,49 @@ parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol) } +/* Parse the ARGS of a + * DECRYPTION_INFO [] + * status. Returns 0 on success and updates the OPD. + */ +static gpgme_error_t +parse_decryption_info (char *args, op_data_t opd, gpgme_protocol_t protocol) +{ + char *field[3]; + int nfields; + char *args2; + int mdc, mode; + const char *algostr, *modestr; + + if (!args) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + args2 = strdup (args); /* Split modifies the input string. */ + nfields = _gpgme_split_fields (args2, field, DIM (field)); + if (nfields < 2) + { + free (args2); + return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing. */ + } + + mdc = atoi (field[0]); + algostr = _gpgme_cipher_algo_name (atoi (field[1]), protocol); + mode = nfields < 3? 0 : atoi (field[2]); + modestr = _gpgme_cipher_mode_name (mode, protocol); + + free (args2); + + free (opd->result.symkey_algo); + if (!mode && mdc != 2) + opd->result.symkey_algo = _gpgme_strconcat (algostr, ".PGPCFB", NULL); + else + opd->result.symkey_algo = _gpgme_strconcat (algostr, ".", modestr, NULL); + if (!opd->result.symkey_algo) + return gpg_error_from_syserror (); + + return 0; +} + + gpgme_error_t _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) @@ -303,7 +353,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, break; case GPGME_STATUS_DECRYPTION_INFO: - /* Fixme: Provide a way to return the used symmetric algorithm. */ + err = parse_decryption_info (args, opd, ctx->protocol); + if (err) + return err; break; case GPGME_STATUS_DECRYPTION_OKAY: diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 860e0931..202859c3 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1368,6 +1368,10 @@ struct _gpgme_op_decrypt_result /* A textual representation of the session key used to decrypt the * message, if available */ char *session_key; + + /* A string with the symmetric encryption algorithm and mode using + * the format ".". */ + char *symkey_algo; }; typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t; diff --git a/src/util.h b/src/util.h index b4043ed1..da929eb4 100644 --- a/src/util.h +++ b/src/util.h @@ -165,10 +165,11 @@ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp); * on error or missing timestamp. */ unsigned long _gpgme_parse_timestamp_ul (const char *timestamp); -gpgme_error_t _gpgme_map_gnupg_error (char *err); - int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol); +const char *_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol); +const char *_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol); + /*-- b64dec.c --*/ diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index a2e82a0e..8eb6ba09 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -59,6 +59,7 @@ print_result (gpgme_decrypt_result_t result) nonnull(result->unsupported_algorithm)); if (result->session_key) printf ("Session key: %s\n", result->session_key); + printf ("Symmetric algorithm: %s\n", result->symkey_algo); for (recp = result->recipients; recp && recp->next; recp = recp->next) { -- cgit From 65479fe7b871ad6237d5a8959b73afcc7db784da Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 18 Apr 2018 15:20:35 +0200 Subject: core: Add 'is_mime' flags to the verify and decrypt results. * src/op-support.c (_gpgme_parse_plaintext): Add arg r_mime. * src/decrypt.c (_gpgme_decrypt_status_handler): Ser mime flag. * src/verify.c (_gpgme_verify_status_handler): Ditto. * src/gpgme.h.in (gpgme_op_verify_result_t): Append fields 'is_mime' and '_unused'. (gpgme_op_decrypt_result_t): New field 'is_mime'. Shrink '_unused'. * tests/run-decrypt.c (print_result): Print MIME flag. * tests/run-verify.c (print_result): Ditto. -- Note that this flag (Liternal Data packet's 'm' mode) is only specified in RFC-4880bis. To use it you currently need to add "rfc4880bis" to the the gpg.conf. Signed-off-by: Werner Koch --- NEWS | 2 ++ doc/gpgme.texi | 2 +- src/decrypt.c | 11 ++++++++--- src/gpgme.h.in | 11 ++++++++++- src/op-support.c | 6 ++++-- src/ops.h | 4 ++-- src/verify.c | 11 ++++++++--- tests/run-decrypt.c | 21 +++++++++++---------- tests/run-verify.c | 9 +++++---- 9 files changed, 51 insertions(+), 26 deletions(-) (limited to 'tests') diff --git a/NEWS b/NEWS index 92a96732..be3111c5 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ Noteworthy changes in version 1.10.1 (unreleased) GPGME_ENCRYPT_WANT_ADDRESS NEW. gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'. gpgme_decrypt_result_t EXTENDED: New field 'symkey_algo'. + gpgme_decrypt_result_t EXTENDED: New field 'is_mime'. + gpgme_verify_result_t EXTENDED: New field 'is_mime'. cpp: Key::locate NEW. cpp: Data::toString NEW. cpp: ImportResult::numV3KeysSkipped NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 5a09ea0a..83348dd0 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -5284,7 +5284,7 @@ if @var{cipher} or @var{plain} is not a valid pointer. @since{1.8.0} The function @code{gpgme_op_decrypt_ext} is the same as -@code{gpgme_op_decrypt_ext} but has an additional argument +@code{gpgme_op_decrypt} but has an additional argument @var{flags}. If @var{flags} is 0 both function behave identically. The value in @var{flags} is a bitwise-or combination of one or diff --git a/src/decrypt.c b/src/decrypt.c index e4de6e41..155e18ef 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -409,9 +409,14 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, break; case GPGME_STATUS_PLAINTEXT: - err = _gpgme_parse_plaintext (args, &opd->result.file_name); - if (err) - return err; + { + int mime = 0; + err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime); + if (err) + return err; + gpgrt_log_debug ("decrypt.c setting mime to %d\n", mime); + opd->result.is_mime = !!mime; + } break; case GPGME_STATUS_INQUIRE_MAXLEN: diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 202859c3..c81e882f 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1356,8 +1356,11 @@ struct _gpgme_op_decrypt_result * mode. */ unsigned int is_de_vs : 1; + /* The message claims that the content is a MIME object. */ + unsigned int is_mime : 1; + /* Internal to GPGME, do not use. */ - int _unused : 30; + int _unused : 29; gpgme_recipient_t recipients; @@ -1572,6 +1575,12 @@ struct _gpgme_op_verify_result /* The original file name of the plaintext message, if available. */ char *file_name; + + /* The message claims that the content is a MIME object. */ + unsigned int is_mime : 1; + + /* Internal to GPGME; do not use. */ + unsigned int _unused : 31; }; typedef struct _gpgme_op_verify_result *gpgme_verify_result_t; diff --git a/src/op-support.c b/src/op-support.c index e55875f9..03f274cf 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -358,7 +358,7 @@ _gpgme_parse_key_considered (const char *args, /* Parse the PLAINTEXT status line in ARGS and return the result in FILENAMEP. */ gpgme_error_t -_gpgme_parse_plaintext (char *args, char **filenamep) +_gpgme_parse_plaintext (char *args, char **filenamep, int *r_mime) { char *tail; @@ -367,7 +367,9 @@ _gpgme_parse_plaintext (char *args, char **filenamep) if (*args == '\0') return 0; - /* First argument is file type. */ + /* First argument is file type (a one byte uppercase hex value). */ + if (args[0] == '6' && args[1] == 'D') + *r_mime = 1; while (*args != ' ' && *args != '\0') args++; while (*args == ' ') diff --git a/src/ops.h b/src/ops.h index cc61dc4f..5955454c 100644 --- a/src/ops.h +++ b/src/ops.h @@ -68,8 +68,8 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, int for_signing, gpgme_invalid_key_t *key); /* Parse the PLAINTEXT status line in ARGS and return the result in - FILENAMEP. */ -gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep); + FILENAMEP and R_MIME. */ +gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep,int *r_mime); /* Parse a FAILURE status line and return the error code. ARGS is modified to contain the location part. */ diff --git a/src/verify.c b/src/verify.c index c3afdef2..bd437c9a 100644 --- a/src/verify.c +++ b/src/verify.c @@ -1091,9 +1091,14 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) case GPGME_STATUS_PLAINTEXT: if (++opd->plaintext_seen > 1) return gpg_error (GPG_ERR_BAD_DATA); - err = _gpgme_parse_plaintext (args, &opd->result.file_name); - if (err) - return err; + { + int mime = 0; + err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime); + if (err) + return err; + gpgrt_log_debug ("verify.c: setting mime to %d\n", mime); + opd->result.is_mime = !!mime; + } break; case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE: diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index 8eb6ba09..69de139c 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -53,20 +53,21 @@ print_result (gpgme_decrypt_result_t result) gpgme_recipient_t recp; int count = 0; - printf ("Original file name: %s\n", nonnull(result->file_name)); - printf ("Wrong key usage: %i\n", result->wrong_key_usage); - printf ("Unsupported algorithm: %s\n", - nonnull(result->unsupported_algorithm)); - if (result->session_key) - printf ("Session key: %s\n", result->session_key); - printf ("Symmetric algorithm: %s\n", result->symkey_algo); + printf ("Original file name .: %s\n", nonnull(result->file_name)); + printf ("Wrong key usage ....: %s\n", result->wrong_key_usage? "yes":"no"); + printf ("Compliance de-vs ...: %s\n", result->is_de_vs? "yes":"no"); + printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no"); + printf ("Unsupported algo ...: %s\n", nonnull(result->unsupported_algorithm)); + printf ("Session key ........: %s\n", nonnull (result->session_key)); + printf ("Symmetric algorithm : %s\n", result->symkey_algo); for (recp = result->recipients; recp && recp->next; recp = recp->next) { - printf ("recipient %d\n", count++); + printf ("Recipient ...: %d\n", count++); printf (" status ....: %s\n", gpgme_strerror (recp->status)); - printf (" keyid: %s\n", nonnull (recp->keyid)); - printf (" algo ...: %s\n", gpgme_pubkey_algo_name (recp->pubkey_algo)); + printf (" keyid .....: %s\n", nonnull (recp->keyid)); + printf (" algo ......: %s\n", + gpgme_pubkey_algo_name (recp->pubkey_algo)); } } diff --git a/tests/run-verify.c b/tests/run-verify.c index 699bfd1f..4a6c9601 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -136,10 +136,11 @@ print_result (gpgme_verify_result_t result) gpgme_tofu_info_t ti; int count = 0; - printf ("Original file name: %s\n", nonnull(result->file_name)); + printf ("Original file name .: %s\n", nonnull(result->file_name)); + printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no"); for (sig = result->signatures; sig; sig = sig->next) { - printf ("Signature %d\n", count++); + printf ("Signature ...: %d\n", count++); printf (" status ....: %s\n", gpgme_strerror (sig->status)); printf (" summary ...:"); print_summary (sig->summary); putchar ('\n'); printf (" fingerprint: %s\n", nonnull (sig->fpr)); @@ -167,7 +168,7 @@ print_result (gpgme_verify_result_t result) { printf (" notation ..: '%s'\n", nt->name); if (strlen (nt->name) != nt->name_len) - printf (" warning : name larger (%d)\n", nt->name_len); + printf (" warning .: name larger (%d)\n", nt->name_len); printf (" flags ...:%s%s (0x%02x)\n", nt->critical? " critical":"", nt->human_readable? " human":"", @@ -180,7 +181,7 @@ print_result (gpgme_verify_result_t result) printf (" policy ....: '%s'\n", nt->value); } if ((nt->value?strlen (nt->value):0) != nt->value_len) - printf (" warning : value larger (%d)\n", nt->value_len); + printf (" warning .: value larger (%d)\n", nt->value_len); } if (sig->key) { -- cgit From 3d8e5c07511938a0b30b4626530822338abd9ec0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 19 Apr 2018 10:29:30 +0200 Subject: tests: Fix t-verify test for GnuPG < 2.2.7. * tests/gpg/t-verify.c (check_result): Tweak for gnupg < 2.2.7. -- The not yet releases 2.2.7-beta may print a full fingerprint in the ERRSIG status. This is compliant with the dscription but the new t-verify test case did not took in account that older GnuPG versions print only a keyid. Fixes-commit: b99502274ae5efdf6df0d967900ec3d1e64373d7 GnUPG-bug-id: 3920 Signed-off-by: Werner Koch --- tests/gpg/t-verify.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index 7c23406f..fa0164ac 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -126,9 +126,15 @@ check_result (gpgme_verify_result_t result, int no_of_sigs, int skip_sigs, } if (strcmp (sig->fpr, fpr)) { - fprintf (stderr, "%s:%i:sig-%d: Unexpected fingerprint: %s\n", - PGM, __LINE__, skip_sigs, sig->fpr); - exit (1); + if (strlen (sig->fpr) == 16 && strlen (fpr) == 40 + && !strncmp (sig->fpr, fpr + 24, 16)) + ; /* okay because gnupg < 2.2.6 only shows the keyid. */ + else + { + fprintf (stderr, "%s:%i:sig-%d: Unexpected fingerprint: %s\n", + PGM, __LINE__, skip_sigs, sig->fpr); + exit (1); + } } if (gpgme_err_code (sig->status) != status) { -- cgit