Merge branch 'STABLE-BRANCH-2-2' into master

--

Signed-off-by: Werner Koch <wk@gnupg.org>
Conflicts:
	NEWS - include release info from 2.2.1
	configure.ac - keep master.
This commit is contained in:
Werner Koch 2017-09-26 12:00:03 +02:00
commit cd2d758f3f
No known key found for this signature in database
GPG Key ID: CD21A80AC8C52565
15 changed files with 513 additions and 114 deletions

27
NEWS
View File

@ -1,10 +1,29 @@
Noteworthy changes in version 2.3.0 (unreleased) Noteworthy changes in version 2.3.0 (unreleased)
------------------------------------------------ ------------------------------------------------
Changes also found in 2.2.1:
* Release dates of 2.2.x versions: * gpg: Fix formatting of the user id in batch mode key generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if only "name-email" is given.
Version 2.2.1 (unreleased)
* 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.
Release dates of 2.2.x versions:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Version 2.2.1 (2017-09-19)
Noteworthy changes in version 2.2.0 (2017-08-28) Noteworthy changes in version 2.2.0 (2017-08-28)
@ -18,6 +37,8 @@ Noteworthy changes in version 2.2.0 (2017-08-28)
* Fixed a few minor bugs. * Fixed a few minor bugs.
See-also: gnupg-announce/2017q3/000413.html
Noteworthy changes in version 2.1.23 (2017-08-09) Noteworthy changes in version 2.1.23 (2017-08-09)
------------------------------------------------- -------------------------------------------------

View File

@ -94,6 +94,10 @@ static int initialization_done;
/* Total number of non-permanent certificates. */ /* Total number of non-permanent certificates. */
static unsigned int total_nonperm_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 #ifdef HAVE_W32_SYSTEM
/* We load some functions dynamically. Provide typedefs for tehse /* 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->permanent = !!permanent;
ci->trustclasses = trustclass; ci->trustclasses = trustclass;
if (!permanent) if (permanent)
any_cert_of_class |= trustclass;
else
total_nonperm_certificates++; total_nonperm_certificates++;
return 0; return 0;
@ -758,6 +764,7 @@ cert_cache_deinit (int full)
} }
total_nonperm_certificates = 0; total_nonperm_certificates = 0;
any_cert_of_class = 0;
initialization_done = 0; initialization_done = 0;
release_cache_lock (); 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. */ /* Put CERT into the certificate cache. */
gpg_error_t gpg_error_t
cache_cert (ksba_cert_t cert) cache_cert (ksba_cert_t cert)

View File

@ -39,6 +39,9 @@ void cert_cache_deinit (int full);
/* Print some statistics to the log file. */ /* Print some statistics to the log file. */
void cert_cache_print_stats (void); 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 /* Compute the fingerprint of the certificate CERT and put it into
the 20 bytes large buffer DIGEST. Return address of this buffer. */ the 20 bytes large buffer DIGEST. Return address of this buffer. */
unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest); unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest);

View File

@ -91,6 +91,12 @@ gnupg_http_tls_verify_cb (void *opaque,
validate_flags |= VALIDATE_FLAG_TRUST_HKP; validate_flags |= VALIDATE_FLAG_TRUST_HKP;
if ((http_flags & HTTP_FLAG_TRUST_SYS)) if ((http_flags & HTTP_FLAG_TRUST_SYS))
validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM; 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)) if ((http_flags & HTTP_FLAG_NO_CRL))

View File

@ -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 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 actually send that mail. If @command{sendmail(8)} is installed the
option @option{--send} can be used to directly send the created 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 The @option{--receive} and @option{--read} commands are used to
process confirmation mails as send from the service provider. The process confirmation mails as send from the service provider. The

View File

@ -202,6 +202,7 @@ main( int argc, char **argv )
dotlock_disable (); dotlock_disable ();
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
additional_weak_digest("MD5"); additional_weak_digest("MD5");
gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG);
pargs.argc = &argc; pargs.argc = &argc;
pargs.argv = &argv; pargs.argv = &argv;

View File

@ -3529,7 +3529,14 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
if( s2 ) if( s2 )
p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
if( s3 ) 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 (*r->u.value)
p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
else
p = stpcpy (p, s3);
}
append_to_parameter (para, r); append_to_parameter (para, r);
have_user_id=1; have_user_id=1;
} }

View File

