gpg: Allow fingerprint based lookup with --locate-external-key.

* g10/keyserver.c (keyserver_import_fprint_ntds): New.
* g10/getkey.c (get_pubkey_byname): Detect an attempt to search by
fingerprint in no_local mode.
--

See the man page.  For testing use

  gpg --auto-key-locate local,wkd,keyserver --locate-external-key  \
    FINGERPRINT

with at least one LDAP keyserver given in dirmngr.conf.  On Windows
"ntds" may be used instead or in addtion to "keyserver".

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2021-04-21 18:32:21 +02:00
parent f79e9540ca
commit ec36eca08c
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
7 changed files with 181 additions and 46 deletions

View File

@ -355,11 +355,17 @@ numbers 1-9 or "T" for 10 and above to indicate trust signature levels
Locate the keys given as arguments. This command basically uses the
same algorithm as used when locating keys for encryption and may thus
be used to see what keys @command{@gpgname} might use. In particular
external methods as defined by @option{--auto-key-locate} may be used
to locate a key. Only public keys are listed. The variant
@option{--locate-external-keys} does not consider a locally existing
key and can thus be used to force the refresh of a key via the defined
external methods.
external methods as defined by @option{--auto-key-locate} are used to
locate a key if the arguments comain valid mail addresses. Only
public keys are listed.
The variant @option{--locate-external-keys} does not consider a
locally existing key and can thus be used to force the refresh of a
key via the defined external methods. If a fingerprint is given and
and the methods defined by --auto-key-locate define LDAP servers, the
key is fetched from these resources; defined non-LDAP keyservers are
skipped.
@item --show-keys
@opindex show-keys
@ -1842,14 +1848,20 @@ list. The default is "local,wkd".
PGP Universal method of checking @samp{ldap://keys.(thedomain)}.
@item ntds
Locate the key using the Active Directory (Windows only).
Locate the key using the Active Directory (Windows only). This
method also allows to search by fingerprint using the command
@option{--locate-external-key}.
@item keyserver
Locate a key using a keyserver.
Locate a key using a keyserver. This method also allows to search
by fingerprint using the command @option{--locate-external-key} if
any of the configured keyservers is an LDAP server.
@item keyserver-URL
In addition, a keyserver URL as used in the @command{dirmngr}
configuration may be used here to query that particular keyserver.
This method also allows to search by fingerprint using the command
@option{--locate-external-key} if the URL specifies an LDAP server.
@item local
Locate the key using the local keyrings. This mechanism allows the user to

View File

@ -678,7 +678,7 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern,
/* If we have an override keyserver we first indicate that the next
user of the context needs to again setup the global keyservers and
them we send the override keyserver. */
then we send the override keyserver. */
if (override_keyserver)
{
clear_context_flags (ctrl, ctx);

View File

@ -925,11 +925,13 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
int rc;
strlist_t namelist = NULL;
struct akl *akl;
int is_mbox;
int is_mbox, is_fpr;
KEYDB_SEARCH_DESC fprbuf;
int nodefault = 0;
int anylocalfirst = 0;
int mechanism_type = AKL_NODEFAULT;
/* If RETCTX is not NULL, then RET_KDBHD must be NULL. */
log_assert (retctx == NULL || ret_kdbhd == NULL);
@ -950,6 +952,18 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
is_mbox = 1;
}
/* If we are called due to --locate-external-key Check whether NAME
* is a fingerprint and then try to lookup that key by configured
* method which support lookup by fingerprint. FPRBUF carries the
* parsed fingerpint iff IS_FPR is true. */
is_fpr = 0;
if (!is_mbox && mode == GET_PUBKEY_NO_LOCAL)
{
if (!classify_user_id (name, &fprbuf, 1)
&& fprbuf.mode == KEYDB_SEARCH_MODE_FPR)
is_fpr = 1;
}
/* The auto-key-locate feature works as follows: there are a number
* of methods to look up keys. By default, the local keyring is
* tried first. Then, each method listed in the --auto-key-locate is
@ -1027,7 +1041,7 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
retrieval has been enabled, we try to import the key. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& mode != GET_PUBKEY_NO_AKL
&& is_mbox)
&& (is_mbox || is_fpr))
{
/* NAME wasn't present in the local keyring (or we didn't try
* the local keyring). Since the auto key locate feature is
@ -1053,6 +1067,8 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
case AKL_LOCAL:
if (mode == GET_PUBKEY_NO_LOCAL)
{
/* Note that we get here in is_fpr more, so there is
* no extra check for it required. */
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
}
@ -1073,41 +1089,80 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
break;
case AKL_CERT:
mechanism_string = "DNS CERT";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
if (is_fpr)
{
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
}
else
{
mechanism_string = "DNS CERT";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
}
break;
case AKL_PKA:
/* This is now obsolete. */
break;
case AKL_DANE:
mechanism_string = "DANE";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
if (is_fpr)
{
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
break;
}
else
{
mechanism_string = "DANE";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
}
break;
case AKL_WKD:
mechanism_string = "WKD";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_wkd (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
if (is_fpr)
{
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
break;
}
else
{
mechanism_string = "WKD";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_wkd (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
}
break;
case AKL_LDAP:
mechanism_string = "LDAP";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
if (is_fpr)
{
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
break;
}
else
{
mechanism_string = "LDAP";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
}
break;
case AKL_NTDS:
mechanism_string = "NTDS";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ntds (ctrl, name, &fpr, &fpr_len);
if (is_fpr)
rc = keyserver_import_fprint_ntds (ctrl,
fprbuf.u.fpr, fprbuf.fprlen);
else
rc = keyserver_import_ntds (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
@ -1120,8 +1175,25 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
{
mechanism_string = "keyserver";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
opt.keyserver);
if (is_fpr)
{
rc = keyserver_import_fprint (ctrl,
fprbuf.u.fpr, fprbuf.fprlen,
opt.keyserver,
KEYSERVER_IMPORT_FLAG_LDAP);
/* Map error codes because Dirmngr returns NO
* DATA if the keyserver does not have the
* requested key. It returns NO KEYSERVER if no
* LDAP keyservers are configured. */
if (gpg_err_code (rc) == GPG_ERR_NO_DATA
|| gpg_err_code (rc) == GPG_ERR_NO_KEYSERVER)
rc = gpg_error (GPG_ERR_NO_PUBKEY);
}
else
{
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
opt.keyserver);
}
glo_ctrl.in_auto_key_retrieve--;
}
else
@ -1138,8 +1210,21 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
mechanism_string = akl->spec->uri;
keyserver = keyserver_match (akl->spec);
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl,
name, &fpr, &fpr_len, keyserver);
if (is_fpr)
{
rc = keyserver_import_fprint (ctrl,
fprbuf.u.fpr, fprbuf.fprlen,
opt.keyserver,
KEYSERVER_IMPORT_FLAG_LDAP);
if (gpg_err_code (rc) == GPG_ERR_NO_DATA
|| gpg_err_code (rc) == GPG_ERR_NO_KEYSERVER)
rc = gpg_error (GPG_ERR_NO_PUBKEY);
}
else
{
rc = keyserver_import_name (ctrl, name,
&fpr, &fpr_len, keyserver);
}
glo_ctrl.in_auto_key_retrieve--;
}
break;
@ -1152,21 +1237,27 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* requirement as the URL might point to a key put in by an
* attacker. By forcing the use of the fingerprint, we
* won't use the attacker's key here. */
if (!rc && fpr)
if (!rc && (fpr || is_fpr))
{
char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
free_strlist (namelist);
namelist = NULL;
bin2hex (fpr, fpr_len, fpr_string);
if (is_fpr)
{
log_assert (fprbuf.fprlen <= MAX_FINGERPRINT_LEN);
bin2hex (fprbuf.u.fpr, fprbuf.fprlen, fpr_string);
}
else
{
log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
bin2hex (fpr, fpr_len, fpr_string);
}
if (opt.verbose)
log_info ("auto-key-locate found fingerprint %s\n",
fpr_string);
free_strlist (namelist);
namelist = NULL;
add_to_strlist (&namelist, fpr_string);
}
else if (!rc && !fpr && !did_akl_local)

