aboutsummaryrefslogtreecommitdiffstats
path: root/sm/certchain.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/certchain.c')
-rw-r--r--sm/certchain.c132
1 files changed, 108 insertions, 24 deletions
diff --git a/sm/certchain.c b/sm/certchain.c
index a21a38a07..04b7e05ff 100644
--- a/sm/certchain.c
+++ b/sm/certchain.c
@@ -60,7 +60,7 @@ struct chain_item_s
typedef struct chain_item_s *chain_item_t;
-static int get_regtp_ca_info (ksba_cert_t cert, int *chainlen);
+static int get_regtp_ca_info (ctrl_t ctrl, ksba_cert_t cert, int *chainlen);
/* This function returns true if we already asked during this session
@@ -259,7 +259,8 @@ unknown_criticals (ksba_cert_t cert, int listmode, estream_t fp)
BasicConstraints extension. The function returns 0 on success and
the awlloed length of the chain at CHAINLEN. */
static int
-allowed_ca (ksba_cert_t cert, int *chainlen, int listmode, estream_t fp)
+allowed_ca (ctrl_t ctrl,
+ ksba_cert_t cert, int *chainlen, int listmode, estream_t fp)
{
gpg_error_t err;
int flag;
@@ -269,7 +270,7 @@ allowed_ca (ksba_cert_t cert, int *chainlen, int listmode, estream_t fp)
return err;
if (!flag)
{
- if (get_regtp_ca_info (cert, chainlen))
+ if (get_regtp_ca_info (ctrl, cert, chainlen))
{
/* Note that dirmngr takes a different way to cope with such
certs. */
@@ -417,7 +418,7 @@ check_cert_policy (ksba_cert_t cert, int listmode, estream_t fplist)
/* Helper function for find_up. This resets the key handle and search
for an issuer ISSUER with a subjectKeyIdentifier of KEYID. Returns
- 0 obn success or -1 when not found. */
+ 0 on success or -1 when not found. */
static int
find_up_search_by_keyid (KEYDB_HANDLE kh,
const char *issuer, ksba_sexp_t keyid)
@@ -464,9 +465,10 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
external lookup. 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(). KEYID is the keyIdentifier from
- the AKI or NULL. */
+ the AKI or NULL. */
static int
-find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
+find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh,
+ const char *issuer, ksba_sexp_t keyid)
{
int rc;
strlist_t names = NULL;
@@ -476,14 +478,13 @@ find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
if (opt.verbose)
log_info (_("looking up issuer at external location\n"));
- /* The DIRMNGR process is confused about unknown attributes. As a
+ /* The Dirmngr process is confused about unknown attributes. As a
quick and ugly hack we locate the CN and use the issuer string
starting at this attribite. Fixme: we should have far better
- parsing in the dirmngr. */
+ parsing for external lookups in the Dirmngr. */
s = strstr (issuer, "CN=");
if (!s || s == issuer || s[-1] != ',')
s = issuer;
-
pattern = xtrymalloc (strlen (s)+2);
if (!pattern)
return gpg_error_from_syserror ();
@@ -491,7 +492,7 @@ find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
add_to_strlist (&names, pattern);
xfree (pattern);
- rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count);
+ rc = gpgsm_dirmngr_lookup (ctrl, names, 0, find_up_store_certs_cb, &count);
free_strlist (names);
if (opt.verbose)
@@ -522,6 +523,54 @@ find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
}
+/* 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
+ subject. On success 0 is returned and the certificate is available
+ in the ephemeral DB. */
+static int
+find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh,
+ ksba_sexp_t serialno, const char *issuer, int subject_mode)
+{
+ int rc;
+ strlist_t names = NULL;
+ int count = 0;
+ char *pattern;
+
+ if (opt.verbose)
+ log_info (_("looking up issuer from the Dirmngr cache\n"));
+ if (subject_mode)
+ {
+ pattern = xtrymalloc (strlen (issuer)+2);
+ if (pattern)
+ strcpy (stpcpy (pattern, "/"), issuer);
+ }
+ else if (serialno)
+ pattern = gpgsm_format_sn_issuer (serialno, issuer);
+ else
+ {
+ pattern = xtrymalloc (strlen (issuer)+3);
+ if (pattern)
+ strcpy (stpcpy (pattern, "#/"), issuer);
+ }
+ if (!pattern)
+ return gpg_error_from_syserror ();
+ add_to_strlist (&names, pattern);
+ xfree (pattern);
+
+ rc = gpgsm_dirmngr_lookup (ctrl, names, 1, find_up_store_certs_cb, &count);
+ free_strlist (names);
+
+ if (opt.verbose)
+ log_info (_("number of matching certificates: %d\n"), count);
+ if (rc)
+ log_info (_("dirmngr cache-only key lookup failed: %s\n"),
+ gpg_strerror (rc));
+ return (!rc && count)? 0 : -1;
+}
+
+
+
/* Locate issuing certificate for CERT. ISSUER is the name of the
issuer used as a fallback if the other methods don't work. If
FIND_NEXT is true, the function shall return the next possible
@@ -529,7 +578,8 @@ find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
keydb_get_cert on the keyDb context KH will return it. Returns 0
on success, -1 if not found or an error code. */
static int
-find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
+find_up (ctrl_t ctrl, KEYDB_HANDLE kh,
+ ksba_cert_t cert, const char *issuer, int find_next)
{
ksba_name_t authid;
ksba_sexp_t authidno;
@@ -545,6 +595,14 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
if (rc)
keydb_search_reset (kh);
+ /* In case of an error, try to get the certifcate from the
+ dirmngr. That is done by trying to put that certifcate
+ into the ephemeral DB and let the code below do the
+ actual retrieve. Thus there is no error checking.
+ Skipped in find_next mode as usual. */
+ if (rc == -1 && !find_next)
+ find_up_dirmngr (ctrl, kh, authidno, s, 0);
+
/* In case of an error try the ephemeral DB. We can't do
that in find_next mode because we can't keep the search
state then. */
@@ -559,7 +617,8 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
}
keydb_set_ephemeral (kh, old);
}
-
+ if (rc)
+ rc = -1; /* Need to make sure to have this error code. */
}
if (rc == -1 && keyid && !find_next)
@@ -568,6 +627,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
instead. Loop over all certificates with that issuer as
subject and stop for the one with a matching
subjectKeyIdentifier. */
+ /* Fixme: Should we also search in the dirmngr? */
rc = find_up_search_by_keyid (kh, issuer, keyid);
if (rc)
{
@@ -580,9 +640,29 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
rc = -1; /* Need to make sure to have this error code. */
}
+ /* If we still didn't found it, try to find it via the subject
+ from the dirmngr-cache. */
+ if (rc == -1 && !find_next)
+ {
+ if (!find_up_dirmngr (ctrl, kh, NULL, issuer, 1))
+ {
+ int old = keydb_set_ephemeral (kh, 1);
+ if (keyid)
+ rc = find_up_search_by_keyid (kh, issuer, keyid);
+ else
+ {
+ keydb_search_reset (kh);
+ rc = keydb_search_subject (kh, issuer);
+ }
+ keydb_set_ephemeral (kh, old);
+ }
+ if (rc)
+ rc = -1; /* Need to make sure to have this error code. */
+ }
+
/* 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 (kh, issuer, keyid);
+ rc = find_up_external (ctrl, kh, issuer, keyid);
/* Print a note so that the user does not feel too helpless when
an issuer certificate was found and gpgsm prints BAD
@@ -617,6 +697,10 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
rc = keydb_search_subject (kh, issuer);
if (rc == -1 && !find_next)
{
+ /* Also try to get it from the Dirmngr cache. The function
+ merely puts it into the ephemeral database. */
+ find_up_dirmngr (ctrl, kh, NULL, issuer, 0);
+
/* Not found, let us see whether we have one in the ephemeral key DB. */
int old = keydb_set_ephemeral (kh, 1);
if (!old)
@@ -629,7 +713,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
/* Still not found. If enabled, try an external lookup. */
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
- rc = find_up_external (kh, issuer, NULL);
+ rc = find_up_external (ctrl, kh, issuer, NULL);
return rc;
}
@@ -638,7 +722,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
/* Return the next certificate up in the chain starting at START.
Returns -1 when there are no more certificates. */
int
-gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next)
+gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next)
{
int rc = 0;
char *issuer = NULL;
@@ -674,7 +758,7 @@ gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next)
goto leave;
}
- rc = find_up (kh, start, issuer, 0);
+ rc = find_up (ctrl, kh, start, issuer, 0);
if (rc)
{
/* It is quite common not to have a certificate, so better don't
@@ -1194,7 +1278,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
}
if (!rootca_flags->relax)
{
- rc = allowed_ca (subject_cert, NULL, listmode, listfp);
+ rc = allowed_ca (ctrl, subject_cert, NULL, listmode, listfp);
if (rc)
goto leave;
}
@@ -1301,7 +1385,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
/* Find the next cert up the tree. */
keydb_search_reset (kh);
- rc = find_up (kh, subject_cert, issuer, 0);
+ rc = find_up (ctrl, kh, subject_cert, issuer, 0);
if (rc)
{
if (rc == -1)
@@ -1353,7 +1437,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
root certificates. */
/* FIXME: Do this only if we don't have an
AKI.keyIdentifier */
- rc = find_up (kh, subject_cert, issuer, 1);
+ rc = find_up (ctrl, kh, subject_cert, issuer, 1);
if (!rc)
{
ksba_cert_t tmp_cert;
@@ -1393,7 +1477,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
{
int chainlen;
- rc = allowed_ca (issuer_cert, &chainlen, listmode, listfp);
+ rc = allowed_ca (ctrl, issuer_cert, &chainlen, listmode, listfp);
if (rc)
{
/* Not allowed. Check whether this is a trusted root
@@ -1656,7 +1740,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
the DB and that this one is valid; which it should be because it
has been checked using this function. */
int
-gpgsm_basic_cert_check (ksba_cert_t cert)
+gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
{
int rc = 0;
char *issuer = NULL;
@@ -1706,7 +1790,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
{
/* Find the next cert up the tree. */
keydb_search_reset (kh);
- rc = find_up (kh, cert, issuer, 0);
+ rc = find_up (ctrl, kh, cert, issuer, 0);
if (rc)
{
if (rc == -1)
@@ -1771,7 +1855,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
receive the length of the chain which is either 0 or 1.
*/
static int
-get_regtp_ca_info (ksba_cert_t cert, int *chainlen)
+get_regtp_ca_info (ctrl_t ctrl, ksba_cert_t cert, int *chainlen)
{
gpg_error_t err;
ksba_cert_t next;
@@ -1816,7 +1900,7 @@ get_regtp_ca_info (ksba_cert_t cert, int *chainlen)
ksba_cert_ref (cert);
array[depth++] = cert;
ksba_cert_ref (cert);
- while (depth < DIM(array) && !(rc=gpgsm_walk_cert_chain (cert, &next)))
+ while (depth < DIM(array) && !(rc=gpgsm_walk_cert_chain (ctrl, cert, &next)))
{
ksba_cert_release (cert);
ksba_cert_ref (next);