@ -9,7 +9,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnupg-2.1.0\n" "Project-Id-Version: gnupg-2.1.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2017-08-09 12:49+0200\n" "PO-Revision-Date: 2017-09-26 11:51+0200\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n" "Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German <de@li.org>\n" "Language-Team: German <de@li.org>\n"
"Language: de\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" msgstr "Das Erzeugen eines Datenstroms aus dem Socket schlug fehl: %s\n"
msgid "Please insert the card with serial number" 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" msgid "Please remove the current card and insert the one with serial number"
msgstr "" msgstr ""

View File

@ -1,20 +1,21 @@
# Greek Translation of GnuPG. # Greek Translation of GnuPG.
# Copyright (C) 2002 Free Software Foundation, Inc. # Copyright (C) 2002 Free Software Foundation, Inc.
# Dokianakis Theofanis <madf@hellug.gr>, 2002. # Dokianakis Theofanis <madf@hellug.gr>, 2002.
# !-- psbl.surriel.com rejected (2011-01-11) # !-- psbl.surriel.com rejected (2011-01-11)
# Designated-Translator: none # Designated-Translator: none
# # Dimitris Maroulidis <dmaroulidis@dimitrismaroulidis.com>, 2017.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnupg-1.1.92\n" "Project-Id-Version: gnupg-1.1.92\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2003-06-27 12:00+0200\n" "PO-Revision-Date: 2017-09-14 21:14+0300\n"
"Last-Translator: Dokianakis Theofanis <madf@hellug.gr>\n" "Last-Translator: Dimitris Maroulidis <dmaroulidis@dimitrismaroulidis.com>\n"
"Language-Team: Greek <nls@tux.hellug.gr>\n" "Language-Team: team@gnome.gr\n"
"Language: el\n" "Language: el\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#, fuzzy, c-format #, fuzzy, c-format
msgid "failed to acquire the pinentry lock: %s\n" msgid "failed to acquire the pinentry lock: %s\n"
@ -4423,7 +4424,7 @@ msgid "Keyring"
msgstr "Κλειδοθήκη" msgstr "Κλειδοθήκη"
msgid "Primary key fingerprint:" msgid "Primary key fingerprint:"
msgstr "Αποτύπωμα πρωτεύων κλειδιού:" msgstr "Αποτύπωμα πρωτεύοντος κλειδιού:"
msgid " Subkey fingerprint:" msgid " Subkey fingerprint:"
msgstr " Αποτύπωμα υποκλειδιού:" msgstr " Αποτύπωμα υποκλειδιού:"
@ -4431,7 +4432,7 @@ msgstr " Αποτύπωμα υποκλειδιού:"
#. TRANSLATORS: this should fit into 24 bytes so that the #. TRANSLATORS: this should fit into 24 bytes so that the
#. * fingerprint data is properly aligned with the user ID #. * fingerprint data is properly aligned with the user ID
msgid " Primary key fingerprint:" msgid " Primary key fingerprint:"
msgstr " Αποτύπωμα πρωτεύων κλειδιού:" msgstr " Αποτύπωμα πρωτ. κλειδιού:"
msgid " Subkey fingerprint:" msgid " Subkey fingerprint:"
msgstr " Αποτύπωμα υποκλειδιού:" msgstr " Αποτύπωμα υποκλειδιού:"

View File

