mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpg: Add experimental AKL method "wkd" and option --with-wkd-hash.
* g10/getkey.c (parse_auto_key_locate): Add method "wkd". (get_pubkey_byname): Implement that method. Also rename a variable. * g10/call-dirmngr.c (gpg_dirmngr_wkd_get): New. * g10/keyserver.c (keyserver_import_wkd): New. * g10/test-stubs.c (keyserver_import_wkd): Add stub. * g10/gpgv.c (keyserver_import_wkd): Ditto. * g10/options.h (opt): Add field 'with_wkd_hash'. (AKL_WKD): New. * g10/gpg.c (oWithWKDHash): New. (opts): Add option --with-wkd-hash. (main): Set that option. * g10/keylist.c (list_keyblock_print): Implement that option. -- The Web Key Directory is an experimental feature to retrieve a key via https. It is similar to OpenPGP DANE but also uses an encryption to reveal less information about a key lookup. For example the URI to lookup the key for Joe.Doe@Example.ORG is: https://example.org/.well-known/openpgpkey/ hu/example.org/iy9q119eutrkn8s1mk4r39qejnbu3n5q (line has been wrapped for rendering purposes). The hash is a z-Base-32 encoded SHA-1 hash of the mail address' local-part. The address wk@gnupg.org can be used for testing. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
c83c6f212e
commit
87de9e19ed
@ -1600,6 +1600,10 @@ mechanisms, in the order they are to be tried:
|
||||
Locate a key using DANE, as specified
|
||||
in draft-ietf-dane-openpgpkey-05.txt.
|
||||
|
||||
@item wkd
|
||||
Locate a key using the Web Key Directory protocol.
|
||||
This is an experimental method and semantics may change.
|
||||
|
||||
@item ldap
|
||||
Using DNS Service Discovery, check the domain in question for any LDAP
|
||||
keyservers to use. If this fails, attempt to locate the key using the
|
||||
@ -2235,6 +2239,11 @@ Print the ICAO spelling of the fingerprint in addition to the hex digits.
|
||||
@opindex with-keygrip
|
||||
Include the keygrip in the key listings.
|
||||
|
||||
@item --with-wkd-hash
|
||||
@opindex with-wkd-hash
|
||||
Print a Web Key Directory indentifier along with each user ID in key
|
||||
listings. This is an experimental feature and semantics may change.
|
||||
|
||||
@item --with-secret
|
||||
@opindex with-secret
|
||||
Include info about the presence of a secret key in public key listings
|
||||
|
@ -1064,7 +1064,7 @@ gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock)
|
||||
|
||||
|
||||
|
||||
/* Data callback for the DNS_CERT command. */
|
||||
/* Data callback for the DNS_CERT and WKD_GET commands. */
|
||||
static gpg_error_t
|
||||
dns_cert_data_cb (void *opaque, const void *data, size_t datalen)
|
||||
{
|
||||
@ -1287,3 +1287,62 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
|
||||
close_context (ctrl, ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Ask the dirmngr to retrieve a key via the Web Key Directory
|
||||
* protocol. On success a new estream with the key is stored at
|
||||
* R_KEY.
|
||||
*/
|
||||
gpg_error_t
|
||||
gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, estream_t *r_key)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
struct dns_cert_parm_s parm;
|
||||
char *line = NULL;
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
|
||||
err = open_context (ctrl, &ctx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
line = es_bsprintf ("WKD_GET -- %s", name);
|
||||
if (!line)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
parm.memfp = es_fopenmem (0, "rwb");
|
||||
if (!parm.memfp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
err = assuan_transact (ctx, line, dns_cert_data_cb, &parm,
|
||||
NULL, NULL, NULL, &parm);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (r_key)
|
||||
{
|
||||
es_rewind (parm.memfp);
|
||||
*r_key = parm.memfp;
|
||||
parm.memfp = NULL;
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (parm.fpr);
|
||||
xfree (parm.url);
|
||||
es_fclose (parm.memfp);
|
||||
xfree (line);
|
||||
close_context (ctrl, ctx);
|
||||
return err;
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ gpg_error_t gpg_dirmngr_dns_cert (ctrl_t ctrl,
|
||||
gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
|
||||
unsigned char **r_fpr, size_t *r_fprlen,
|
||||
char **r_url);
|
||||
gpg_error_t gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name,
|
||||
estream_t *r_key);
|
||||
|
||||
|
||||
#endif /*GNUPG_G10_CALL_DIRMNGR_H*/
|
||||
|
34
g10/getkey.c
34
g10/getkey.c
@ -1274,7 +1274,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
|
||||
{
|
||||
unsigned char *fpr = NULL;
|
||||
size_t fpr_len;
|
||||
int did_key_byname = 0;
|
||||
int did_akl_local = 0;
|
||||
int no_fingerprint = 0;
|
||||
const char *mechanism = "?";
|
||||
|
||||
@ -1288,7 +1288,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
|
||||
|
||||
case AKL_LOCAL:
|
||||
mechanism = "Local";
|
||||
did_key_byname = 1;
|
||||
did_akl_local = 1;
|
||||
if (retctx)
|
||||
{
|
||||
getkey_end (*retctx);
|
||||
@ -1321,6 +1321,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
|
||||
glo_ctrl.in_auto_key_retrieve--;
|
||||
break;
|
||||
|
||||
case AKL_WKD:
|
||||
mechanism = "WKD";
|
||||
glo_ctrl.in_auto_key_retrieve++;
|
||||
rc = keyserver_import_wkd (ctrl, name, &fpr, &fpr_len);
|
||||
glo_ctrl.in_auto_key_retrieve--;
|
||||
break;
|
||||
|
||||
case AKL_LDAP:
|
||||
mechanism = "LDAP";
|
||||
glo_ctrl.in_auto_key_retrieve++;
|
||||
@ -1386,22 +1393,20 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
|
||||
|
||||
add_to_strlist (&namelist, fpr_string);
|
||||
}
|
||||
else if (!rc && !fpr && !did_key_byname)
|
||||
/* The acquisition method said no failure occurred, but it
|
||||
didn't return a fingerprint. That's a failure. */
|
||||
{
|
||||
no_fingerprint = 1;
|
||||
else if (!rc && !fpr && !did_akl_local)
|
||||
{ /* The acquisition method said no failure occurred, but
|
||||
it didn't return a fingerprint. That's a failure. */
|
||||
no_fingerprint = 1;
|
||||
rc = GPG_ERR_NO_PUBKEY;
|
||||
}
|
||||
xfree (fpr);
|
||||
fpr = NULL;
|
||||
|
||||
if (!rc && !did_key_byname)
|
||||
/* There was no error and we didn't do a local lookup.
|
||||
This means that we imported a key into the local
|
||||
keyring. Try to read the imported key from the
|
||||
keyring. */
|
||||
{
|
||||
if (!rc && !did_akl_local)
|
||||
{ /* There was no error and we didn't do a local lookup.
|
||||
This means that we imported a key into the local
|
||||
keyring. Try to read the imported key from the
|
||||
keyring. */
|
||||
if (retctx)
|
||||
{
|
||||
getkey_end (*retctx);
|
||||
@ -3195,6 +3200,7 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tsubkey has expired\n");
|
||||
continue;
|
||||
|
||||
}
|
||||
if (pk->timestamp > curtime && !opt.ignore_valid_from)
|
||||
{
|
||||
@ -3769,6 +3775,8 @@ parse_auto_key_locate (char *options)
|
||||
akl->type = AKL_PKA;
|
||||
else if (ascii_strcasecmp (tok, "dane") == 0)
|
||||
akl->type = AKL_DANE;
|
||||
else if (ascii_strcasecmp (tok, "wkd") == 0)
|
||||
akl->type = AKL_WKD;
|
||||
else if ((akl->spec = parse_keyserver_uri (tok, 1)))
|
||||
akl->type = AKL_SPEC;
|
||||
else
|
||||
|
@ -185,6 +185,7 @@ enum cmd_and_opt_values
|
||||
oWithICAOSpelling,
|
||||
oWithKeygrip,
|
||||
oWithSecret,
|
||||
oWithWKDHash,
|
||||
oAnswerYes,
|
||||
oAnswerNo,
|
||||
oKeyring,
|
||||
@ -721,6 +722,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
|
||||
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
|
||||
ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
|
||||
ARGPARSE_s_n (oWithWKDHash, "with-wkd-hash", "@"),
|
||||
ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"),
|
||||
ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"),
|
||||
ARGPARSE_s_n (oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", "@"),
|
||||
@ -2575,6 +2577,10 @@ main (int argc, char **argv)
|
||||
opt.with_secret = 1;
|
||||
break;
|
||||
|
||||
case oWithWKDHash:
|
||||
opt.with_wkd_hash = 1;
|
||||
break;
|
||||
|
||||
case oSecretKeyring:
|
||||
/* Ignore this old option. */
|
||||
break;
|
||||
|
11
g10/gpgv.c
11
g10/gpgv.c
@ -374,6 +374,17 @@ keyserver_import_pka (const char *name,unsigned char *fpr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
keyserver_import_wkd (ctrl_t ctrl, const char *name,
|
||||
unsigned char **fpr, size_t *fpr_len)
|
||||
{
|
||||
(void)ctrl;
|
||||
(void)name;
|
||||
(void)fpr;
|
||||
(void)fpr_len;
|
||||
return GPG_ERR_BUG;
|
||||
}
|
||||
|
||||
int
|
||||
keyserver_import_name (const char *name,struct keyserver_spec *spec)
|
||||
{
|
||||
|
@ -1279,7 +1279,7 @@ import_one (ctrl_t ctrl,
|
||||
{
|
||||
xfree (*fpr);
|
||||
/* Note that we need to compare against 0 here because
|
||||
COUNT gets only incremented after returning form this
|
||||
COUNT gets only incremented after returning from this
|
||||
function. */
|
||||
if (!stats->count)
|
||||
*fpr = fingerprint_from_pk (pk, NULL, fpr_len);
|
||||
|
@ -1116,6 +1116,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
|
||||
if (node->pkt->pkttype == PKT_USER_ID)
|
||||
{
|
||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||
int indent;
|
||||
|
||||
if ((uid->is_expired || uid->is_revoked)
|
||||
&& !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
|
||||
@ -1133,25 +1134,46 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
|
||||
|| (opt.list_options & LIST_SHOW_UID_VALIDITY))
|
||||
{
|
||||
const char *validity;
|
||||
int indent;
|
||||
|
||||
validity = uid_trust_string_fixed (pk, uid);
|
||||
indent =
|
||||
(keystrlen () + (opt.legacy_list_mode? 9:11)) -
|
||||
atoi (uid_trust_string_fixed (NULL, NULL));
|
||||
|
||||
indent = ((keystrlen () + (opt.legacy_list_mode? 9:11))
|
||||
- atoi (uid_trust_string_fixed (NULL, NULL)));
|
||||
if (indent < 0 || indent > 40)
|
||||
indent = 0;
|
||||
|
||||
es_fprintf (es_stdout, "uid%*s%s ", indent, "", validity);
|
||||
}
|
||||
else
|
||||
es_fprintf (es_stdout, "uid%*s",
|
||||
(int) keystrlen () + (opt.legacy_list_mode? 10:12), "");
|
||||
{
|
||||
indent = keystrlen () + (opt.legacy_list_mode? 10:12);
|
||||
es_fprintf (es_stdout, "uid%*s", indent, "");
|
||||
}
|
||||
|
||||
print_utf8_buffer (es_stdout, uid->name, uid->len);
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (opt.with_wkd_hash)
|
||||
{
|
||||
char *mbox, *hash, *p;
|
||||
char hashbuf[32];
|
||||
|
||||
mbox = mailbox_from_userid (uid->name);
|
||||
if (mbox && (p = strchr (mbox, '@')))
|
||||
{
|
||||
*p++ = 0;
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf,
|
||||
mbox, strlen (mbox));
|
||||
hash = zb32_encode (hashbuf, 8*20);
|
||||
if (hash)
|
||||
{
|
||||
es_fprintf (es_stdout, " %*s%s@%s\n",
|
||||
indent, "", hash, p);
|
||||
xfree (hash);
|
||||
}
|
||||
}
|
||||
xfree (mbox);
|
||||
}
|
||||
|
||||
if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL)
|
||||
show_photos (uid->attribs, uid->numattribs, pk, uid);
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ int keyserver_import_cert (ctrl_t ctrl, const char *name, int dane_mode,
|
||||
unsigned char **fpr,size_t *fpr_len);
|
||||
gpg_error_t keyserver_import_pka (ctrl_t ctrl, const char *name,
|
||||
unsigned char **fpr,size_t *fpr_len);
|
||||
gpg_error_t keyserver_import_wkd (ctrl_t ctrl, const char *name,
|
||||
unsigned char **fpr, size_t *fpr_len);
|
||||
int keyserver_import_name (ctrl_t ctrl,
|
||||
const char *name,unsigned char **fpr,size_t *fpr_len,
|
||||
struct keyserver_spec *keyserver);
|
||||
|
@ -2004,6 +2004,39 @@ keyserver_import_pka (ctrl_t ctrl, const char *name,
|
||||
}
|
||||
|
||||
|
||||
/* Import a key using the Web Key Directory protocol. */
|
||||
gpg_error_t
|
||||
keyserver_import_wkd (ctrl_t ctrl, const char *name,
|
||||
unsigned char **fpr, size_t *fpr_len)
|
||||
{
|
||||
gpg_error_t err;
|
||||
estream_t key;
|
||||
|
||||
err = gpg_dirmngr_wkd_get (ctrl, name, &key);
|
||||
if (err)
|
||||
;
|
||||
else if (key)
|
||||
{
|
||||
int armor_status = opt.no_armor;
|
||||
|
||||
/* Keys returned via WKD are in binary format. */
|
||||
opt.no_armor = 1;
|
||||
|
||||
err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
|
||||
(opt.keyserver_options.import_options
|
||||
| IMPORT_NO_SECKEY),
|
||||
NULL, NULL);
|
||||
|
||||
opt.no_armor = armor_status;
|
||||
|
||||
es_fclose (key);
|
||||
key = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Import a key by name using LDAP */
|
||||
int
|
||||
keyserver_import_ldap (ctrl_t ctrl,
|
||||
|
@ -73,6 +73,7 @@ struct
|
||||
int with_fingerprint; /* Option --with-fingerprint active. */
|
||||
int with_keygrip; /* Option --with-keygrip active. */
|
||||
int with_secret; /* Option --with-secret active. */
|
||||
int with_wkd_hash; /* Option --with-wkd-hash. */
|
||||
int fingerprint; /* list fingerprints */
|
||||
int list_sigs; /* list signatures */
|
||||
int print_pka_records;
|
||||
@ -245,6 +246,7 @@ struct
|
||||
AKL_CERT,
|
||||
AKL_PKA,
|
||||
AKL_DANE,
|
||||
AKL_WKD,
|
||||
AKL_LDAP,
|
||||
AKL_KEYSERVER,
|
||||
AKL_SPEC
|
||||
|
@ -186,6 +186,17 @@ keyserver_import_pka (const char *name,unsigned char *fpr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
gpg_error_t
|
||||
keyserver_import_wkd (ctrl_t ctrl, const char *name,
|
||||
unsigned char **fpr, size_t *fpr_len)
|
||||
{
|
||||
(void)ctrl;
|
||||
(void)name;
|
||||
(void)fpr;
|
||||
(void)fpr_len;
|
||||
return GPG_ERR_BUG;
|
||||
}
|
||||
|
||||
int
|
||||
keyserver_import_name (const char *name,struct keyserver_spec *spec)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user