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>
(cherry picked from commit ec36eca08c)
This commit is contained in:
Werner Koch 2021-04-21 18:32:21 +02:00
parent b59af0e2a0
commit 2af217ecd7
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
7 changed files with 204 additions and 53 deletions

View File

@ -353,13 +353,18 @@ numbers 1-9 or "T" for 10 and above to indicate trust signature levels
@opindex locate-keys @opindex locate-keys
@opindex locate-external-keys @opindex locate-external-keys
Locate the keys given as arguments. This command basically uses the Locate the keys given as arguments. This command basically uses the
same algorithm as used when locating keys for encryption or signing same algorithm as used when locating keys for encryption and may thus
and may thus be used to see what keys @command{@gpgname} might use. be used to see what keys @command{@gpgname} might use. In particular
In particular external methods as defined by external methods as defined by @option{--auto-key-locate} are used to
@option{--auto-key-locate} may be used to locate a key. Only public locate a key if the arguments comain valid mail addresses. Only
keys are listed. The variant @option{--locate-external-keys} does not public keys are listed.
consider a locally existing key and can thus be used to force the
refresh of a key via the defined external methods. 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 @item --show-keys
@opindex show-keys @opindex show-keys
@ -1811,14 +1816,20 @@ list. The default is "local,wkd".
PGP Universal method of checking @samp{ldap://keys.(thedomain)}. PGP Universal method of checking @samp{ldap://keys.(thedomain)}.
@item ntds @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 @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 @item keyserver-URL
In addition, a keyserver URL as used in the @command{dirmngr} In addition, a keyserver URL as used in the @command{dirmngr}
configuration may be used here to query that particular keyserver. 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 @item local
Locate the key using the local keyrings. This mechanism allows the user to Locate the key using the local keyrings. This mechanism allows the user to

View File

@ -710,7 +710,7 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern,
/* If we have an override keyserver we first indicate that the next /* If we have an override keyserver we first indicate that the next
user of the context needs to again setup the global keyservers and 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) if (override_keyserver)
{ {
clear_context_flags (ctrl, ctx); clear_context_flags (ctrl, ctx);

View File

@ -1020,10 +1020,12 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
int rc; int rc;
strlist_t namelist = NULL; strlist_t namelist = NULL;
struct akl *akl; struct akl *akl;
int is_mbox; int is_mbox, is_fpr;
KEYDB_SEARCH_DESC fprbuf;
int nodefault = 0; int nodefault = 0;
int anylocalfirst = 0; int anylocalfirst = 0;
int mechanism_type = AKL_NODEFAULT; int mechanism_type = AKL_NODEFAULT;
size_t fprbuf_fprlen = 0;
/* If RETCTX is not NULL, then RET_KDBHD must be NULL. */ /* If RETCTX is not NULL, then RET_KDBHD must be NULL. */
log_assert (retctx == NULL || ret_kdbhd == NULL); log_assert (retctx == NULL || ret_kdbhd == NULL);
@ -1045,6 +1047,30 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
is_mbox = 1; 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_FPR16
|| fprbuf.mode == KEYDB_SEARCH_MODE_FPR20
|| fprbuf.mode == KEYDB_SEARCH_MODE_FPR))
{
/* Note: We should get rid of the FPR16 because we don't
* support v3 keys anymore. However, in 2.3 the fingerprint
* code has already been reworked and thus it is
* questionable whether we should really tackle this here. */
if (fprbuf.mode == KEYDB_SEARCH_MODE_FPR16)
fprbuf_fprlen = 16;
else
fprbuf_fprlen = 20;
is_fpr = 1;
}
}
/* The auto-key-locate feature works as follows: there are a number /* The auto-key-locate feature works as follows: there are a number
* of methods to look up keys. By default, the local keyring is * of methods to look up keys. By default, the local keyring is
* tried first. Then, each method listed in the --auto-key-locate is * tried first. Then, each method listed in the --auto-key-locate is
@ -1122,7 +1148,7 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
retrieval has been enabled, we try to import the key. */ retrieval has been enabled, we try to import the key. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& mode != GET_PUBKEY_NO_AKL && mode != GET_PUBKEY_NO_AKL
&& is_mbox) && (is_mbox || is_fpr))
{ {
/* NAME wasn't present in the local keyring (or we didn't try /* NAME wasn't present in the local keyring (or we didn't try
* the local keyring). Since the auto key locate feature is * the local keyring). Since the auto key locate feature is
@ -1148,6 +1174,8 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
case AKL_LOCAL: case AKL_LOCAL:
if (mode == GET_PUBKEY_NO_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 = ""; mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY; rc = GPG_ERR_NO_PUBKEY;
} }
@ -1168,44 +1196,88 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
break; break;
case AKL_CERT: case AKL_CERT:
mechanism_string = "DNS CERT"; if (is_fpr)
glo_ctrl.in_auto_key_retrieve++; {
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len); mechanism_string = "";
glo_ctrl.in_auto_key_retrieve--; rc = GPG_ERR_NO_PUBKEY;
break; }
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: case AKL_PKA:
mechanism_string = "PKA"; if (is_fpr)
glo_ctrl.in_auto_key_retrieve++; {
rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len); mechanism_string = "";
glo_ctrl.in_auto_key_retrieve--; rc = GPG_ERR_NO_PUBKEY;
break; }
else
{
mechanism_string = "PKA";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
}
break;
case AKL_DANE: case AKL_DANE:
mechanism_string = "DANE"; if (is_fpr)
glo_ctrl.in_auto_key_retrieve++; {
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len); mechanism_string = "";
glo_ctrl.in_auto_key_retrieve--; rc = GPG_ERR_NO_PUBKEY;
}
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; break;
case AKL_WKD: case AKL_WKD:
mechanism_string = "WKD"; if (is_fpr)
glo_ctrl.in_auto_key_retrieve++; {
rc = keyserver_import_wkd (ctrl, name, 0, &fpr, &fpr_len); mechanism_string = "";
glo_ctrl.in_auto_key_retrieve--; rc = GPG_ERR_NO_PUBKEY;
}
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; break;
case AKL_LDAP: case AKL_LDAP:
mechanism_string = "LDAP"; if (is_fpr)
glo_ctrl.in_auto_key_retrieve++; {
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len); mechanism_string = "";
glo_ctrl.in_auto_key_retrieve--; 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: case AKL_NTDS:
mechanism_string = "NTDS"; mechanism_string = "NTDS";
glo_ctrl.in_auto_key_retrieve++; 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--; glo_ctrl.in_auto_key_retrieve--;
break; break;
@ -1218,8 +1290,25 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
{ {
mechanism_string = "keyserver"; mechanism_string = "keyserver";
glo_ctrl.in_auto_key_retrieve++; glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len, if (is_fpr)
opt.keyserver); {
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--; glo_ctrl.in_auto_key_retrieve--;
} }
else else
@ -1236,8 +1325,21 @@ get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
mechanism_string = akl->spec->uri; mechanism_string = akl->spec->uri;
keyserver = keyserver_match (akl->spec); keyserver = keyserver_match (akl->spec);
glo_ctrl.in_auto_key_retrieve++; glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, if (is_fpr)
name, &fpr, &fpr_len, keyserver); {
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--; glo_ctrl.in_auto_key_retrieve--;
} }
break; break;
@ -1250,21 +1352,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 * requirement as the URL might point to a key put in by an
* attacker. By forcing the use of the fingerprint, we * attacker. By forcing the use of the fingerprint, we
* won't use the attacker's key here. */ * won't use the attacker's key here. */
if (!rc && fpr) if (!rc && (fpr || is_fpr))
{ {
char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1]; char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
log_assert (fpr_len <= MAX_FINGERPRINT_LEN); if (is_fpr)
{
free_strlist (namelist); log_assert (fprbuf_fprlen <= MAX_FINGERPRINT_LEN);
namelist = NULL; bin2hex (fprbuf.u.fpr, fprbuf_fprlen, fpr_string);
}
bin2hex (fpr, fpr_len, fpr_string); else
{
log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
bin2hex (fpr, fpr_len, fpr_string);
}
if (opt.verbose) if (opt.verbose)
log_info ("auto-key-locate found fingerprint %s\n", log_info ("auto-key-locate found fingerprint %s\n",
fpr_string); fpr_string);
free_strlist (namelist);
namelist = NULL;
add_to_strlist (&namelist, fpr_string); add_to_strlist (&namelist, fpr_string);
} }
else if (!rc && !fpr && !did_akl_local) else if (!rc && !fpr && !did_akl_local)

View File

@ -440,6 +440,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
return -1; 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 int
keyserver_import_cert (const char *name) 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, int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
struct keyserver_spec *keyserver, struct keyserver_spec *keyserver,
unsigned int flags); 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, int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid,
struct keyserver_spec *keyserver, struct keyserver_spec *keyserver,
unsigned int flags); unsigned int flags);

