diff --git a/sm/ChangeLog b/sm/ChangeLog index 160fe4766..6a0200ba0 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,19 @@ +2002-06-29 Werner Koch + + * gpgsm.c: New option --auto-issuer-key-retrieve. + * certpath.c (find_up): Try to retrieve an issuer key from an + external source and from the ephemeral key DB. + (find_up_store_certs_cb): New. + + * keydb.c (keydb_set_ephemeral): Does now return the old + state. Call the backend only when required. + + * call-dirmngr.c (start_dirmngr): Use GNUPG_DEFAULT_DIRMNGR. + (lookup_status_cb): Issue status only when CTRL is not NULL. + (gpgsm_dirmngr_lookup): Document that CTRL is optional. + + * call-agent.c (start_agent): Use GNUPG_DEFAULT_AGENT. + 2002-06-28 Werner Koch * server.c (cmd_recipient): Add more reason codes. diff --git a/sm/call-agent.c b/sm/call-agent.c index b3c78579c..9462deb40 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -164,7 +164,7 @@ start_agent (void) } if (!opt.agent_program || !*opt.agent_program) - opt.agent_program = "../agent/gpg-agent"; + opt.agent_program = GNUPG_DEFAULT_AGENT; if ( !(pgmname = strrchr (opt.agent_program, '/'))) pgmname = opt.agent_program; else diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 017191dbe..30b34762f 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -156,7 +156,7 @@ start_dirmngr (void) } if (!opt.dirmngr_program || !*opt.dirmngr_program) - opt.dirmngr_program = "/usr/sbin/dirmngr"; + opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR; if ( !(pgmname = strrchr (opt.dirmngr_program, '/'))) pgmname = opt.dirmngr_program; else @@ -432,9 +432,12 @@ lookup_status_cb (void *opaque, const char *line) if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9])) { - for (line +=9; *line == ' '; line++) - ; - gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line); + if (parm->ctrl) + { + for (line +=9; *line == ' '; line++) + ; + gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line); + } } return 0; } @@ -442,7 +445,8 @@ lookup_status_cb (void *opaque, const char *line) /* Run the Directroy Managers lookup command using the apptern compiled from the strings given in NAMES. The caller must provide - the callback CB which will be passed cert by cert. */ + the callback CB which will be passed cert by cert. Note that CTRL + is optional. */ int gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names, void (*cb)(void*, KsbaCert), void *cb_value) diff --git a/sm/certchain.c b/sm/certchain.c index a32c2d7f7..0457a0aa1 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -196,6 +196,15 @@ check_cert_policy (KsbaCert cert) } +static void +find_up_store_certs_cb (void *cb_value, KsbaCert cert) +{ + if (keydb_store_cert (cert, 1)) + log_error ("error storing issuer certificate as ephemeral\n"); + ++*(int*)cb_value; +} + + static int find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer) { @@ -211,13 +220,82 @@ find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer) rc = keydb_search_issuer_sn (kh, s, authidno); if (rc) keydb_search_reset (kh); + if (rc == -1) + { /* And try the ephemeral DB. */ + int old = keydb_set_ephemeral (kh, 1); + if (!old) + { + rc = keydb_search_issuer_sn (kh, s, authidno); + if (rc) + keydb_search_reset (kh); + } + keydb_set_ephemeral (kh, old); + } } ksba_name_release (authid); xfree (authidno); + /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */ } - if (rc) - rc = keydb_search_subject (kh, issuer); + if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */ + rc = keydb_search_subject (kh, issuer); + if (rc == -1) + { + /* Not found, lets see whether we have one in the ephemeral key DB. */ + int old = keydb_set_ephemeral (kh, 1); + if (!old) + { + keydb_search_reset (kh); + rc = keydb_search_subject (kh, issuer); + } + keydb_set_ephemeral (kh, old); + } + + if (rc == -1 && opt.auto_issuer_key_retrieve) + { + STRLIST names = NULL; + int count = 0; + char *pattern; + const char *s; + + if (opt.verbose) + log_info (_("looking up issuer at external location\n")); + /* dirmngr is confused about unknown attributes so has a quick + and ugly hack we locate the CN and use this and the + following. Fixme: we should have far ebtter parsing in the + dirmngr. */ + s = strstr (issuer, "CN="); + if (!s || s == issuer || s[-1] != ',') + s = issuer; + + pattern = xtrymalloc (strlen (s)+2); + if (!pattern) + return GNUPG_Out_Of_Core; + strcpy (stpcpy (pattern, "/"), s); + add_to_strlist (&names, pattern); + xfree (pattern); + rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count); + free_strlist (names); + if (opt.verbose) + log_info (_("number of issuers matching: %d\n"), count); + if (rc) + { + log_error ("external key lookup failed: %s\n", gnupg_strerror (rc)); + rc = -1; + } + else if (!count) + rc = -1; + else + { + int old; + /* The issuers 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); + rc = keydb_search_subject (kh, issuer); + keydb_set_ephemeral (kh, old); + } + } return rc; } diff --git a/sm/certpath.c b/sm/certpath.c index a32c2d7f7..0457a0aa1 100644 --- a/sm/certpath.c +++ b/sm/certpath.c @@ -196,6 +196,15 @@ check_cert_policy (KsbaCert cert) } +static void +find_up_store_certs_cb (void *cb_value, KsbaCert cert) +{ + if (keydb_store_cert (cert, 1)) + log_error ("error storing issuer certificate as ephemeral\n"); + ++*(int*)cb_value; +} + + static int find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer) { @@ -211,13 +220,82 @@ find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer) rc = keydb_search_issuer_sn (kh, s, authidno); if (rc) keydb_search_reset (kh); + if (rc == -1) + { /* And try the ephemeral DB. */ + int old = keydb_set_ephemeral (kh, 1); + if (!old) + { + rc = keydb_search_issuer_sn (kh, s, authidno); + if (rc) + keydb_search_reset (kh); + } + keydb_set_ephemeral (kh, old); + } } ksba_name_release (authid); xfree (authidno); + /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */ } - if (rc) - rc = keydb_search_subject (kh, issuer); + if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */ + rc = keydb_search_subject (kh, issuer); + if (rc == -1) + { + /* Not found, lets see whether we have one in the ephemeral key DB. */ + int old = keydb_set_ephemeral (kh, 1); + if (!old) + { + keydb_search_reset (kh); + rc = keydb_search_subject (kh, issuer); + } + keydb_set_ephemeral (kh, old); + } + + if (rc == -1 && opt.auto_issuer_key_retrieve) + { + STRLIST names = NULL; + int count = 0; + char *pattern; + const char *s; + + if (opt.verbose) + log_info (_("looking up issuer at external location\n")); + /* dirmngr is confused about unknown attributes so has a quick + and ugly hack we locate the CN and use this and the + following. Fixme: we should have far ebtter parsing in the + dirmngr. */ + s = strstr (issuer, "CN="); + if (!s || s == issuer || s[-1] != ',') + s = issuer; + + pattern = xtrymalloc (strlen (s)+2); + if (!pattern) + return GNUPG_Out_Of_Core; + strcpy (stpcpy (pattern, "/"), s); + add_to_strlist (&names, pattern); + xfree (pattern); + rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count); + free_strlist (names); + if (opt.verbose) + log_info (_("number of issuers matching: %d\n"), count); + if (rc) + { + log_error ("external key lookup failed: %s\n", gnupg_strerror (rc)); + rc = -1; + } + else if (!count) + rc = -1; + else + { + int old; + /* The issuers 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); + rc = keydb_search_subject (kh, issuer); + keydb_set_ephemeral (kh, old); + } + } return rc; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 9d91cd9db..7b1b0d715 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -112,7 +112,7 @@ enum cmd_and_opt_values { oPolicyFile, oDisablePolicyChecks, oEnablePolicyChecks, - + oAutoIssuerKeyRetrieve, oTextmode, @@ -259,6 +259,9 @@ static ARGPARSE_OPTS opts[] = { N_("do not check certificate policies")}, { oEnablePolicyChecks, "enable-policy-checks", 0, "@"}, + { oAutoIssuerKeyRetrieve, "auto-issuer-key-retrieve", 0, + N_("fetch missing issuer certificates")}, + #if 0 { oDefRecipient, "default-recipient" ,2, N_("|NAME|use NAME as default recipient")}, @@ -809,7 +812,10 @@ main ( int argc, char **argv) case oEnablePolicyChecks: opt.no_policy_check = 0; break; - + + case oAutoIssuerKeyRetrieve: + opt.auto_issuer_key_retrieve = 1; + break; case oOutput: opt.outfile = pargs.r.ret_str; break; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index b4f7ebe5c..efa98dee5 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -79,6 +79,8 @@ struct { char *policy_file; /* full pathname of policy file */ int no_policy_check; /* ignore certificate policies */ int no_path_validation; /* Bypass all cert path validity tests */ + + int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */ } opt; diff --git a/sm/keydb.c b/sm/keydb.c index bc4721418..52f40f1ad 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -59,7 +59,7 @@ struct keydb_handle { int locked; int found; int current; - int ephemeral; + int is_ephemeral; int used; /* items in active */ struct resource_item active[MAX_KEYDB_RESOURCES]; }; @@ -332,27 +332,34 @@ keydb_get_resource_name (KEYDB_HANDLE hd) return s? s: ""; } +/* Switch the handle into ephemeral mode and return the orginal value. */ int keydb_set_ephemeral (KEYDB_HANDLE hd, int yes) { int i; if (!hd) - return GNUPG_Invalid_Value; + return 0; - for (i=0; i < hd->used; i++) + yes = !!yes; + if (hd->is_ephemeral != yes) { - switch (hd->active[i].type) + for (i=0; i < hd->used; i++) { - case KEYDB_RESOURCE_TYPE_NONE: - break; - case KEYDB_RESOURCE_TYPE_KEYBOX: - keybox_set_ephemeral (hd->active[i].u.kr, yes); - break; + switch (hd->active[i].type) + { + case KEYDB_RESOURCE_TYPE_NONE: + break; + case KEYDB_RESOURCE_TYPE_KEYBOX: + keybox_set_ephemeral (hd->active[i].u.kr, yes); + break; + } } } - - return 0; + + i = hd->is_ephemeral; + hd->is_ephemeral = yes; + return i; }