From 9e3d41bf727fcf12f7cf05926890c687125c2902 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 28 Aug 2017 11:57:17 +0200 Subject: [PATCH 01/20] Post release updates -- --- NEWS | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 345fe23e3..7510ff4e5 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 2.2.1 (unreleased) +------------------------------------------------ + + Noteworthy changes in version 2.2.0 (2017-08-28) ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 6f945bd0e..fbd5c1807 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,7 @@ min_automake_version="1.14" m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [2]) -m4_define([mym4_micro], [0]) +m4_define([mym4_micro], [1]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release From 7089dcc54099a4909ce7d386c07ab87e1398e2eb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 11 Sep 2017 11:29:13 +0200 Subject: [PATCH 02/20] gpg: Fix key generation with only an email part. * g10/keygen.c (proc_parameter_file): Special case the email only case. -- Using a parameter file like %ask-passphrase key-type: RSA key-length: 2048 key-usage: sign subkey-type: RSA subkey-length: 2048 subkey-usage: encrypt name-email: foo@example.org with "gpg --gen-key --patch" the result was this key pub rsa2048 2017-09-11 [SC] 63A8C1BA12CC289A0E8072C971C7F8D4A18CE0BE uid [ultimate] sub rsa2048 2017-09-11 [E] At least the the extra leading space the left angle bracket is wrong. Further some mail providers reject keys which consist of more than just a plain mail address. Using just a mail address is anyway the new new suggested content for a user id. With this patch the key will be pub rsa2048 2017-09-11 [SC] B302343C20EA6DECDB6A155135352F2520397080 uid [ultimate] foo@example.org sub rsa2048 2017-09-11 [E] Signed-off-by: Werner Koch --- g10/keygen.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/g10/keygen.c b/g10/keygen.c index 6a3d32345..08bc62131 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -3530,7 +3530,14 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, if( s2 ) p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); if( s3 ) - p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); + { + /* If we have only the email part, do not add the space + * and the angle brackets. */ + if (*p) + p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); + else + p = stpcpy (p, s3); + } append_to_parameter (para, r); have_user_id=1; } From 827abe01a72a50eab1cdcde78985b42a4a8480fb Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 29 Aug 2017 14:35:47 +0900 Subject: [PATCH 03/20] scd: Fix for large ECC keys. * scd/app-openpgp.c (do_decipher): Support larger length. -- Reported-by: Achim Pietig Signed-off-by: NIIBE Yutaka --- scd/app-openpgp.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index f9d07ac46..6fcec3e4e 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4575,19 +4575,43 @@ do_decipher (app_t app, const char *keyidstr, } } - fixuplen = 7; + n = 0; + if (indatalen < 128) + fixuplen = 7; + else + fixuplen = 10; + fixbuf = xtrymalloc (fixuplen + indatalen); if (!fixbuf) return gpg_error_from_syserror (); /* Build 'Cipher DO' */ - fixbuf[0] = '\xa6'; - fixbuf[1] = (char)(indatalen+5); - fixbuf[2] = '\x7f'; - fixbuf[3] = '\x49'; - fixbuf[4] = (char)(indatalen+2); - fixbuf[5] = '\x86'; - fixbuf[6] = (char)indatalen; + fixbuf[n++] = '\xa6'; + if (indatalen < 128) + fixbuf[n++] = (char)(indatalen+5); + else + { + fixbuf[n++] = 0x81; + fixbuf[n++] = (char)(indatalen+7); + } + fixbuf[n++] = '\x7f'; + fixbuf[n++] = '\x49'; + if (indatalen < 128) + fixbuf[n++] = (char)(indatalen+2); + else + { + fixbuf[n++] = 0x81; + fixbuf[n++] = (char)(indatalen+3); + } + fixbuf[n++] = '\x86'; + if (indatalen < 128) + fixbuf[n++] = (char)indatalen; + else + { + fixbuf[n++] = 0x81; + fixbuf[n++] = (char)indatalen; + } + if (old_format_len) { memset (fixbuf+fixuplen, 0, 32 - old_format_len); From a172759b5088ae086c0caa2e7d4d0ea346b28a90 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 8 Sep 2017 14:21:29 +0900 Subject: [PATCH 04/20] tests: Fix a test which specifies expiration date. * tests/openpgp/quick-key-manipulation.scm: Fix expiration time comparison. -- This is a bug fix for Amelia Earhart who is probably in UTC-12. When expiration date is specified, GnuPG interprets it as noon of the date in local time. Before this fix, the test compared the value by 2145916800 which is 2038-01-01 00:00:00 in UTC with allowance of 1 day. When the test was ran in UTC-12 timezone, it failed because of noon in the timezone is midnight of the next day in UTC. GnuPG-bug-id: 3393 Reported-by: Daniel Kahn Gillmor Signed-off-by: NIIBE Yutaka --- tests/openpgp/quick-key-manipulation.scm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/openpgp/quick-key-manipulation.scm b/tests/openpgp/quick-key-manipulation.scm index c21abfee2..2023f17bd 100755 --- a/tests/openpgp/quick-key-manipulation.scm +++ b/tests/openpgp/quick-key-manipulation.scm @@ -178,11 +178,11 @@ (lambda (subkey) (assert (= 1 (:alg subkey))) (assert (string-contains? (:cap subkey) "s")) - (assert (time-matches? 2145916800 ;; 2038-01-01 - ;; 4260207600 ;; 2105-01-01 + (assert (time-matches? 2145960000 ;; UTC 2038-01-01 12:00:00 + ;; 4260254400 ;; UTC 2105-01-01 12:00:00 (string->number (:expire subkey)) - ;; This is off by 12h, but I guess it just - ;; choses the middle of the day. + ;; GnuPG choses the middle of the day (local time) + ;; when no hh:mm:ss is specified (days->seconds 1)))) (lambda (subkey) (assert (= 1 (:alg subkey))) From 7d15ee88980f88ca62fc7de9492dd08e54d0f0f1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 14:29:04 +0200 Subject: [PATCH 05/20] tools: New function mime_maker_add_body_data. * tools/mime-maker.c (mime_maker_add_body_data): New. Signed-off-by: Werner Koch --- tools/mime-maker.c | 13 ++++++++++++- tools/mime-maker.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/mime-maker.c b/tools/mime-maker.c index d1241f3f8..0edc14d78 100644 --- a/tools/mime-maker.c +++ b/tools/mime-maker.c @@ -478,7 +478,8 @@ add_body (mime_maker_t ctx, const void *data, size_t datalen) /* Add STRING as body to the mail or the current MIME container. A - * second call to this function is not allowed. + * second call to this function or mime_make_add_body_data is not + * allowed. * * FIXME: We may want to have an append_body to add more data to a body. */ @@ -489,6 +490,16 @@ mime_maker_add_body (mime_maker_t ctx, const char *string) } +/* Add (DATA,DATALEN) as body to the mail or the current MIME + * container. Note that a second call to this function or to + * mime_make_add_body is not allowed. */ +gpg_error_t +mime_maker_add_body_data (mime_maker_t ctx, const void *data, size_t datalen) +{ + return add_body (ctx, data, datalen); +} + + /* This is the same as mime_maker_add_body but takes a stream as * argument. As of now the stream is copied to the MIME object but * eventually we may delay that and read the stream only at the time diff --git a/tools/mime-maker.h b/tools/mime-maker.h index f2a76cdb8..c0ddaeaa5 100644 --- a/tools/mime-maker.h +++ b/tools/mime-maker.h @@ -34,6 +34,8 @@ void mime_maker_dump_tree (mime_maker_t ctx); gpg_error_t mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value); gpg_error_t mime_maker_add_body (mime_maker_t ctx, const char *string); +gpg_error_t mime_maker_add_body_data (mime_maker_t ctx, + const void *data, size_t datalen); gpg_error_t mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr); gpg_error_t mime_maker_add_container (mime_maker_t ctx); gpg_error_t mime_maker_end_container (mime_maker_t ctx); From c65a7bba7331975d20910f90cf648b6ecc5410f0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 14:32:29 +0200 Subject: [PATCH 06/20] wks: Use unencrypted draft-1 mode for posteo.de * tools/gpg-wks-client.c (command_send): Allow sending in draft-1 mode. -- Obviously Posteo did not implement the current draft and thus it was not possible to send a request to them. This hack uses the old method for posteo.de. Not sending it encrypted is okay here because they use authenticated sending anyway. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 120 +++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 39 deletions(-) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 594f28a7c..5b98de441 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -349,10 +349,7 @@ get_key_status_cb (void *opaque, const char *keyword, char *args) /* Get a key by fingerprint from gpg's keyring and make sure that the * mail address ADDRSPEC is included in the key. The key is returned - * as a new memory stream at R_KEY. - * - * Fixme: After we have implemented import and export filters for gpg - * this function shall only return a key with just this user id. */ + * as a new memory stream at R_KEY. */ static gpg_error_t get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) { @@ -695,6 +692,8 @@ command_send (const char *fingerprint, char *userid) char *submission_to = NULL; mime_maker_t mime = NULL; struct policy_flags_s policy; + int no_encrypt = 0; + const char *domain; memset (&policy, 0, sizeof policy); @@ -717,6 +716,10 @@ command_send (const char *fingerprint, char *userid) if (err) goto leave; + domain = strchr (addrspec, '@'); + log_assert (domain); + domain++; + /* Get the submission address. */ if (fake_submission_addr) { @@ -727,11 +730,8 @@ command_send (const char *fingerprint, char *userid) err = wkd_get_submission_address (addrspec, &submission_to); if (err) { - char *domain = strchr (addrspec, '@'); - if (domain) - domain = domain + 1; - log_error (_("looking up WKS submission address for %s: %s\n"), - domain ? domain : addrspec, gpg_strerror (err)); + log_error (_("error looking up submission address for domain '%s': %s\n"), + domain, gpg_strerror (err)); if (gpg_err_code (err) == GPG_ERR_NO_DATA) log_error (_("this domain probably doesn't support WKS.\n")); goto leave; @@ -762,14 +762,23 @@ command_send (const char *fingerprint, char *userid) if (policy.auth_submit) log_info ("no confirmation required for '%s'\n", addrspec); - /* Encrypt the key part. */ - es_rewind (key); - err = encrypt_response (&keyenc, key, submission_to, fingerprint); - if (err) - goto leave; - es_fclose (key); - key = NULL; + /* Hack to support old providers. */ + if (policy.auth_submit && !ascii_strcasecmp (domain, "posteo.de")) + { + log_info ("Warning: Using draft-1 method for domain '%s'\n", domain); + no_encrypt = 1; + } + /* Encrypt the key part. */ + if (!no_encrypt) + { + es_rewind (key); + err = encrypt_response (&keyenc, key, submission_to, fingerprint); + if (err) + goto leave; + es_fclose (key); + key = NULL; + } /* Send the key. */ err = mime_maker_new (&mime, NULL); @@ -787,34 +796,67 @@ command_send (const char *fingerprint, char *userid) /* Tell server which draft we support. */ err = mime_maker_add_header (mime, "Wks-Draft-Version", - STR2(WKS_DRAFT_VERSION)); + STR2(WKS_DRAFT_VERSION)); if (err) goto leave; - err = mime_maker_add_header (mime, "Content-Type", - "multipart/encrypted; " - "protocol=\"application/pgp-encrypted\""); - if (err) - goto leave; - err = mime_maker_add_container (mime); - if (err) - goto leave; + if (no_encrypt) + { + void *data; + size_t datalen, n; - err = mime_maker_add_header (mime, "Content-Type", - "application/pgp-encrypted"); - if (err) - goto leave; - err = mime_maker_add_body (mime, "Version: 1\n"); - if (err) - goto leave; - err = mime_maker_add_header (mime, "Content-Type", - "application/octet-stream"); - if (err) - goto leave; + err = mime_maker_add_header (mime, "Content-type", + "application/pgp-keys"); + if (err) + goto leave; - err = mime_maker_add_stream (mime, &keyenc); - if (err) - goto leave; + if (es_fclose_snatch (key, &data, &datalen)) + { + err = gpg_error_from_syserror (); + goto leave; + } + key = NULL; + /* We need to skip over the first line which has a content-type + * header not needed here. */ + for (n=0; n < datalen ; n++) + if (((const char *)data)[n] == '\n') + { + n++; + break; + } + + err = mime_maker_add_body_data (mime, (char*)data + n, datalen - n); + xfree (data); + if (err) + goto leave; + } + else + { + err = mime_maker_add_header (mime, "Content-Type", + "multipart/encrypted; " + "protocol=\"application/pgp-encrypted\""); + if (err) + goto leave; + err = mime_maker_add_container (mime); + if (err) + goto leave; + + err = mime_maker_add_header (mime, "Content-Type", + "application/pgp-encrypted"); + if (err) + goto leave; + err = mime_maker_add_body (mime, "Version: 1\n"); + if (err) + goto leave; + err = mime_maker_add_header (mime, "Content-Type", + "application/octet-stream"); + if (err) + goto leave; + + err = mime_maker_add_stream (mime, &keyenc); + if (err) + goto leave; + } err = wks_send_mime (mime); From 8b5a2474f21dd4f1aa2a283e2f57d75e42742af5 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 14:38:44 +0200 Subject: [PATCH 07/20] gpg: Fix "Fix key generation with only an email part". * g10/keygen.c (proc_parameter_file): Don't check the result of stpcpy. -- Fixes-commit: 7089dcc54099a4909ce7d386c07ab87e1398e2eb Signed-off-by: Werner Koch --- g10/keygen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g10/keygen.c b/g10/keygen.c index 08bc62131..2b17a1e09 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -3533,7 +3533,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, { /* If we have only the email part, do not add the space * and the angle brackets. */ - if (*p) + if (*r->u.value) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); else p = stpcpy (p, s3); From 332c9eaa2a3c7cae90b389cdaa2c149c5595fb4d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 18:05:00 +0200 Subject: [PATCH 08/20] wks: Add new policy flag protocol-version * tools/gpg-wks.h (policy_flags_s): Add field protocol_version. * tools/wks-util.c (wks_parse_policy): Add new policy flag. Signed-off-by: Werner Koch --- tools/gpg-wks.h | 1 + tools/wks-util.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index f73c183e0..caea98e2f 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -63,6 +63,7 @@ struct policy_flags_s unsigned int mailbox_only : 1; unsigned int dane_only : 1; unsigned int auth_submit : 1; + unsigned int protocol_version; /* The supported WKS_DRAFT_VERION or 0 */ unsigned int max_pending; /* Seconds to wait for a confirmation. */ }; typedef struct policy_flags_s *policy_flags_t; diff --git a/tools/wks-util.c b/tools/wks-util.c index 46ad5c27b..45237b2b4 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -316,7 +316,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) TOK_MAILBOX_ONLY, TOK_DANE_ONLY, TOK_AUTH_SUBMIT, - TOK_MAX_PENDING + TOK_MAX_PENDING, + TOK_PROTOCOL_VERSION }; static struct { const char *name; @@ -325,7 +326,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) { "mailbox-only", TOK_MAILBOX_ONLY }, { "dane-only", TOK_DANE_ONLY }, { "auth-submit", TOK_AUTH_SUBMIT }, - { "max-pending", TOK_MAX_PENDING } + { "max-pending", TOK_MAX_PENDING }, + { "protocol-version", TOK_PROTOCOL_VERSION } }; gpg_error_t err = 0; int lnr = 0; @@ -400,6 +402,14 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) * and decide whether to allow other units. */ flags->max_pending = atoi (value); break; + case TOK_PROTOCOL_VERSION: + if (!value) + { + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + flags->protocol_version = atoi (value); + break; } } From a821b4f5567d02c3329c2b94a73dcbe12e6699a2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 18:08:09 +0200 Subject: [PATCH 09/20] wks: Add hack for the broken posteo system * tools/gpg-wks-client.c (command_send): Additional hack for posteo. Check the protocol-version flag. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 5b98de441..e703640e1 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -693,6 +693,7 @@ command_send (const char *fingerprint, char *userid) mime_maker_t mime = NULL; struct policy_flags_s policy; int no_encrypt = 0; + int posteo_hack = 0; const char *domain; memset (&policy, 0, sizeof policy); @@ -762,11 +763,14 @@ command_send (const char *fingerprint, char *userid) if (policy.auth_submit) log_info ("no confirmation required for '%s'\n", addrspec); - /* Hack to support old providers. */ - if (policy.auth_submit && !ascii_strcasecmp (domain, "posteo.de")) + /* Hack to support posteo but let them disable this by setting the + * new policy-version flag. */ + if (policy.protocol_version < 3 + && !ascii_strcasecmp (domain, "posteo.de")) { log_info ("Warning: Using draft-1 method for domain '%s'\n", domain); no_encrypt = 1; + posteo_hack = 1; } /* Encrypt the key part. */ @@ -805,6 +809,18 @@ command_send (const char *fingerprint, char *userid) void *data; size_t datalen, n; + if (posteo_hack) + { + /* Needs a multipart/mixed with one(!) attachment. It does + * not grok a non-multipart mail. */ + err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed"); + if (err) + goto leave; + err = mime_maker_add_container (mime); + if (err) + goto leave; + } + err = mime_maker_add_header (mime, "Content-type", "application/pgp-keys"); if (err) From 006ca124ed95845d43af8c14d7ab2bc085b47b4c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Sep 2017 09:18:15 +0200 Subject: [PATCH 10/20] gpgv: Initialize compliance checker. * g10/gpgv.c (main): Call gnupg_initialize_compliance. -- The compliance checker needs to be initialize so that it won't let spit out a "not suitable" message. We use the module name of gpg. Because there is no option to change the compliance mode in gpgv we will always be in the default (CO_GNUPG) mode. It also does not make much sense to have it here because gpgv expects a "curated" keyring. GnuPG-bug-id: 3404 Signed-off-by: Werner Koch --- g10/gpgv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/g10/gpgv.c b/g10/gpgv.c index fb274b337..c43067dfd 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -202,6 +202,7 @@ main( int argc, char **argv ) dotlock_disable (); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); additional_weak_digest("MD5"); + gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG); pargs.argc = &argc; pargs.argv = &argv; From 4e0696de897cac6a34d55a69d8889faf26f1a923 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 11:16:07 +0200 Subject: [PATCH 11/20] wks: Use dedicated type to convey user ids. * tools/gpg-wks.h (uidinfo_list_s, uidinfo_list_t): New. * tools/wks-util.c (append_to_uidinfo_list): New. (free_uidinfo_list): New. (wks_list_key): Change arg r_mboxes to uidinfo_list_t. Use append_to_uidinfo_list. * tools/gpg-wks-server.c (sserver_ctx_s): Replace strlist_t by uidinfo_list_t. (process_new_key): Ditto. (check_and_publish): Ditto. (command_receive_cb): Replace free_strlist by free_uidinfo_list. * tools/gpg-wks-client.c (command_check): Replace strlist_t by uidinfo_list_t. Also print user id in verbose mode. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 19 +++++++++------ tools/gpg-wks-server.c | 36 +++++++++++++++------------- tools/gpg-wks.h | 14 ++++++++++- tools/wks-util.c | 54 +++++++++++++++++++++++++++++++++++------- 4 files changed, 91 insertions(+), 32 deletions(-) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index e703640e1..6b83de8c5 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -119,7 +119,7 @@ const char *fake_submission_addr; static void wrong_args (const char *text) GPGRT_ATTR_NORETURN; static gpg_error_t command_supported (char *userid); static gpg_error_t command_check (char *userid); -static gpg_error_t command_send (const char *fingerprint, char *userid); +static gpg_error_t command_send (const char *fingerprint, const char *userid); static gpg_error_t encrypt_response (estream_t *r_output, estream_t input, const char *addrspec, const char *fingerprint); @@ -597,8 +597,8 @@ command_check (char *userid) char *addrspec = NULL; estream_t key = NULL; char *fpr = NULL; - strlist_t mboxes = NULL; - strlist_t sl; + uidinfo_list_t mboxes = NULL; + uidinfo_list_t sl; int found = 0; addrspec = mailbox_from_userid (userid); @@ -657,10 +657,14 @@ command_check (char *userid) for (sl = mboxes; sl; sl = sl->next) { - if (!strcmp (sl->d, addrspec)) + if (sl->mbox && !strcmp (sl->mbox, addrspec)) found = 1; if (opt.verbose) - log_info (" addr-spec: %s\n", sl->d); + { + log_info (" user-id: %s\n", sl->uid); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); + } } if (!found) { @@ -671,7 +675,7 @@ command_check (char *userid) leave: xfree (fpr); - free_strlist (mboxes); + free_uidinfo_list (mboxes); es_fclose (key); xfree (addrspec); return err; @@ -682,7 +686,7 @@ command_check (char *userid) /* Locate the key by fingerprint and userid and send a publication * request. */ static gpg_error_t -command_send (const char *fingerprint, char *userid) +command_send (const char *fingerprint, const char *userid) { gpg_error_t err; KEYDB_SEARCH_DESC desc; @@ -706,6 +710,7 @@ command_send (const char *fingerprint, char *userid) err = gpg_error (GPG_ERR_INV_NAME); goto leave; } + addrspec = mailbox_from_userid (userid); if (!addrspec) { diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index 1633a2084..f7aadba3d 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -127,7 +127,7 @@ static struct debug_flags_s debug_flags [] = struct server_ctx_s { char *fpr; - strlist_t mboxes; /* List of addr-specs taken from the UIDs. */ + uidinfo_list_t mboxes; /* List with addr-specs taken from the UIDs. */ unsigned int draft_version_2:1; /* Client supports the draft 2. */ }; typedef struct server_ctx_s *server_ctx_t; @@ -1092,7 +1092,7 @@ static gpg_error_t process_new_key (server_ctx_t ctx, estream_t key) { gpg_error_t err; - strlist_t sl; + uidinfo_list_t sl; const char *s; char *dname = NULL; char *nonce = NULL; @@ -1101,7 +1101,7 @@ process_new_key (server_ctx_t ctx, estream_t key) /* First figure out the user id from the key. */ xfree (ctx->fpr); - free_strlist (ctx->mboxes); + free_uidinfo_list (ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; @@ -1114,14 +1114,17 @@ process_new_key (server_ctx_t ctx, estream_t key) log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) { - log_info (" addr-spec: %s\n", sl->d); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); } /* Walk over all user ids and send confirmation requests for those * we support. */ for (sl = ctx->mboxes; sl; sl = sl->next) { - s = strchr (sl->d, '@'); + if (!sl->mbox) + continue; + s = strchr (sl->mbox, '@'); log_assert (s && s[1]); xfree (dname); dname = make_filename_try (opt.directory, s+1, NULL); @@ -1133,26 +1136,26 @@ process_new_key (server_ctx_t ctx, estream_t key) if (access (dname, W_OK)) { - log_info ("skipping address '%s': Domain not configured\n", sl->d); + log_info ("skipping address '%s': Domain not configured\n", sl->mbox); continue; } - if (get_policy_flags (&policybuf, sl->d)) + if (get_policy_flags (&policybuf, sl->mbox)) { - log_info ("skipping address '%s': Bad policy flags\n", sl->d); + log_info ("skipping address '%s': Bad policy flags\n", sl->mbox); continue; } if (policybuf.auth_submit) { /* Bypass the confirmation stuff and publish the key as is. */ - log_info ("publishing address '%s'\n", sl->d); + log_info ("publishing address '%s'\n", sl->mbox); /* FIXME: We need to make sure that we do this only for the * address in the mail. */ log_debug ("auth-submit not yet working!\n"); } else { - log_info ("storing address '%s'\n", sl->d); + log_info ("storing address '%s'\n", sl->mbox); xfree (nonce); xfree (fname); @@ -1160,7 +1163,7 @@ process_new_key (server_ctx_t ctx, estream_t key) if (err) goto leave; - err = send_confirmation_request (ctx, sl->d, nonce, fname); + err = send_confirmation_request (ctx, sl->mbox, nonce, fname); if (err) goto leave; } @@ -1313,7 +1316,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) char *hash = NULL; const char *domain; const char *s; - strlist_t sl; + uidinfo_list_t sl; char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */ /* FIXME: There is a bug in name-value.c which adds white space for @@ -1351,7 +1354,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) /* We need to get the fingerprint from the key. */ xfree (ctx->fpr); - free_strlist (ctx->mboxes); + free_uidinfo_list (ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; @@ -1363,13 +1366,14 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) } log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) - log_info (" addr-spec: %s\n", sl->d); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); /* Check that the key has 'address' as a user id. We use * case-insensitive matching because the client is expected to * return the address verbatim. */ for (sl = ctx->mboxes; sl; sl = sl->next) - if (!strcmp (sl->d, address)) + if (sl->mbox && !strcmp (sl->mbox, address)) break; if (!sl) { @@ -1565,7 +1569,7 @@ command_receive_cb (void *opaque, const char *mediatype, } xfree (ctx.fpr); - free_strlist (ctx.mboxes); + free_uidinfo_list (ctx.mboxes); return err; } diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index caea98e2f..7fc8d9acd 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -69,11 +69,23 @@ struct policy_flags_s typedef struct policy_flags_s *policy_flags_t; +/* An object to convey user ids of a key. */ +struct uidinfo_list_s +{ + struct uidinfo_list_s *next; + char *mbox; /* NULL or the malloced mailbox from UID. */ + char uid[1]; +}; +typedef struct uidinfo_list_s *uidinfo_list_t; + + /*-- wks-util.c --*/ void wks_set_status_fd (int fd); void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); -gpg_error_t wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes); +void free_uidinfo_list (uidinfo_list_t list); +gpg_error_t wks_list_key (estream_t key, char **r_fpr, + uidinfo_list_t *r_mboxes); gpg_error_t wks_send_mime (mime_maker_t mime); gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown); diff --git a/tools/wks-util.c b/tools/wks-util.c index 45237b2b4..bc076a7c0 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -89,6 +89,48 @@ wks_write_status (int no, const char *format, ...) } + + +/* Append UID to LIST and return the new item. On success LIST is + * updated. On error ERRNO is set and NULL returned. */ +static uidinfo_list_t +append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) +{ + uidinfo_list_t r, sl; + + sl = xtrymalloc (sizeof *sl + strlen (uid)); + if (!sl) + return NULL; + + strcpy (sl->uid, uid); + sl->mbox = mailbox_from_userid (uid); + sl->next = NULL; + if (!*list) + *list = sl; + else + { + for (r = *list; r->next; r = r->next ) + ; + r->next = sl; + } + return sl; +} + + +/* Free the list of uid infos at LIST. */ +void +free_uidinfo_list (uidinfo_list_t list) +{ + while (list) + { + uidinfo_list_t tmp = list->next; + xfree (list->mbox); + xfree (list); + list = tmp; + } +} + + /* Helper for wks_list_key. */ static void @@ -105,7 +147,7 @@ list_key_status_cb (void *opaque, const char *keyword, char *args) * list of mailboxes at R_MBOXES. Returns 0 on success; on error NULL * is stored at R_FPR and R_MBOXES and an error code is returned. */ gpg_error_t -wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) +wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) { gpg_error_t err; ccparray_t ccp; @@ -118,9 +160,8 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) char **fields = NULL; int nfields; int lnr; - char *mbox = NULL; char *fpr = NULL; - strlist_t mboxes = NULL; + uidinfo_list_t mboxes = NULL; *r_fpr = NULL; *r_mboxes = NULL; @@ -232,9 +273,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) else if (!strcmp (fields[0], "uid") && nfields > 9) { /* Fixme: Unescape fields[9] */ - xfree (mbox); - mbox = mailbox_from_userid (fields[9]); - if (mbox && !append_to_strlist_try (&mboxes, mbox)) + if (!append_to_uidinfo_list (&mboxes, fields[9])) { err = gpg_error_from_syserror (); goto leave; @@ -255,8 +294,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) leave: xfree (fpr); - xfree (mboxes); - xfree (mbox); + free_uidinfo_list (mboxes); xfree (fields); es_free (line); xfree (argv); From a0035986a8615df056182bb9af775b8b7b22003d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 11:31:36 +0200 Subject: [PATCH 12/20] wks: Print the UID creation time with gpg-wks-client --check. * tools/gpg-wks.h (uidinfo_list_s): Add field 'created'. * tools/wks-util.c (append_to_uidinfo_list): Add arf 'created'. (wks_list_key): Pass timestamp to append_to_uidinfo_list. * tools/gpg-wks-client.c (command_check): Print UID creation time. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 1 + tools/gpg-wks.h | 1 + tools/wks-util.c | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 6b83de8c5..18a0edd72 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -662,6 +662,7 @@ command_check (char *userid) if (opt.verbose) { log_info (" user-id: %s\n", sl->uid); + log_info (" created: %s\n", asctimestamp (sl->created)); if (sl->mbox) log_info (" addr-spec: %s\n", sl->mbox); } diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index 7fc8d9acd..cb89fd501 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -73,6 +73,7 @@ typedef struct policy_flags_s *policy_flags_t; struct uidinfo_list_s { struct uidinfo_list_s *next; + time_t created; /* Time the userid was created. */ char *mbox; /* NULL or the malloced mailbox from UID. */ char uid[1]; }; diff --git a/tools/wks-util.c b/tools/wks-util.c index bc076a7c0..8fc0a2e5c 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -94,7 +94,7 @@ wks_write_status (int no, const char *format, ...) /* Append UID to LIST and return the new item. On success LIST is * updated. On error ERRNO is set and NULL returned. */ static uidinfo_list_t -append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) +append_to_uidinfo_list (uidinfo_list_t *list, const char *uid, time_t created) { uidinfo_list_t r, sl; @@ -103,6 +103,7 @@ append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) return NULL; strcpy (sl->uid, uid); + sl->created = created; sl->mbox = mailbox_from_userid (uid); sl->next = NULL; if (!*list) @@ -273,7 +274,8 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) else if (!strcmp (fields[0], "uid") && nfields > 9) { /* Fixme: Unescape fields[9] */ - if (!append_to_uidinfo_list (&mboxes, fields[9])) + if (!append_to_uidinfo_list (&mboxes, fields[9], + parse_timestamp (fields[5], NULL))) { err = gpg_error_from_syserror (); goto leave; From 7f7f5d06fa5aa3a3c5ab8d2e59ee76207bfdeaa0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 12:52:20 +0200 Subject: [PATCH 13/20] wks: Send only the newest UID to the server. * tools/wks-util.c (list_key_status_cb): Rename to key_status_cb. (wks_filter_uid): New. (wks_list_key): Allow FPR to be NULL. Return an error if no fingerprint was found. * tools/gpg-wks-server.c (process_new_key) (check_and_publish): Remove now useless extra check for FPR. * tools/gpg-wks-client.c (command_check): Ditto. (command_send): Filter out the newest uid. -- This fixes the case of having several userids with all the the same mailbox. Now we use the latest user id created. This patch is also a prerequisite to automatically create a new user id for providers with the mailbox-only policy. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 60 ++++++++++++++++++++++-- tools/gpg-wks-server.c | 14 +----- tools/gpg-wks.h | 2 + tools/wks-util.c | 104 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 158 insertions(+), 22 deletions(-) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 18a0edd72..37b75606b 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -644,10 +644,9 @@ command_check (char *userid) /* Look closer at the key. */ err = wks_list_key (key, &fpr, &mboxes); - if (err || !fpr) + if (err) { - log_error ("error parsing key: %s\n", - err? gpg_strerror (err) : "no fingerprint found"); + log_error ("error parsing key: %s\n", gpg_strerror (err)); err = gpg_error (GPG_ERR_NO_PUBKEY); goto leave; } @@ -700,6 +699,9 @@ command_send (const char *fingerprint, const char *userid) int no_encrypt = 0; int posteo_hack = 0; const char *domain; + uidinfo_list_t uidlist = NULL; + uidinfo_list_t uid, thisuid; + time_t thistime; memset (&policy, 0, sizeof policy); @@ -769,6 +771,57 @@ command_send (const char *fingerprint, const char *userid) if (policy.auth_submit) log_info ("no confirmation required for '%s'\n", addrspec); + /* In case the key has several uids with the same addr-spec we will + * use the newest one. */ + err = wks_list_key (key, NULL, &uidlist); + if (err) + { + log_error ("error parsing key: %s\n",gpg_strerror (err)); + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + thistime = 0; + thisuid = NULL; + for (uid = uidlist; uid; uid = uid->next) + { + if (!uid->mbox) + continue; /* Should not happen anyway. */ + if (uid->created > thistime) + { + thistime = uid->created; + thisuid = uid; + } + } + if (!thisuid) + thisuid = uid; /* This is the case for a missing timestamp. */ + if (opt.verbose) + log_info ("submitting key with user id '%s'\n", thisuid->uid); + + /* If we have more than one user id we need to filter the key to + * include only THISUID. */ + if (uidlist->next) + { + estream_t newkey; + + es_rewind (key); + err = wks_filter_uid (&newkey, key, thisuid->uid); + if (err) + { + log_error ("error filtering key: %s\n", gpg_strerror (err)); + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + es_fclose (key); + key = newkey; + } + + if (policy.mailbox_only + && ascii_strcasecmp (userid, addrspec)) + { + log_info ("Warning: policy requires 'mailbox-only'" + " - creating new user id'\n"); + } + /* Hack to support posteo but let them disable this by setting the * new policy-version flag. */ if (policy.protocol_version < 3 @@ -885,6 +938,7 @@ command_send (const char *fingerprint, const char *userid) leave: mime_maker_release (mime); xfree (submission_to); + free_uidinfo_list (uidlist); es_fclose (keyenc); es_fclose (key); xfree (addrspec); diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index f7aadba3d..7e3f05017 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -1105,12 +1105,7 @@ process_new_key (server_ctx_t ctx, estream_t key) err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; - if (!ctx->fpr) - { - log_error ("error parsing key (no fingerprint)\n"); - err = gpg_error (GPG_ERR_NO_PUBKEY); - goto leave; - } + log_assert (ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) { @@ -1358,12 +1353,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; - if (!ctx->fpr) - { - log_error ("error parsing key (no fingerprint)\n"); - err = gpg_error (GPG_ERR_NO_PUBKEY); - goto leave; - } + log_assert (ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) if (sl->mbox) diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index cb89fd501..ece7add5f 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -87,6 +87,8 @@ void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); void free_uidinfo_list (uidinfo_list_t list); gpg_error_t wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes); +gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key, + const char *uid); gpg_error_t wks_send_mime (mime_maker_t mime); gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown); diff --git a/tools/wks-util.c b/tools/wks-util.c index 8fc0a2e5c..889ca36dc 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -133,9 +133,9 @@ free_uidinfo_list (uidinfo_list_t list) -/* Helper for wks_list_key. */ +/* Helper for wks_list_key and wks_filter_uid. */ static void -list_key_status_cb (void *opaque, const char *keyword, char *args) +key_status_cb (void *opaque, const char *keyword, char *args) { (void)opaque; @@ -146,7 +146,8 @@ list_key_status_cb (void *opaque, const char *keyword, char *args) /* Run gpg on KEY and store the primary fingerprint at R_FPR and the * list of mailboxes at R_MBOXES. Returns 0 on success; on error NULL - * is stored at R_FPR and R_MBOXES and an error code is returned. */ + * is stored at R_FPR and R_MBOXES and an error code is returned. + * R_FPR may be NULL if the fingerprint is not needed. */ gpg_error_t wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) { @@ -164,7 +165,8 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) char *fpr = NULL; uidinfo_list_t mboxes = NULL; - *r_fpr = NULL; + if (r_fpr) + *r_fpr = NULL; *r_mboxes = NULL; /* Open a memory stream. */ @@ -200,7 +202,7 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) } err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, NULL, listing, - list_key_status_cb, NULL); + key_status_cb, NULL); if (err) { log_error ("import failed: %s\n", gpg_strerror (err)); @@ -289,8 +291,17 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) goto leave; } - *r_fpr = fpr; - fpr = NULL; + if (!fpr) + { + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + + if (r_fpr) + { + *r_fpr = fpr; + fpr = NULL; + } *r_mboxes = mboxes; mboxes = NULL; @@ -305,6 +316,85 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) } +/* Run gpg as a filter on KEY and write the output to a new stream + * stored at R_NEWKEY. The new key will containn only the user id + * UID. Returns 0 on success. Only one key is expected in KEY. */ +gpg_error_t +wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid) +{ + gpg_error_t err; + ccparray_t ccp; + const char **argv = NULL; + estream_t newkey; + char *filterexp = NULL; + + *r_newkey = NULL; + + /* Open a memory stream. */ + newkey = es_fopenmem (0, "w+b"); + if (!newkey) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + return err; + } + + /* Prefix the key with the MIME content type. */ + es_fputs ("Content-Type: application/pgp-keys\n" + "\n", newkey); + + filterexp = es_bsprintf ("keep-uid=uid=%s", uid); + if (!filterexp) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + goto leave; + } + + ccparray_init (&ccp, 0); + + ccparray_put (&ccp, "--no-options"); + if (!opt.verbose) + ccparray_put (&ccp, "--quiet"); + else if (opt.verbose > 1) + ccparray_put (&ccp, "--verbose"); + ccparray_put (&ccp, "--batch"); + ccparray_put (&ccp, "--status-fd=2"); + ccparray_put (&ccp, "--always-trust"); + ccparray_put (&ccp, "--armor"); + ccparray_put (&ccp, "--import-options=import-export"); + ccparray_put (&ccp, "--import-filter"); + ccparray_put (&ccp, filterexp); + ccparray_put (&ccp, "--import"); + + ccparray_put (&ccp, NULL); + argv = ccparray_get (&ccp, NULL); + if (!argv) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, + NULL, newkey, + key_status_cb, NULL); + if (err) + { + log_error ("import/export failed: %s\n", gpg_strerror (err)); + goto leave; + } + + es_rewind (newkey); + *r_newkey = newkey; + newkey = NULL; + + leave: + xfree (filterexp); + xfree (argv); + es_fclose (newkey); + return err; +} + + /* Helper to write mail to the output(s). */ gpg_error_t wks_send_mime (mime_maker_t mime) From 50c8b6c88f5d9f4b6c4e9c03aee31fe29afa94b8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 15:37:21 +0200 Subject: [PATCH 14/20] wks: Create a new user id if provider wants mailbox-only. * tools/gpg-wks-client.c (get_key): Add arg 'exact'. (add_user_id): New. (command_send): Create new user id. Signed-off-by: Werner Koch --- doc/wks.texi | 4 ++- tools/gpg-wks-client.c | 77 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/doc/wks.texi b/doc/wks.texi index f9b1a0c14..029dbf0c0 100644 --- a/doc/wks.texi +++ b/doc/wks.texi @@ -78,7 +78,9 @@ the command is a properly formatted mail with all standard headers. This mail can be fed to @command{sendmail(8)} or any other tool to actually send that mail. If @command{sendmail(8)} is installed the option @option{--send} can be used to directly send the created -request. +request. If the provider request a 'mailbox-only' user id and no such +user id is found, @command{gpg-wks-client} will try an additional user +id. The @option{--receive} and @option{--read} commands are used to process confirmation mails as send from the service provider. The diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 37b75606b..73a8a1f43 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -348,10 +348,13 @@ get_key_status_cb (void *opaque, const char *keyword, char *args) /* Get a key by fingerprint from gpg's keyring and make sure that the - * mail address ADDRSPEC is included in the key. The key is returned - * as a new memory stream at R_KEY. */ + * mail address ADDRSPEC is included in the key. If EXACT is set the + * returned user id must match Addrspec exactly and not just in the + * addr-spec (mailbox) part. The key is returned as a new memory + * stream at R_KEY. */ static gpg_error_t -get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) +get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, + int exact) { gpg_error_t err; ccparray_t ccp; @@ -376,7 +379,7 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) es_fputs ("Content-Type: application/pgp-keys\n" "\n", key); - filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec); + filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec); if (!filterexp) { err = gpg_error_from_syserror (); @@ -435,6 +438,49 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) } +/* Add the user id UID to the key identified by FINGERPRINT. */ +static gpg_error_t +add_user_id (const char *fingerprint, const char *uid) +{ + gpg_error_t err; + ccparray_t ccp; + const char **argv = NULL; + + ccparray_init (&ccp, 0); + + ccparray_put (&ccp, "--no-options"); + if (!opt.verbose) + ccparray_put (&ccp, "--quiet"); + else if (opt.verbose > 1) + ccparray_put (&ccp, "--verbose"); + ccparray_put (&ccp, "--batch"); + ccparray_put (&ccp, "--always-trust"); + ccparray_put (&ccp, "--quick-add-uid"); + ccparray_put (&ccp, fingerprint); + ccparray_put (&ccp, uid); + + ccparray_put (&ccp, NULL); + argv = ccparray_get (&ccp, NULL); + if (!argv) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL, + NULL, NULL, + NULL, NULL); + if (err) + { + log_error ("adding user id failed: %s\n", gpg_strerror (err)); + goto leave; + } + + leave: + xfree (argv); + return err; +} + + struct decrypt_stream_parm_s { @@ -721,7 +767,7 @@ command_send (const char *fingerprint, const char *userid) err = gpg_error (GPG_ERR_INV_USER_ID); goto leave; } - err = get_key (&key, fingerprint, addrspec); + err = get_key (&key, fingerprint, addrspec, 0); if (err) goto leave; @@ -786,6 +832,9 @@ command_send (const char *fingerprint, const char *userid) { if (!uid->mbox) continue; /* Should not happen anyway. */ + if (policy.mailbox_only + && ascii_strcasecmp (uid->uid, uid->mbox)) + continue; /* UID has more than just the mailbox. */ if (uid->created > thistime) { thistime = uid->created; @@ -793,7 +842,7 @@ command_send (const char *fingerprint, const char *userid) } } if (!thisuid) - thisuid = uid; /* This is the case for a missing timestamp. */ + thisuid = uidlist; /* This is the case for a missing timestamp. */ if (opt.verbose) log_info ("submitting key with user id '%s'\n", thisuid->uid); @@ -816,10 +865,22 @@ command_send (const char *fingerprint, const char *userid) } if (policy.mailbox_only - && ascii_strcasecmp (userid, addrspec)) + && (!thisuid->mbox || ascii_strcasecmp (thisuid->uid, thisuid->mbox))) { log_info ("Warning: policy requires 'mailbox-only'" - " - creating new user id'\n"); + " - adding user id '%s'\n", addrspec); + err = add_user_id (fingerprint, addrspec); + if (err) + goto leave; + + /* Need to get the key again. This time we request filtering + * for the full user id, so that we do not need check and filter + * the key again. */ + es_fclose (key); + key = NULL; + err = get_key (&key, fingerprint, addrspec, 1); + if (err) + goto leave; } /* Hack to support posteo but let them disable this by setting the From 9588dd116c0118f31fc33dc09a1d08125ab8cdc9 Mon Sep 17 00:00:00 2001 From: Dimitris Maroulidis Date: Mon, 18 Sep 2017 16:23:43 +0200 Subject: [PATCH 15/20] po: Minor Grammar update of the Greek translation -- GnuPG-bug-id: 3409 Signed-off-by: Werner Koch --- po/el.po | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/po/el.po b/po/el.po index dd690a46e..a57c8b8dd 100644 --- a/po/el.po +++ b/po/el.po @@ -1,20 +1,21 @@ # Greek Translation of GnuPG. # Copyright (C) 2002 Free Software Foundation, Inc. # Dokianakis Theofanis , 2002. -# !-- psbl.surriel.com rejected (2011-01-11) +# !-- psbl.surriel.com rejected (2011-01-11) # Designated-Translator: none -# +# Dimitris Maroulidis , 2017. msgid "" msgstr "" "Project-Id-Version: gnupg-1.1.92\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2003-06-27 12:00+0200\n" -"Last-Translator: Dokianakis Theofanis \n" -"Language-Team: Greek \n" +"PO-Revision-Date: 2017-09-14 21:14+0300\n" +"Last-Translator: Dimitris Maroulidis \n" +"Language-Team: team@gnome.gr\n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" #, fuzzy, c-format msgid "failed to acquire the pinentry lock: %s\n" @@ -4423,7 +4424,7 @@ msgid "Keyring" msgstr "Κλειδοθήκη" msgid "Primary key fingerprint:" -msgstr "Αποτύπωμα πρωτεύων κλειδιού:" +msgstr "Αποτύπωμα πρωτεύοντος κλειδιού:" msgid " Subkey fingerprint:" msgstr " Αποτύπωμα υποκλειδιού:" @@ -4431,7 +4432,7 @@ msgstr " Αποτύπωμα υποκλειδιού:" #. TRANSLATORS: this should fit into 24 bytes so that the #. * fingerprint data is properly aligned with the user ID msgid " Primary key fingerprint:" -msgstr " Αποτύπωμα πρωτεύων κλειδιού:" +msgstr " Αποτύπωμα πρωτ. κλειδιού:" msgid " Subkey fingerprint:" msgstr " Αποτύπωμα υποκλειδιού:" From df692a6167be5486f9a29da003a00292fd895176 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 22:49:05 +0200 Subject: [PATCH 16/20] dirmngr: Use system certs if --hkp-cacert is not used. * dirmngr/certcache.c (any_cert_of_class): New var. (put_cert): Set it. (cert_cache_deinit): Clear it. (cert_cache_any_in_class): New func. * dirmngr/http-ntbtls.c (gnupg_http_tls_verify_cb): Add hack to override empty list of HKP certs. -- This patch carries the changes for GNUTLS from commit 7c1613d41566f7d8db116790087de323621205fe over to NTBTLS. NTBTLS works quite different and thus we need to do it this way. Signed-off-by: Werner Koch --- dirmngr/certcache.c | 18 +++++++++++++++++- dirmngr/certcache.h | 3 +++ dirmngr/http-ntbtls.c | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index b4e538131..56629fdda 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -94,6 +94,10 @@ static int initialization_done; /* Total number of non-permanent certificates. */ static unsigned int total_nonperm_certificates; +/* For each cert class the corresponding bit is set if at least one + * certificate of that class is loaded permanetly. */ +static unsigned int any_cert_of_class; + #ifdef HAVE_W32_SYSTEM /* We load some functions dynamically. Provide typedefs for tehse @@ -343,7 +347,9 @@ put_cert (ksba_cert_t cert, int permanent, unsigned int trustclass, ci->permanent = !!permanent; ci->trustclasses = trustclass; - if (!permanent) + if (permanent) + any_cert_of_class |= trustclass; + else total_nonperm_certificates++; return 0; @@ -758,6 +764,7 @@ cert_cache_deinit (int full) } total_nonperm_certificates = 0; + any_cert_of_class = 0; initialization_done = 0; release_cache_lock (); } @@ -814,6 +821,15 @@ cert_cache_print_stats (void) } +/* Return true if any cert of a class in MASK is permanently + * loaded. */ +int +cert_cache_any_in_class (unsigned int mask) +{ + return !!(any_cert_of_class & mask); +} + + /* Put CERT into the certificate cache. */ gpg_error_t cache_cert (ksba_cert_t cert) diff --git a/dirmngr/certcache.h b/dirmngr/certcache.h index 92529bf11..8d645836d 100644 --- a/dirmngr/certcache.h +++ b/dirmngr/certcache.h @@ -39,6 +39,9 @@ void cert_cache_deinit (int full); /* Print some statistics to the log file. */ void cert_cache_print_stats (void); +/* Return true if any cert of a class in MASK is permanently loaded. */ +int cert_cache_any_in_class (unsigned int mask); + /* Compute the fingerprint of the certificate CERT and put it into the 20 bytes large buffer DIGEST. Return address of this buffer. */ unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest); diff --git a/dirmngr/http-ntbtls.c b/dirmngr/http-ntbtls.c index 250db556c..ea66a4d73 100644 --- a/dirmngr/http-ntbtls.c +++ b/dirmngr/http-ntbtls.c @@ -91,6 +91,12 @@ gnupg_http_tls_verify_cb (void *opaque, validate_flags |= VALIDATE_FLAG_TRUST_HKP; if ((http_flags & HTTP_FLAG_TRUST_SYS)) validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM; + + /* If HKP trust is requested and there are no HKP certificates + * configured, also try thye standard system certificates. */ + if ((validate_flags & VALIDATE_FLAG_TRUST_HKP) + && !cert_cache_any_in_class (CERTTRUST_CLASS_HKP)) + validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM; } if ((http_flags & HTTP_FLAG_NO_CRL)) From 355ca9e9498740fb6294eec451507b4891ae01ec Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 19 Sep 2017 08:13:44 +0200 Subject: [PATCH 17/20] Release 2.2.1 --- NEWS | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 7510ff4e5..081dbcc61 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,24 @@ -Noteworthy changes in version 2.2.1 (unreleased) +Noteworthy changes in version 2.2.1 (2017-09-19) ------------------------------------------------ + * gpg: Fix formatting of the user id in batch mode key generation + if only "name-email" is given. + + * gpgv: Fix annoying "not suitable for" warnings. + + * wks: Convey only the newest user id to the provider. This is the + case if different names are used with the same addr-spec. + + * wks: Create a complying user id for provider policy mailbox-only. + + * wks: Add workaround for posteo.de. + + * scd: Fix the use of large ECC keys with an OpenPGP card. + + * dirmngr: Use system provided root certificates if no specific HKP + certificates are configured. If build with GNUTLS, this was + already the case. + Noteworthy changes in version 2.2.0 (2017-08-28) ------------------------------------------------ @@ -13,6 +31,8 @@ Noteworthy changes in version 2.2.0 (2017-08-28) * Fixed a few minor bugs. + See-also: gnupg-announce/2017q3/000413.html + Noteworthy changes in version 2.1.23 (2017-08-09) ------------------------------------------------- From e1f04616e410dd31a0aa91d331817bd087093c8d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 19 Sep 2017 08:34:36 +0200 Subject: [PATCH 18/20] Post release updates -- --- NEWS | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 081dbcc61..2dd4e53a0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 2.2.2 (unreleased) +------------------------------------------------ + + Noteworthy changes in version 2.2.1 (2017-09-19) ------------------------------------------------ diff --git a/configure.ac b/configure.ac index fbd5c1807..70c122615 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,7 @@ min_automake_version="1.14" m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [2]) -m4_define([mym4_micro], [1]) +m4_define([mym4_micro], [2]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release From 1e033aa39009edcf5fe2d2bc65bdcf1cf062b38e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sun, 24 Sep 2017 09:56:26 +0200 Subject: [PATCH 19/20] po: Fix German translation. -- Reported-by: engelmarkus --- po/de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/de.po b/po/de.po index 8174b3416..e0f1aef0b 100644 --- a/po/de.po +++ b/po/de.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg-2.1.0\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2017-08-09 12:49+0200\n" +"PO-Revision-Date: 2017-09-24 09:55+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: German \n" "Language: de\n" @@ -194,7 +194,7 @@ msgid "failed to create stream from socket: %s\n" msgstr "Das Erzeugen eines Datenstroms aus dem Socket schlug fehl: %s\n" msgid "Please insert the card with serial number" -msgstr "Die legen Sie die Karte mit der folgenden Seriennummer ein:" +msgstr "Bitte legen Sie die Karte mit der folgenden Seriennummer ein:" msgid "Please remove the current card and insert the one with serial number" msgstr "" From 93a2b7761297dc1d859126d7711abd35ba35d215 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 26 Sep 2017 11:52:18 +0200 Subject: [PATCH 20/20] po: Remove trailing colon from a German pinentry string. -- --- po/de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/de.po b/po/de.po index e0f1aef0b..2f82d9910 100644 --- a/po/de.po +++ b/po/de.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg-2.1.0\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2017-09-24 09:55+0200\n" +"PO-Revision-Date: 2017-09-26 11:51+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: German \n" "Language: de\n" @@ -194,7 +194,7 @@ msgid "failed to create stream from socket: %s\n" msgstr "Das Erzeugen eines Datenstroms aus dem Socket schlug fehl: %s\n" msgid "Please insert the card with serial number" -msgstr "Bitte legen Sie die Karte mit der folgenden Seriennummer ein:" +msgstr "Bitte legen Sie die Karte mit der folgenden Seriennummer ein" msgid "Please remove the current card and insert the one with serial number" msgstr ""