View File

@ -1175,28 +1175,38 @@ keyserver_import_ntds (ctrl_t ctrl, const char *mbox,
int 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, struct keyserver_spec *keyserver,
unsigned int flags) unsigned int flags)
{ {
KEYDB_SEARCH_DESC desc; KEYDB_SEARCH_DESC desc;
memset(&desc,0,sizeof(desc)); memset (&desc, 0, sizeof(desc));
if(fprint_len==16) if(fprint_len==16)
desc.mode=KEYDB_SEARCH_MODE_FPR16; desc.mode=KEYDB_SEARCH_MODE_FPR16;
else if(fprint_len==20) else if(fprint_len==20)
desc.mode=KEYDB_SEARCH_MODE_FPR20; desc.mode=KEYDB_SEARCH_MODE_FPR20;
else else
return -1; return gpg_error (GPG_ERR_INV_ARG);
memcpy(desc.u.fpr,fprint,fprint_len); memcpy (desc.u.fpr, fprint, 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); 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 int
keyserver_import_keyid (ctrl_t ctrl, keyserver_import_keyid (ctrl_t ctrl,
u32 *keyid,struct keyserver_spec *keyserver, u32 *keyid,struct keyserver_spec *keyserver,

View File

@ -198,6 +198,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
return -1; 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 int
keyserver_import_cert (const char *name) keyserver_import_cert (const char *name)
{ {