mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
sm: Lookup missing issuers first using authorityInfoAccess.
* sm/call-dirmngr.c (gpgsm_dirmngr_lookup): Add optional arg URL and adjust all callers. * sm/certchain.c (oidstr_caIssuers): New. (struct find_up_store_certs_s): Add additional fields. (find_up_store_certs_cb): Store the fingerprint. (find_up_via_auth_info_access): New. (find_up): Try the AIA URI first. -- Note that --auto-issuer-key-retrieve is required to use that. GnuPG-bug-id: 4898 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
7f1be1ea52
commit
f5efbd5a11
@ -757,20 +757,24 @@ lookup_status_cb (void *opaque, const char *line)
|
||||
|
||||
|
||||
/* Run the Directory Manager's lookup command using the pattern
|
||||
compiled from the strings given in NAMES. The caller must provide
|
||||
the callback CB which will be passed cert by cert. Note that CTRL
|
||||
is optional. With CACHE_ONLY the dirmngr will search only its own
|
||||
key cache. */
|
||||
compiled from the strings given in NAMES or from URI. The caller
|
||||
must provide the callback CB which will be passed cert by cert.
|
||||
Note that CTRL is optional. With CACHE_ONLY the dirmngr will
|
||||
search only its own key cache. */
|
||||
int
|
||||
gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
|
||||
gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri,
|
||||
int cache_only,
|
||||
void (*cb)(void*, ksba_cert_t), void *cb_value)
|
||||
{
|
||||
int rc;
|
||||
char *pattern;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct lookup_parm_s parm;
|
||||
size_t len;
|
||||
assuan_context_t ctx;
|
||||
const char *s;
|
||||
|
||||
if ((names && uri) || (!names && !uri))
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
/* The lookup function can be invoked from the callback of a lookup
|
||||
function, for example to walk the chain. */
|
||||
@ -793,19 +797,35 @@ gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
|
||||
log_fatal ("both dirmngr contexts are in use\n");
|
||||
}
|
||||
|
||||
pattern = pattern_from_strlist (names);
|
||||
if (!pattern)
|
||||
if (names)
|
||||
{
|
||||
if (ctx == dirmngr_ctx)
|
||||
release_dirmngr (ctrl);
|
||||
else
|
||||
release_dirmngr2 (ctrl);
|
||||
char *pattern = pattern_from_strlist (names);
|
||||
if (!pattern)
|
||||
{
|
||||
if (ctx == dirmngr_ctx)
|
||||
release_dirmngr (ctrl);
|
||||
else
|
||||
release_dirmngr2 (ctrl);
|
||||
|
||||
return out_of_core ();
|
||||
return out_of_core ();
|
||||
}
|
||||
snprintf (line, DIM(line), "LOOKUP%s %s",
|
||||
cache_only? " --cache-only":"", pattern);
|
||||
xfree (pattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (s=uri; *s; s++)
|
||||
if (*s <= ' ')
|
||||
{
|
||||
if (ctx == dirmngr_ctx)
|
||||
release_dirmngr (ctrl);
|
||||
else
|
||||
release_dirmngr2 (ctrl);
|
||||
return gpg_error (GPG_ERR_INV_URI);
|
||||
}
|
||||
snprintf (line, DIM(line), "LOOKUP --url %s", uri);
|
||||
}
|
||||
snprintf (line, DIM(line), "LOOKUP%s %s",
|
||||
cache_only? " --cache-only":"", pattern);
|
||||
xfree (pattern);
|
||||
|
||||
parm.ctrl = ctrl;
|
||||
parm.ctx = ctx;
|
||||
|
149
sm/certchain.c
149
sm/certchain.c
@ -38,6 +38,10 @@
|
||||
#include "../common/tlv.h"
|
||||
|
||||
|
||||
/* The OID for the authorityInfoAccess's caIssuers. */
|
||||
static const char oidstr_caIssuers[] = "1.3.6.1.5.5.7.48.2";
|
||||
|
||||
|
||||
/* Object to keep track of certain root certificates. */
|
||||
struct marktrusted_info_s
|
||||
{
|
||||
@ -574,6 +578,9 @@ struct find_up_store_certs_s
|
||||
{
|
||||
ctrl_t ctrl;
|
||||
int count;
|
||||
unsigned int want_fpr:1;
|
||||
unsigned int got_fpr:1;
|
||||
unsigned char fpr[20];
|
||||
};
|
||||
|
||||
static void
|
||||
@ -583,6 +590,13 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
|
||||
|
||||
if (keydb_store_cert (parm->ctrl, cert, 1, NULL))
|
||||
log_error ("error storing issuer certificate as ephemeral\n");
|
||||
else if (parm->want_fpr && !parm->got_fpr)
|
||||
{
|
||||
if (!gpgsm_get_fingerprint (cert, 0, parm->fpr, NULL))
|
||||
log_error (_("failed to get the fingerprint\n"));
|
||||
else
|
||||
parm->got_fpr = 1;
|
||||
}
|
||||
parm->count++;
|
||||
}
|
||||
|
||||
@ -603,6 +617,8 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
const char *s;
|
||||
|
||||
find_up_store_certs_parm.ctrl = ctrl;
|
||||
find_up_store_certs_parm.want_fpr = 0;
|
||||
find_up_store_certs_parm.got_fpr = 0;
|
||||
find_up_store_certs_parm.count = 0;
|
||||
|
||||
if (opt.verbose)
|
||||
@ -621,7 +637,7 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
add_to_strlist (&names, pattern);
|
||||
xfree (pattern);
|
||||
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, 0, find_up_store_certs_cb,
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, find_up_store_certs_cb,
|
||||
&find_up_store_certs_parm);
|
||||
free_strlist (names);
|
||||
|
||||
@ -654,6 +670,105 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
}
|
||||
|
||||
|
||||
/* Helper for find_up(). Locate the certificate for CERT using the
|
||||
* caIssuer from the authorityInfoAccess. KH is the keydb context we
|
||||
* are currently using. On success 0 is returned and the certificate
|
||||
* may be retrieved from the keydb using keydb_get_cert(). If no
|
||||
* suitable authorityInfoAccess is encoded in the certificate
|
||||
* GPG_ERR_NOT_FOUND is returned. */
|
||||
static gpg_error_t
|
||||
find_up_via_auth_info_access (ctrl_t ctrl, KEYDB_HANDLE kh, ksba_cert_t cert)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct find_up_store_certs_s find_up_store_certs_parm;
|
||||
char *url, *ldapurl;
|
||||
int idx, i;
|
||||
char *oid;
|
||||
ksba_name_t name;
|
||||
|
||||
find_up_store_certs_parm.ctrl = ctrl;
|
||||
find_up_store_certs_parm.want_fpr = 1;
|
||||
find_up_store_certs_parm.got_fpr = 0;
|
||||
find_up_store_certs_parm.count = 0;
|
||||
|
||||
/* Find suitable URLs; if there is a http scheme we prefer that. */
|
||||
url = ldapurl = NULL;
|
||||
for (idx=0;
|
||||
!url && !(err = ksba_cert_get_authority_info_access (cert, idx,
|
||||
&oid, &name));
|
||||
idx++)
|
||||
{
|
||||
if (!strcmp (oid, oidstr_caIssuers))
|
||||
{
|
||||
for (i=0; !url && ksba_name_enum (name, i); i++)
|
||||
{
|
||||
char *p = ksba_name_get_uri (name, i);
|
||||
if (p)
|
||||
{
|
||||
if (!strncmp (p, "http:", 5) || !strncmp (p, "https:", 6))
|
||||
url = p;
|
||||
else if (ldapurl)
|
||||
xfree (p); /* We already got one. */
|
||||
else if (!strncmp (p, "ldap:",5) || !strncmp (p, "ldaps:",6))
|
||||
ldapurl = p;
|
||||
}
|
||||
else
|
||||
xfree (p);
|
||||
}
|
||||
}
|
||||
ksba_name_release (name);
|
||||
ksba_free (oid);
|
||||
}
|
||||
if (err && gpg_err_code (err) != GPG_ERR_EOF)
|
||||
{
|
||||
log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
if (!url && ldapurl)
|
||||
{
|
||||
/* No HTTP scheme; fallback to LDAP if available. */
|
||||
url = ldapurl;
|
||||
ldapurl = NULL;
|
||||
}
|
||||
xfree (ldapurl);
|
||||
if (!url)
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("looking up issuer via authorityInfoAccess.caIssuers\n");
|
||||
|
||||
err = gpgsm_dirmngr_lookup (ctrl, NULL, url, 0, find_up_store_certs_cb,
|
||||
&find_up_store_certs_parm);
|
||||
|
||||
/* Although we might receive several certificates we use only the
|
||||
* first one. Or more exacty the first one for which we retrieved
|
||||
* the fingerprint. */
|
||||
if (opt.verbose)
|
||||
log_info ("number of caIssuers found: %d\n",
|
||||
find_up_store_certs_parm.count);
|
||||
if (err)
|
||||
{
|
||||
log_error ("external URL lookup failed: %s\n", gpg_strerror (err));
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
}
|
||||
else if (!find_up_store_certs_parm.got_fpr)
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
else
|
||||
{
|
||||
int old;
|
||||
/* The retrieved certificates are currently stored in the
|
||||
* ephemeral key DB, so we temporary switch to ephemeral
|
||||
* mode. */
|
||||
old = keydb_set_ephemeral (kh, 1);
|
||||
keydb_search_reset (kh);
|
||||
err = keydb_search_fpr (ctrl, kh, find_up_store_certs_parm.fpr);
|
||||
keydb_set_ephemeral (kh, old);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for find_up(). Ask the dirmngr for the certificate for
|
||||
ISSUER with optional SERIALNO. KH is the keydb context we are
|
||||
currently using. With SUBJECT_MODE set, ISSUER is searched as the
|
||||
@ -694,7 +809,7 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
add_to_strlist (&names, pattern);
|
||||
xfree (pattern);
|
||||
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, 1, find_up_store_certs_cb,
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 1, find_up_store_certs_cb,
|
||||
&find_up_store_certs_parm);
|
||||
free_strlist (names);
|
||||
|
||||
@ -816,9 +931,18 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
/* If we still didn't found it, try an external lookup. */
|
||||
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
|
||||
{
|
||||
rc = find_up_external (ctrl, kh, issuer, keyid);
|
||||
if (!rc && DBG_X509)
|
||||
log_debug (" found via authid and external lookup\n");
|
||||
if (!find_up_via_auth_info_access (ctrl, kh, cert))
|
||||
{
|
||||
if (DBG_X509)
|
||||
log_debug (" found via authorityInfoAccess.caIssuers\n");
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = find_up_external (ctrl, kh, issuer, keyid);
|
||||
if (!rc && DBG_X509)
|
||||
log_debug (" found via authid and external lookup\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -879,9 +1003,18 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
|
||||
/* Still not found. If enabled, try an external lookup. */
|
||||
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
|
||||
{
|
||||
rc = find_up_external (ctrl, kh, issuer, NULL);
|
||||
if (!rc && DBG_X509)
|
||||
log_debug (" found via issuer and external lookup\n");
|
||||
if (!find_up_via_auth_info_access (ctrl, kh, cert))
|
||||
{
|
||||
if (DBG_X509)
|
||||
log_debug (" found via authorityInfoAccess.caIssuers\n");
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = find_up_external (ctrl, kh, issuer, NULL);
|
||||
if (!rc && DBG_X509)
|
||||
log_debug (" found via issuer and external lookup\n");
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -447,7 +447,8 @@ gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip,
|
||||
int gpgsm_dirmngr_isvalid (ctrl_t ctrl,
|
||||
ksba_cert_t cert, ksba_cert_t issuer_cert,
|
||||
int use_ocsp);
|
||||
int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
|
||||
int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri,
|
||||
int cache_only,
|
||||
void (*cb)(void*, ksba_cert_t), void *cb_value);
|
||||
int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
|
||||
int argc, char **argv);
|
||||
|
@ -1648,7 +1648,7 @@ list_external_keys (ctrl_t ctrl, strlist_t names, estream_t fp, int raw_mode)
|
||||
parm.with_chain = ctrl->with_chain;
|
||||
parm.raw_mode = raw_mode;
|
||||
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, 0, list_external_cb, &parm);
|
||||
rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, list_external_cb, &parm);
|
||||
if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1
|
||||
|| gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
|
||||
rc = 0; /* "Not found" is not an error here. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user