mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
wkd: New option --add-revocs and some fixes.
* tools/gpg-wks.h (opt): Add add_revocs. * tools/wks-util.c (wks_get_key): Add arg 'binary'. (wks_armor_key): New. (wks_find_add_revocs): New. (wks_cmd_install_key): Get key in binary mode and add revocations if enabled. * tools/gpg-wks-client.c (oAddRevocs): New. (opts): Add --add-revocs. (parse_arguments): Set option, (command_send): Get key in binary mode, add revocations if enabled, and explictly armor key. Remove kludge to skip the Content-type line in no_encrypt mode. (mirror_one_keys_userid): Always filter the key to get rid of the armor as received from dirmngr. Add revocations from the local keyring. -- Note that this also fixes an oddity of the new mirror command which used to store the keys armored as received from dirmngr.
This commit is contained in:
parent
deac3e91eb
commit
2f4492f3be
@ -222,6 +222,14 @@ operation. The format of @var{file} is one mail address (just the
|
||||
addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines
|
||||
starting with a '#' are ignored.
|
||||
|
||||
@item --add-revocs
|
||||
@opindex add-revocs
|
||||
If enabled append revocation certificates for the same addrspec as
|
||||
used in the WKD to the key. Modern gpg version are able to import and
|
||||
apply them for existing keys. Note that when used with the
|
||||
@option{--mirror} command the revocation are searched in the local
|
||||
keyring and not in an LDAP directory.
|
||||
|
||||
@item --verbose
|
||||
@opindex verbose
|
||||
Enable extra informational output.
|
||||
|
@ -74,6 +74,7 @@ enum cmd_and_opt_values
|
||||
oWithColons,
|
||||
oBlacklist,
|
||||
oNoAutostart,
|
||||
oAddRevocs,
|
||||
|
||||
oDummy
|
||||
};
|
||||
@ -100,9 +101,9 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_c (aRemoveKey, "remove-key",
|
||||
"remove a key from a directory"),
|
||||
ARGPARSE_c (aPrintWKDHash, "print-wkd-hash",
|
||||
"Print the WKD identifier for the given user ids"),
|
||||
"print the WKD identifier for the given user ids"),
|
||||
ARGPARSE_c (aPrintWKDURL, "print-wkd-url",
|
||||
"Print the WKD URL for the given user id"),
|
||||
"print the WKD URL for the given user id"),
|
||||
|
||||
ARGPARSE_group (301, ("@\nOptions:\n ")),
|
||||
|
||||
@ -117,6 +118,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oWithColons, "with-colons", "@"),
|
||||
ARGPARSE_s_s (oBlacklist, "blacklist", "@"),
|
||||
ARGPARSE_s_s (oDirectory, "directory", "@"),
|
||||
ARGPARSE_s_n (oAddRevocs, "add-revocs", "add revocation certificates"),
|
||||
|
||||
ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"),
|
||||
|
||||
@ -254,6 +256,9 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
|
||||
case oBlacklist:
|
||||
add_blacklist (pargs->r.ret_str);
|
||||
break;
|
||||
case oAddRevocs:
|
||||
opt.add_revocs = 1;
|
||||
break;
|
||||
|
||||
case aSupported:
|
||||
case aCreate:
|
||||
@ -1145,7 +1150,7 @@ command_send (const char *fingerprint, const char *userid)
|
||||
err = gpg_error (GPG_ERR_INV_USER_ID);
|
||||
goto leave;
|
||||
}
|
||||
err = wks_get_key (&key, fingerprint, addrspec, 0);
|
||||
err = wks_get_key (&key, fingerprint, addrspec, 0, 1);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -1213,7 +1218,7 @@ command_send (const char *fingerprint, const char *userid)
|
||||
estream_t newkey;
|
||||
|
||||
es_rewind (key);
|
||||
err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
|
||||
err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error filtering key: %s\n", gpg_strerror (err));
|
||||
@ -1238,11 +1243,47 @@ command_send (const char *fingerprint, const char *userid)
|
||||
* the key again. */
|
||||
es_fclose (key);
|
||||
key = NULL;
|
||||
err = wks_get_key (&key, fingerprint, addrspec, 1);
|
||||
err = wks_get_key (&key, fingerprint, addrspec, 1, 1);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (opt.add_revocs)
|
||||
{
|
||||
if (es_fseek (key, 0, SEEK_END))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error seeking stream: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
err = wks_find_add_revocs (key, addrspec);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error finding revocations for '%s': %s\n",
|
||||
addrspec, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now put the armor around the key. */
|
||||
{
|
||||
estream_t newkey;
|
||||
|
||||
es_rewind (key);
|
||||
err = wks_armor_key (&newkey, key,
|
||||
no_encrypt? NULL
|
||||
/* */ : ("Content-Type: application/pgp-keys\n"
|
||||
"\n"));
|
||||
if (err)
|
||||
{
|
||||
log_error ("error armoring key: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
es_fclose (key);
|
||||
key = newkey;
|
||||
}
|
||||
|
||||
/* Hack to support posteo but let them disable this by setting the
|
||||
* new policy-version flag. */
|
||||
if (policy->protocol_version < 3
|
||||
@ -1287,7 +1328,7 @@ command_send (const char *fingerprint, const char *userid)
|
||||
if (no_encrypt)
|
||||
{
|
||||
void *data;
|
||||
size_t datalen, n;
|
||||
size_t datalen;
|
||||
|
||||
if (posteo_hack)
|
||||
{
|
||||
@ -1312,16 +1353,7 @@ command_send (const char *fingerprint, const char *userid)
|
||||
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);
|
||||
err = mime_maker_add_body_data (mime, data, datalen);
|
||||
xfree (data);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -1808,7 +1840,7 @@ domain_matches_mbox (const char *domain, const char *mbox)
|
||||
|
||||
/* Core of mirror_one_key with the goal of mirroring just one uid.
|
||||
* UIDLIST is used to figure out whether the given MBOX occurs several
|
||||
* times in UIDLIST and then to single out the newwest one. This is
|
||||
* times in UIDLIST and then to single out the newest one. This is
|
||||
* so that for a key with
|
||||
* uid: Joe Someone <joe@example.org>
|
||||
* uid: Joe <joe@example.org>
|
||||
@ -1849,24 +1881,36 @@ mirror_one_keys_userid (estream_t key, const char *mbox, uidinfo_list_t uidlist,
|
||||
err = gpg_error (GPG_ERR_NO_USER_ID);
|
||||
goto leave;
|
||||
}
|
||||
/* FIXME: Consult blacklist. */
|
||||
|
||||
|
||||
/* Only if we have more than one user id we bother to run the
|
||||
* filter. In this case the result will be put into NEWKEY*/
|
||||
/* Always filter the key so that the result will be non-armored. */
|
||||
es_rewind (key);
|
||||
if (uidlist->next)
|
||||
err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
|
||||
if (err)
|
||||
{
|
||||
err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
|
||||
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||
goto leave;
|
||||
}
|
||||
log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
|
||||
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = wks_install_key_core (newkey? newkey : key, mbox);
|
||||
if (opt.add_revocs)
|
||||
{
|
||||
if (es_fseek (newkey, 0, SEEK_END))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error seeking stream: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
err = wks_find_add_revocs (newkey, mbox);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error finding revocations for '%s': %s\n",
|
||||
mbox, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
es_rewind (newkey);
|
||||
}
|
||||
|
||||
err = wks_install_key_core (newkey, mbox);
|
||||
if (opt.verbose)
|
||||
log_info ("key %s published for '%s'\n", fpr, mbox);
|
||||
mirror_one_key_parm.nuids++;
|
||||
|
@ -39,6 +39,7 @@ struct
|
||||
int use_sendmail;
|
||||
int with_colons;
|
||||
int no_autostart;
|
||||
int add_revocs;
|
||||
const char *output;
|
||||
const char *gpg_program;
|
||||
const char *directory;
|
||||
@ -91,11 +92,14 @@ void wks_set_status_fd (int fd);
|
||||
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_get_key (estream_t *r_key, const char *fingerprint,
|
||||
const char *addrspec, int exact);
|
||||
const char *addrspec, int exact, int binary);
|
||||
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, int binary);
|
||||
gpg_error_t wks_armor_key (estream_t *r_newkey, estream_t key,
|
||||
const char *prefix);
|
||||
gpg_error_t wks_find_add_revocs (estream_t key, const char *addrspec);
|
||||
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);
|
||||
|
151
tools/wks-util.c
151
tools/wks-util.c
@ -193,10 +193,11 @@ get_key_status_cb (void *opaque, const char *keyword, char *args)
|
||||
* 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. */
|
||||
* stream at R_KEY. If BINARY is set the returned key is
|
||||
* non-armored. */
|
||||
gpg_error_t
|
||||
wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
|
||||
int exact)
|
||||
int exact, int binary)
|
||||
{
|
||||
gpg_error_t err;
|
||||
ccparray_t ccp;
|
||||
@ -218,8 +219,9 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
|
||||
}
|
||||
|
||||
/* Prefix the key with the MIME content type. */
|
||||
es_fputs ("Content-Type: application/pgp-keys\n"
|
||||
"\n", key);
|
||||
if (!binary)
|
||||
es_fputs ("Content-Type: application/pgp-keys\n"
|
||||
"\n", key);
|
||||
|
||||
filterexp = es_bsprintf ("keep-uid=%s= %s", exact? "uid":"mbox", addrspec);
|
||||
if (!filterexp)
|
||||
@ -239,7 +241,8 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
|
||||
ccparray_put (&ccp, "--batch");
|
||||
ccparray_put (&ccp, "--status-fd=2");
|
||||
ccparray_put (&ccp, "--always-trust");
|
||||
ccparray_put (&ccp, "--armor");
|
||||
if (!binary)
|
||||
ccparray_put (&ccp, "--armor");
|
||||
ccparray_put (&ccp, "--export-options=export-minimal");
|
||||
ccparray_put (&ccp, "--export-filter");
|
||||
ccparray_put (&ccp, filterexp);
|
||||
@ -550,6 +553,124 @@ wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid,
|
||||
}
|
||||
|
||||
|
||||
/* Put the ascii-armor around KEY and return that as a new estream
|
||||
* object at R_NEWKEY. Caller must make sure that KEY has been seeked
|
||||
* to the right position (usually by calling es_rewind). The
|
||||
* resulting NEWKEY has already been rewound. If PREFIX is not NULL,
|
||||
* its content is written to NEWKEY propr to the armor; this may be
|
||||
* used for MIME headers. */
|
||||
gpg_error_t
|
||||
wks_armor_key (estream_t *r_newkey, estream_t key, const char *prefix)
|
||||
{
|
||||
gpg_error_t err;
|
||||
estream_t newkey;
|
||||
struct b64state b64state;
|
||||
char buffer[4096];
|
||||
size_t nread;
|
||||
|
||||
*r_newkey = NULL;
|
||||
|
||||
newkey = es_fopenmem (0, "w+b");
|
||||
if (!newkey)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
es_fputs (prefix, newkey);
|
||||
|
||||
err = b64enc_start_es (&b64state, newkey, "PGP PUBLIC KEY BLOCK");
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
do
|
||||
{
|
||||
nread = es_fread (buffer, 1, sizeof buffer, key);
|
||||
if (!nread)
|
||||
break;
|
||||
err = b64enc_write (&b64state, buffer, nread);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
while (!es_feof (key) && !es_ferror (key));
|
||||
if (!es_feof (key) || es_ferror (key))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = b64enc_finish (&b64state);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
es_rewind (newkey);
|
||||
*r_newkey = newkey;
|
||||
newkey = NULL;
|
||||
|
||||
leave:
|
||||
es_fclose (newkey);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Run gpg to export the revocation certificates for ADDRSPEC. Add
|
||||
* them to KEY which is expected to be non-armored keyblock. */
|
||||
gpg_error_t
|
||||
wks_find_add_revocs (estream_t key, const char *addrspec)
|
||||
{
|
||||
gpg_error_t err;
|
||||
ccparray_t ccp;
|
||||
const char **argv = NULL;
|
||||
char *filterexp = NULL;
|
||||
|
||||
filterexp = es_bsprintf ("select=mbox= %s", addrspec);
|
||||
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 < 2)
|
||||
ccparray_put (&ccp, "--quiet");
|
||||
else
|
||||
ccparray_put (&ccp, "--verbose");
|
||||
ccparray_put (&ccp, "--batch");
|
||||
ccparray_put (&ccp, "--status-fd=2");
|
||||
ccparray_put (&ccp, "--export-options=export-revocs");
|
||||
ccparray_put (&ccp, "--export-filter");
|
||||
ccparray_put (&ccp, filterexp);
|
||||
ccparray_put (&ccp, "--export");
|
||||
ccparray_put (&ccp, addrspec);
|
||||
|
||||
ccparray_put (&ccp, NULL);
|
||||
argv = ccparray_get (&ccp, NULL);
|
||||
if (!argv)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
debug_gpg_invocation (__func__, argv);
|
||||
err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
|
||||
NULL, key,
|
||||
key_status_cb, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("exporting revocs failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (filterexp);
|
||||
xfree (argv);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Helper to write mail to the output(s). */
|
||||
gpg_error_t
|
||||
wks_send_mime (mime_maker_t mime)
|
||||
@ -1122,7 +1243,7 @@ wks_cmd_install_key (const char *fname, const char *userid)
|
||||
{
|
||||
/* FNAME looks like a fingerprint. Get the key from the
|
||||
* standard keyring. */
|
||||
err = wks_get_key (&fp, fname, addrspec, 0);
|
||||
err = wks_get_key (&fp, fname, addrspec, 0, 1);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error getting key '%s' (uid='%s'): %s\n",
|
||||
@ -1194,6 +1315,24 @@ wks_cmd_install_key (const char *fname, const char *userid)
|
||||
fp = fp2;
|
||||
}
|
||||
|
||||
if (opt.add_revocs)
|
||||
{
|
||||
if (es_fseek (fp, 0, SEEK_END))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error seeking stream: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
err = wks_find_add_revocs (fp, addrspec);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error finding revocations for '%s': %s\n",
|
||||
addrspec, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
es_rewind (fp);
|
||||
}
|
||||
|
||||
err = wks_install_key_core (fp, addrspec);
|
||||
if (!opt.quiet)
|
||||
log_info ("key %s published for '%s'\n", fpr, addrspec);
|
||||
|
Loading…
x
Reference in New Issue
Block a user