aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2021-04-21 16:32:21 +0000
committerWerner Koch <[email protected]>2021-05-03 18:53:15 +0000
commit2af217ecd7e4242be2b35bc0085eccaf13cc2027 (patch)
tree653e14d2f99499ec5ec519085aa82acbf0462a8e
parentgpg: Lookup a missing public key of the current card via LDAP. (diff)
downloadgnupg-2af217ecd7e4242be2b35bc0085eccaf13cc2027.tar.gz
gnupg-2af217ecd7e4242be2b35bc0085eccaf13cc2027.zip
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 <[email protected]> (cherry picked from commit ec36eca08cdbf6653e7362e8e0e6c5f2c75b4a60)
-rw-r--r--doc/gpg.texi29
-rw-r--r--g10/call-dirmngr.c2
-rw-r--r--g10/getkey.c182
-rw-r--r--g10/gpgv.c10
-rw-r--r--g10/keyserver-internal.h2
-rw-r--r--g10/keyserver.c22
-rw-r--r--g10/test-stubs.c10
7 files changed, 204 insertions, 53 deletions
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 9b6303540..0c53bc1d4 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -353,13 +353,18 @@ numbers 1-9 or "T" for 10 and above to indicate trust signature levels
@opindex locate-keys
@opindex locate-external-keys
Locate the keys given as arguments. This command basically uses the
-same algorithm as used when locating keys for encryption or signing
-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.
+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} 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
@@ -1811,14 +1816,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
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
index 72afad8bc..f5fc8fcde 100644
--- a/g10/call-dirmngr.c
+++ b/g10/call-dirmngr.c
@@ -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
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);
diff --git a/g10/getkey.c b/g10/getkey.c
index 27ad007c9..8dd585ea9 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1020,10 +1020,12 @@ 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;
+ size_t fprbuf_fprlen = 0;
/* If RETCTX is not NULL, then RET_KDBHD must be 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;
}
+ /* 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
* of methods to look up keys. By default, the local keyring 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. */
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
@@ -1148,6 +1174,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;
}
@@ -1168,44 +1196,88 @@ 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:
- 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;
+ if (is_fpr)
+ {
+ mechanism_string = "";
+ rc = GPG_ERR_NO_PUBKEY;
+ }
+ 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:
- 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
@@ -1218,8 +1290,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
@@ -1236,8 +1325,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;
@@ -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
* 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)
diff --git a/g10/gpgv.c b/g10/gpgv.c
index a788c67c4..3131ba904 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -441,6 +441,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
}
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)
{
(void)name;
diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h
index 4439468c0..d1fb682a2 100644
--- a/g10/keyserver-internal.h
+++ b/g10/keyserver-internal.h
@@ -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);
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 7bbfe97ec..c5e70601d 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -1175,28 +1175,38 @@ 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)
desc.mode=KEYDB_SEARCH_MODE_FPR16;
else if(fprint_len==20)
desc.mode=KEYDB_SEARCH_MODE_FPR20;
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);
}
+
+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,
diff --git a/g10/test-stubs.c b/g10/test-stubs.c
index 9125d6a64..c6fa9c024 100644
--- a/g10/test-stubs.c
+++ b/g10/test-stubs.c
@@ -199,6 +199,16 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
}
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)
{
(void)name;