@ -119,7 +119,7 @@ const char *fake_submission_addr;
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN; static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
static gpg_error_t command_supported (char *userid); static gpg_error_t command_supported (char *userid);
static gpg_error_t command_check (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, static gpg_error_t encrypt_response (estream_t *r_output, estream_t input,
const char *addrspec, const char *addrspec,
const char *fingerprint); const char *fingerprint);
@ -348,13 +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 /* 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 * mail address ADDRSPEC is included in the key. If EXACT is set the
* as a new memory stream at R_KEY. * returned user id must match Addrspec exactly and not just in the
* * addr-spec (mailbox) part. The key is returned as a new memory
* Fixme: After we have implemented import and export filters for gpg * stream at R_KEY. */
* this function shall only return a key with just this user id. */
static gpg_error_t 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; gpg_error_t err;
ccparray_t ccp; ccparray_t ccp;
@ -379,7 +379,7 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
es_fputs ("Content-Type: application/pgp-keys\n" es_fputs ("Content-Type: application/pgp-keys\n"
"\n", key); "\n", key);
filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec); filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec);
if (!filterexp) if (!filterexp)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
@ -438,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 struct decrypt_stream_parm_s
{ {
@ -600,8 +643,8 @@ command_check (char *userid)
char *addrspec = NULL; char *addrspec = NULL;
estream_t key = NULL; estream_t key = NULL;
char *fpr = NULL; char *fpr = NULL;
strlist_t mboxes = NULL; uidinfo_list_t mboxes = NULL;
strlist_t sl; uidinfo_list_t sl;
int found = 0; int found = 0;
addrspec = mailbox_from_userid (userid); addrspec = mailbox_from_userid (userid);
@ -647,10 +690,9 @@ command_check (char *userid)
/* Look closer at the key. */ /* Look closer at the key. */
err = wks_list_key (key, &fpr, &mboxes); err = wks_list_key (key, &fpr, &mboxes);
if (err || !fpr) if (err)
{ {
log_error ("error parsing key: %s\n", log_error ("error parsing key: %s\n", gpg_strerror (err));
err? gpg_strerror (err) : "no fingerprint found");
err = gpg_error (GPG_ERR_NO_PUBKEY); err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave; goto leave;
} }
@ -660,10 +702,15 @@ command_check (char *userid)
for (sl = mboxes; sl; sl = sl->next) for (sl = mboxes; sl; sl = sl->next)
{ {
if (!strcmp (sl->d, addrspec)) if (sl->mbox && !strcmp (sl->mbox, addrspec))
found = 1; found = 1;
if (opt.verbose) if (opt.verbose)
log_info (" addr-spec: %s\n", sl->d); {
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);
}
} }
if (!found) if (!found)
{ {
@ -674,7 +721,7 @@ command_check (char *userid)
leave: leave:
xfree (fpr); xfree (fpr);
free_strlist (mboxes); free_uidinfo_list (mboxes);
es_fclose (key); es_fclose (key);
xfree (addrspec); xfree (addrspec);
return err; return err;
@ -685,7 +732,7 @@ command_check (char *userid)
/* Locate the key by fingerprint and userid and send a publication /* Locate the key by fingerprint and userid and send a publication
* request. */ * request. */
static gpg_error_t static gpg_error_t
command_send (const char *fingerprint, char *userid) command_send (const char *fingerprint, const char *userid)
{ {
gpg_error_t err; gpg_error_t err;
KEYDB_SEARCH_DESC desc; KEYDB_SEARCH_DESC desc;
@ -695,6 +742,12 @@ command_send (const char *fingerprint, char *userid)
char *submission_to = NULL; char *submission_to = NULL;
mime_maker_t mime = NULL; mime_maker_t mime = NULL;
struct policy_flags_s policy; struct policy_flags_s policy;
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); memset (&policy, 0, sizeof policy);
@ -706,6 +759,7 @@ command_send (const char *fingerprint, char *userid)
err = gpg_error (GPG_ERR_INV_NAME); err = gpg_error (GPG_ERR_INV_NAME);
goto leave; goto leave;
} }
addrspec = mailbox_from_userid (userid); addrspec = mailbox_from_userid (userid);
if (!addrspec) if (!addrspec)
{ {
@ -713,10 +767,14 @@ command_send (const char *fingerprint, char *userid)
err = gpg_error (GPG_ERR_INV_USER_ID); err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave; goto leave;
} }
err = get_key (&key, fingerprint, addrspec); err = get_key (&key, fingerprint, addrspec, 0);
if (err) if (err)
goto leave; goto leave;
domain = strchr (addrspec, '@');
log_assert (domain);
domain++;
/* Get the submission address. */ /* Get the submission address. */
if (fake_submission_addr) if (fake_submission_addr)
{ {
@ -727,11 +785,8 @@ command_send (const char *fingerprint, char *userid)
err = wkd_get_submission_address (addrspec, &submission_to); err = wkd_get_submission_address (addrspec, &submission_to);
if (err) if (err)
{ {
char *domain = strchr (addrspec, '@'); log_error (_("error looking up submission address for domain '%s': %s\n"),
if (domain) domain, gpg_strerror (err));
domain = domain + 1;
log_error (_("looking up WKS submission address for %s: %s\n"),
domain ? domain : addrspec, gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_NO_DATA) if (gpg_err_code (err) == GPG_ERR_NO_DATA)
log_error (_("this domain probably doesn't support WKS.\n")); log_error (_("this domain probably doesn't support WKS.\n"));
goto leave; goto leave;
@ -762,14 +817,92 @@ command_send (const char *fingerprint, char *userid)
if (policy.auth_submit) if (policy.auth_submit)
log_info ("no confirmation required for '%s'\n", addrspec); log_info ("no confirmation required for '%s'\n", addrspec);
/* Encrypt the key part. */ /* In case the key has several uids with the same addr-spec we will
es_rewind (key); * use the newest one. */
err = encrypt_response (&keyenc, key, submission_to, fingerprint); err = wks_list_key (key, NULL, &uidlist);
if (err) if (err)
goto leave; {
es_fclose (key); log_error ("error parsing key: %s\n",gpg_strerror (err));
key = NULL; 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 (policy.mailbox_only
&& ascii_strcasecmp (uid->uid, uid->mbox))
continue; /* UID has more than just the mailbox. */
if (uid->created > thistime)
{
thistime = uid->created;
thisuid = uid;
}
}
if (!thisuid)
thisuid = uidlist; /* 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
&& (!thisuid->mbox || ascii_strcasecmp (thisuid->uid, thisuid->mbox)))
{
log_info ("Warning: policy requires 'mailbox-only'"
" - 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
* 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. */
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. */ /* Send the key. */
err = mime_maker_new (&mime, NULL); err = mime_maker_new (&mime, NULL);
@ -787,40 +920,86 @@ command_send (const char *fingerprint, char *userid)
/* Tell server which draft we support. */ /* Tell server which draft we support. */
err = mime_maker_add_header (mime, "Wks-Draft-Version", err = mime_maker_add_header (mime, "Wks-Draft-Version",
STR2(WKS_DRAFT_VERSION)); STR2(WKS_DRAFT_VERSION));
if (err) if (err)
goto leave; goto leave;
err = mime_maker_add_header (mime, "Content-Type", if (no_encrypt)
"multipart/encrypted; " {
"protocol=\"application/pgp-encrypted\""); void *data;
if (err) size_t datalen, n;
goto leave;
err = mime_maker_add_container (mime);
if (err)
goto leave;
err = mime_maker_add_header (mime, "Content-Type", if (posteo_hack)
"application/pgp-encrypted"); {
if (err) /* Needs a multipart/mixed with one(!) attachment. It does
goto leave; * not grok a non-multipart mail. */
err = mime_maker_add_body (mime, "Version: 1\n"); err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
if (err) if (err)
goto leave; goto leave;
err = mime_maker_add_header (mime, "Content-Type", err = mime_maker_add_container (mime);
"application/octet-stream"); if (err)
if (err) goto leave;
goto leave; }
err = mime_maker_add_stream (mime, &keyenc); err = mime_maker_add_header (mime, "Content-type",
if (err) "application/pgp-keys");
goto leave; 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); err = wks_send_mime (mime);
leave: leave:
mime_maker_release (mime); mime_maker_release (mime);
xfree (submission_to); xfree (submission_to);
free_uidinfo_list (uidlist);
es_fclose (keyenc); es_fclose (keyenc);
es_fclose (key); es_fclose (key);
xfree (addrspec); xfree (addrspec);

View File

@ -127,7 +127,7 @@ static struct debug_flags_s debug_flags [] =
struct server_ctx_s struct server_ctx_s
{ {
char *fpr; 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. */ unsigned int draft_version_2:1; /* Client supports the draft 2. */
}; };
typedef struct server_ctx_s *server_ctx_t; 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) process_new_key (server_ctx_t ctx, estream_t key)
{ {
gpg_error_t err; gpg_error_t err;
strlist_t sl; uidinfo_list_t sl;
const char *s; const char *s;
char *dname = NULL; char *dname = NULL;
char *nonce = NULL; char *nonce = NULL;
@ -1101,27 +1101,25 @@ process_new_key (server_ctx_t ctx, estream_t key)
/* First figure out the user id from the key. */ /* First figure out the user id from the key. */
xfree (ctx->fpr); xfree (ctx->fpr);
free_strlist (ctx->mboxes); free_uidinfo_list (ctx->mboxes);
err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
if (err) if (err)
goto leave; goto leave;
if (!ctx->fpr) log_assert (ctx->fpr);
{
log_error ("error parsing key (no fingerprint)\n");
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
log_info ("fingerprint: %s\n", ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr);
for (sl = ctx->mboxes; sl; sl = sl->next) 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 /* Walk over all user ids and send confirmation requests for those
* we support. */ * we support. */
for (sl = ctx->mboxes; sl; sl = sl->next) 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]); log_assert (s && s[1]);
xfree (dname); xfree (dname);
dname = make_filename_try (opt.directory, s+1, NULL); dname = make_filename_try (opt.directory, s+1, NULL);
@ -1133,26 +1131,26 @@ process_new_key (server_ctx_t ctx, estream_t key)
if (access (dname, W_OK)) 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; 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; continue;
} }
if (policybuf.auth_submit) if (policybuf.auth_submit)
{ {
/* Bypass the confirmation stuff and publish the key as is. */ /* 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 /* FIXME: We need to make sure that we do this only for the
* address in the mail. */ * address in the mail. */
log_debug ("auth-submit not yet working!\n"); log_debug ("auth-submit not yet working!\n");
} }
else else
{ {
log_info ("storing address '%s'\n", sl->d); log_info ("storing address '%s'\n", sl->mbox);
xfree (nonce); xfree (nonce);
xfree (fname); xfree (fname);
@ -1160,7 +1158,7 @@ process_new_key (server_ctx_t ctx, estream_t key)
if (err) if (err)
goto leave; goto leave;
err = send_confirmation_request (ctx, sl->d, nonce, fname); err = send_confirmation_request (ctx, sl->mbox, nonce, fname);
if (err) if (err)
goto leave; goto leave;
} }
@ -1313,7 +1311,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
char *hash = NULL; char *hash = NULL;
const char *domain; const char *domain;
const char *s; const char *s;
strlist_t sl; uidinfo_list_t sl;
char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */ char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
/* FIXME: There is a bug in name-value.c which adds white space for /* FIXME: There is a bug in name-value.c which adds white space for
@ -1351,25 +1349,21 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
/* We need to get the fingerprint from the key. */ /* We need to get the fingerprint from the key. */
xfree (ctx->fpr); xfree (ctx->fpr);
free_strlist (ctx->mboxes); free_uidinfo_list (ctx->mboxes);
err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
if (err) if (err)
goto leave; goto leave;
if (!ctx->fpr) log_assert (ctx->fpr);
{
log_error ("error parsing key (no fingerprint)\n");
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
log_info ("fingerprint: %s\n", ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr);
for (sl = ctx->mboxes; sl; sl = sl->next) 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 /* Check that the key has 'address' as a user id. We use
* case-insensitive matching because the client is expected to * case-insensitive matching because the client is expected to
* return the address verbatim. */ * return the address verbatim. */
for (sl = ctx->mboxes; sl; sl = sl->next) for (sl = ctx->mboxes; sl; sl = sl->next)
if (!strcmp (sl->d, address)) if (sl->mbox && !strcmp (sl->mbox, address))
break; break;
if (!sl) if (!sl)
{ {
@ -1565,7 +1559,7 @@ command_receive_cb (void *opaque, const char *mediatype,
} }
xfree (ctx.fpr); xfree (ctx.fpr);
free_strlist (ctx.mboxes); free_uidinfo_list (ctx.mboxes);
return err; return err;
} }

View File

@ -63,16 +63,32 @@ struct policy_flags_s
unsigned int mailbox_only : 1; unsigned int mailbox_only : 1;
unsigned int dane_only : 1; unsigned int dane_only : 1;
unsigned int auth_submit : 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. */ unsigned int max_pending; /* Seconds to wait for a confirmation. */
}; };
typedef struct policy_flags_s *policy_flags_t; 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;
time_t created; /* Time the userid was created. */
char *mbox; /* NULL or the malloced mailbox from UID. */
char uid[1];
};
typedef struct uidinfo_list_s *uidinfo_list_t;
/*-- wks-util.c --*/ /*-- wks-util.c --*/
void wks_set_status_fd (int fd); void wks_set_status_fd (int fd);
void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); 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_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_send_mime (mime_maker_t mime);
gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
int ignore_unknown); int ignore_unknown);

