diff options
Diffstat (limited to 'g10/getkey.c')
-rw-r--r-- | g10/getkey.c | 307 |
1 files changed, 239 insertions, 68 deletions
diff --git a/g10/getkey.c b/g10/getkey.c index e758b43..4642174 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -558,6 +558,42 @@ leave: } +/* Same as get_pubkey but if the key was not found the function tries + * to import it from LDAP. FIXME: We should not need this but swicth + * to a fingerprint lookup. */ +gpg_error_t +get_pubkey_with_ldap_fallback (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid) +{ + gpg_error_t err; + + err = get_pubkey (ctrl, pk, keyid); + if (!err) + return 0; + + if (gpg_err_code (err) != GPG_ERR_NO_PUBKEY) + return err; + + /* Note that this code does not handle the case for two readers + * having both openpgp encryption keys. Only one will be tried. */ + if (opt.debug) + log_debug ("using LDAP to find a public key\n"); + err = keyserver_import_keyid (ctrl, keyid, + opt.keyserver, KEYSERVER_IMPORT_FLAG_LDAP); + if (gpg_err_code (err) == GPG_ERR_NO_DATA + || gpg_err_code (err) == GPG_ERR_NO_KEYSERVER) + { + /* Dirmngr returns NO DATA is the selected keyserver + * does not have the requested key. It returns NO + * KEYSERVER if no LDAP keyservers are configured. */ + err = gpg_error (GPG_ERR_NO_PUBKEY); + } + if (err) + return err; + + return get_pubkey (ctrl, pk, keyid); +} + + /* Similar to get_pubkey, but it does not take PK->REQ_USAGE into * account nor does it merge in the self-signed data. This function * also only considers primary keys. It is intended to be used as a @@ -1020,10 +1056,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 +1083,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 +1184,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 +1210,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 +1232,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 +1326,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_mbox (ctrl, name, &fpr, &fpr_len, + opt.keyserver); + } glo_ctrl.in_auto_key_retrieve--; } else @@ -1236,8 +1361,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_mbox (ctrl, name, + &fpr, &fpr_len, keyserver); + } glo_ctrl.in_auto_key_retrieve--; } break; @@ -1250,21 +1388,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) @@ -3884,66 +4028,93 @@ lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret, } +/* If a default key has been specified, return that key. If a card + * based key is also available as indicated by FPR_CARD not being + * NULL, return that key if suitable. */ gpg_error_t get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, const byte *fpr_card, size_t fpr_len) { gpg_error_t err; strlist_t namelist = NULL; + const char *def_secret_key; - const char *def_secret_key = parse_def_secret_key (ctrl); + def_secret_key = parse_def_secret_key (ctrl); if (def_secret_key) add_to_strlist (&namelist, def_secret_key); else if (fpr_card) { - int rc = get_pubkey_byfprint (ctrl, pk, NULL, fpr_card, fpr_len); + err = get_pubkey_byfprint (ctrl, pk, NULL, fpr_card, fpr_len); + if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) + { + if (opt.debug) + log_debug ("using LDAP to find public key for current card\n"); + err = keyserver_import_fprint (ctrl, fpr_card, fpr_len, + opt.keyserver, + KEYSERVER_IMPORT_FLAG_LDAP); + if (!err) + err = get_pubkey_byfprint (ctrl, pk, NULL, fpr_card, fpr_len); + else if (gpg_err_code (err) == GPG_ERR_NO_DATA + || gpg_err_code (err) == GPG_ERR_NO_KEYSERVER) + { + /* Dirmngr returns NO DATA is the selected keyserver + * does not have the requested key. It returns NO + * KEYSERVER if no LDAP keyservers are configured. */ + err = gpg_error (GPG_ERR_NO_PUBKEY); + } + } /* The key on card can be not suitable for requested usage. */ - if (rc == GPG_ERR_UNUSABLE_PUBKEY) + if (gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY) fpr_card = NULL; /* Fallthrough as no card. */ else - return rc; + return err; /* Success or other error. */ } - if (!fpr_card - || (def_secret_key && def_secret_key[strlen (def_secret_key)-1] == '!')) - err = key_byname (ctrl, NULL, namelist, pk, 1, 0, NULL, NULL); + if (!fpr_card || (def_secret_key && *def_secret_key + && def_secret_key[strlen (def_secret_key)-1] == '!')) + { + err = key_byname (ctrl, NULL, namelist, pk, 1, 0, NULL, NULL); + } else { /* Default key is specified and card key is also available. */ kbnode_t k, keyblock = NULL; err = key_byname (ctrl, NULL, namelist, pk, 1, 0, &keyblock, NULL); - if (!err) - for (k = keyblock; k; k = k->next) - { - PKT_public_key *pk_candidate; - char fpr[MAX_FINGERPRINT_LEN]; - - if (k->pkt->pkttype != PKT_PUBLIC_KEY - &&k->pkt->pkttype != PKT_PUBLIC_SUBKEY) - continue; - - pk_candidate = k->pkt->pkt.public_key; - if (!pk_candidate->flags.valid) - continue; - if (!((pk_candidate->pubkey_usage & USAGE_MASK) & pk->req_usage)) - continue; - fingerprint_from_pk (pk_candidate, fpr, NULL); - if (!memcmp (fpr_card, fpr, fpr_len)) - { - release_public_key_parts (pk); - copy_public_key (pk, pk_candidate); - break; - } - } + if (err) + goto leave; + for (k = keyblock; k; k = k->next) + { + PKT_public_key *pk_candidate; + char fpr[MAX_FINGERPRINT_LEN]; + + if (k->pkt->pkttype != PKT_PUBLIC_KEY + &&k->pkt->pkttype != PKT_PUBLIC_SUBKEY) + continue; + + pk_candidate = k->pkt->pkt.public_key; + if (!pk_candidate->flags.valid) + continue; + if (!((pk_candidate->pubkey_usage & USAGE_MASK) & pk->req_usage)) + continue; + fingerprint_from_pk (pk_candidate, fpr, NULL); + if (!memcmp (fpr_card, fpr, fpr_len)) + { + release_public_key_parts (pk); + copy_public_key (pk, pk_candidate); + break; + } + } release_kbnode (keyblock); } + leave: free_strlist (namelist); - return err; } + + /********************************************* *********** User ID printing helpers ******* |