summaryrefslogtreecommitdiff
path: root/g10/getkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/getkey.c')
-rw-r--r--g10/getkey.c307
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 *******