View File

@ -443,6 +443,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
return -1;
}
int
keyserver_import_fprint_ntds (ctrl_t ctrl,
const byte *fprint, size_t fprint_len)
{
(void)ctrl;
(void)fprint;
(void)fprint_len;
return -1;
}
int
keyserver_import_cert (const char *name)
{

View File

@ -41,6 +41,8 @@ int keyserver_import (ctrl_t ctrl, strlist_t users);
int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
struct keyserver_spec *keyserver,
unsigned int flags);
int keyserver_import_fprint_ntds (ctrl_t ctrl,
const byte *fprint, size_t fprint_len);
int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid,
struct keyserver_spec *keyserver,
unsigned int flags);

View File

@ -1155,27 +1155,37 @@ keyserver_import_ntds (ctrl_t ctrl, const char *mbox,
int
keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
keyserver_import_fprint (ctrl_t ctrl, const byte *fprint, size_t fprint_len,
struct keyserver_spec *keyserver,
unsigned int flags)
{
KEYDB_SEARCH_DESC desc;
memset(&desc,0,sizeof(desc));
memset (&desc, 0, sizeof(desc));
if (fprint_len == 16 || fprint_len == 20 || fprint_len == 32)
desc.mode = KEYDB_SEARCH_MODE_FPR;
else
return -1;
return gpg_error (GPG_ERR_INV_ARG);
memcpy(desc.u.fpr,fprint,fprint_len);
memcpy (desc.u.fpr, fprint, fprint_len);
desc.fprlen = fprint_len;
/* TODO: Warn here if the fingerprint we got doesn't match the one
we asked for? */
return keyserver_get (ctrl, &desc, 1, keyserver, flags, NULL, NULL);
}
int
keyserver_import_fprint_ntds (ctrl_t ctrl,
const byte *fprint, size_t fprint_len)
{
struct keyserver_spec keyserver = { NULL, "ldap:///" };
return keyserver_import_fprint (ctrl, fprint, fprint_len,
&keyserver, KEYSERVER_IMPORT_FLAG_LDAP);
}
int
keyserver_import_keyid (ctrl_t ctrl,
u32 *keyid,struct keyserver_spec *keyserver,

View File

@ -201,6 +201,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
return -1;
}
int
keyserver_import_fprint_ntds (ctrl_t ctrl,
const byte *fprint, size_t fprint_len)
{
(void)ctrl;
(void)fprint;
(void)fprint_len;
return -1;
}
int
keyserver_import_cert (const char *name)
{