View File

@ -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 /* 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. * 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 /* 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 * 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 * eventually we may delay that and read the stream only at the time

View File

@ -34,6 +34,8 @@ void mime_maker_dump_tree (mime_maker_t ctx);
gpg_error_t mime_maker_add_header (mime_maker_t ctx, gpg_error_t mime_maker_add_header (mime_maker_t ctx,
const char *name, const char *value); 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 (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_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_add_container (mime_maker_t ctx);
gpg_error_t mime_maker_end_container (mime_maker_t ctx); gpg_error_t mime_maker_end_container (mime_maker_t ctx);

View File

@ -90,9 +90,52 @@ wks_write_status (int no, const char *format, ...)
/* Helper for wks_list_key. */
/* 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, time_t created)
{
uidinfo_list_t r, sl;
sl = xtrymalloc (sizeof *sl + strlen (uid));
if (!sl)
return NULL;
strcpy (sl->uid, uid);
sl->created = created;
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 and wks_filter_uid. */
static void 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; (void)opaque;
@ -103,9 +146,10 @@ 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 /* 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 * 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 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; gpg_error_t err;
ccparray_t ccp; ccparray_t ccp;
@ -118,11 +162,11 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
char **fields = NULL; char **fields = NULL;
int nfields; int nfields;
int lnr; int lnr;
char *mbox = NULL;
char *fpr = NULL; char *fpr = NULL;
strlist_t mboxes = NULL; uidinfo_list_t mboxes = NULL;
*r_fpr = NULL; if (r_fpr)
*r_fpr = NULL;
*r_mboxes = NULL; *r_mboxes = NULL;
/* Open a memory stream. */ /* Open a memory stream. */
@ -158,7 +202,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
} }
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, listing, NULL, listing,
list_key_status_cb, NULL); key_status_cb, NULL);
if (err) if (err)
{ {
log_error ("import failed: %s\n", gpg_strerror (err)); log_error ("import failed: %s\n", gpg_strerror (err));
@ -232,9 +276,8 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
else if (!strcmp (fields[0], "uid") && nfields > 9) else if (!strcmp (fields[0], "uid") && nfields > 9)
{ {
/* Fixme: Unescape fields[9] */ /* Fixme: Unescape fields[9] */
xfree (mbox); if (!append_to_uidinfo_list (&mboxes, fields[9],
mbox = mailbox_from_userid (fields[9]); parse_timestamp (fields[5], NULL)))
if (mbox && !append_to_strlist_try (&mboxes, mbox))
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
goto leave; goto leave;
@ -248,15 +291,23 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
goto leave; goto leave;
} }
*r_fpr = fpr; if (!fpr)
fpr = NULL; {
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
if (r_fpr)
{
*r_fpr = fpr;
fpr = NULL;
}
*r_mboxes = mboxes; *r_mboxes = mboxes;
mboxes = NULL; mboxes = NULL;
leave: leave:
xfree (fpr); xfree (fpr);
xfree (mboxes); free_uidinfo_list (mboxes);
xfree (mbox);
xfree (fields); xfree (fields);
es_free (line); es_free (line);
xfree (argv); xfree (argv);
@ -265,6 +316,85 @@ wks_list_key (estream_t key, char **r_fpr, strlist_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). */ /* Helper to write mail to the output(s). */
gpg_error_t gpg_error_t
wks_send_mime (mime_maker_t mime) wks_send_mime (mime_maker_t mime)
@ -316,7 +446,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
TOK_MAILBOX_ONLY, TOK_MAILBOX_ONLY,
TOK_DANE_ONLY, TOK_DANE_ONLY,
TOK_AUTH_SUBMIT, TOK_AUTH_SUBMIT,
TOK_MAX_PENDING TOK_MAX_PENDING,
TOK_PROTOCOL_VERSION
}; };
static struct { static struct {
const char *name; const char *name;
@ -325,7 +456,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
{ "mailbox-only", TOK_MAILBOX_ONLY }, { "mailbox-only", TOK_MAILBOX_ONLY },
{ "dane-only", TOK_DANE_ONLY }, { "dane-only", TOK_DANE_ONLY },
{ "auth-submit", TOK_AUTH_SUBMIT }, { "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; gpg_error_t err = 0;
int lnr = 0; int lnr = 0;
@ -400,6 +532,14 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
* and decide whether to allow other units. */ * and decide whether to allow other units. */
flags->max_pending = atoi (value); flags->max_pending = atoi (value);
break; break;
case TOK_PROTOCOL_VERSION:
if (!value)
{
err = gpg_error (GPG_ERR_SYNTAX);
goto leave;
}
flags->protocol_version = atoi (value);
break;
} }
} }