diff options
Diffstat (limited to 'g10/getkey.c')
-rw-r--r-- | g10/getkey.c | 155 |
1 files changed, 123 insertions, 32 deletions
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) |