diff --git a/doc/gpg.texi b/doc/gpg.texi index 16a4b5851..b4997731f 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -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 diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 434b46795..484395afb 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -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); diff --git a/g10/getkey.c b/g10/getkey.c index 6b8d44332..2d89fc4e5 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -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) diff --git a/g10/gpgv.c b/g10/gpgv.c index 09c694c6a..4c5cccb4e 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -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) { diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index ebbd6e914..4b507b227 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 a0620565c..492ce0ce5 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -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, diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 174af82f7..3d3c73716 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -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) {