From fde76a2cf83eab4e0a229cfcffb12e467ff564e8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 17 Mar 2005 19:10:37 +0000 Subject: [PATCH] * certcheck.c: Fixed use of DBG_CRYPTO and DBG_X509. * certchain.c (gpgsm_basic_cert_check): Dump certificates after a failed gcry_pk_verify. (find_up): Do an external lookup also for an authorityKeyIdentifier lookup. Factored external lookup code out to .. (find_up_external): .. new. --- sm/ChangeLog | 12 ++++- sm/certchain.c | 131 +++++++++++++++++++++++++++++++------------------ sm/certcheck.c | 10 ++-- 3 files changed, 98 insertions(+), 55 deletions(-) diff --git a/sm/ChangeLog b/sm/ChangeLog index 85af542d0..bb899f5b7 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,13 @@ +2005-03-17 Werner Koch + + * certcheck.c: Fixed use of DBG_CRYPTO and DBG_X509. + + * certchain.c (gpgsm_basic_cert_check): Dump certificates after a + failed gcry_pk_verify. + (find_up): Do an external lookup also for an authorityKeyIdentifier + lookup. Factored external lookup code out to .. + (find_up_external): .. new. + 2005-03-03 Werner Koch * Makefile.am (gpgsm_LDADD): Added PTH_LIBS. Noted by Kazu Yamamoto. @@ -1407,7 +1417,7 @@ * server.c (rc_to_assuan_status): New. Use it for all commands. - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/sm/certchain.c b/sm/certchain.c index f32507f34..514ee23a5 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -1,5 +1,5 @@ /* certchain.c - certificate chain validation - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -275,6 +275,69 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert) } + +/* Helper for find_up(). Locate the certificate for ISSUER using an + 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().*/ +static int +find_up_external (KEYDB_HANDLE kh, const char *issuer) +{ + int rc; + strlist_t names = NULL; + int count = 0; + char *pattern; + const char *s; + + if (opt.verbose) + log_info (_("looking up issuer at external location\n")); + /* 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. */ + s = strstr (issuer, "CN="); + if (!s || s == issuer || s[-1] != ',') + s = issuer; + + pattern = xtrymalloc (strlen (s)+2); + if (!pattern) + return gpg_error_from_errno (errno); + 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", gpg_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; +} + + +/* 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 + issuer. The certificate itself is not directly returned but a + 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) { @@ -292,7 +355,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next) keydb_search_reset (kh); /* 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 + that in find_next mode because we can't keep the search state then. */ if (rc == -1 && !find_next) { @@ -305,7 +368,12 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next) } keydb_set_ephemeral (kh, old); } + + /* If we didn't found it, try an external lookup. */ + if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next) + rc = find_up_external (kh, issuer); } + /* Print a note so that the user does not feel too helpless when an issuer certificate was found and gpgsm prints BAD signature because it is not the correct one. */ @@ -315,16 +383,17 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next) gpgsm_dump_serial (authidno); log_printf ("/"); gpgsm_dump_string (s); - log_printf (") not found\n"); + log_printf (") not found using authorityKeyIdentifier\n"); } else if (rc) log_error ("failed to find authorityKeyIdentifier: rc=%d\n", rc); ksba_name_release (authid); xfree (authidno); - /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */ + /* Fixme: There is no way to do an external lookup with + serial+issuer. */ } - if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */ + if (rc) /* Not found via authorithyKeyIdentifier, try regular issuer name. */ rc = keydb_search_subject (kh, issuer); if (rc == -1 && !find_next) { @@ -338,51 +407,10 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next) keydb_set_ephemeral (kh, old); } + /* Still not found. If enabled, try an external lookup. */ if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next) - { - 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 as a quick - and ugly hack we locate the CN and use this and the - following. Fixme: we should have far better parsing in the - dirmngr. */ - s = strstr (issuer, "CN="); - if (!s || s == issuer || s[-1] != ',') - s = issuer; + rc = find_up_external (kh, issuer); - pattern = xtrymalloc (strlen (s)+2); - if (!pattern) - return OUT_OF_CORE (errno); - 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", gpg_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; } @@ -959,7 +987,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert) } else { - /* find the next cert up the tree */ + /* Find the next cert up the tree. */ keydb_search_reset (kh); rc = find_up (kh, cert, issuer, 0); if (rc) @@ -990,6 +1018,11 @@ gpgsm_basic_cert_check (ksba_cert_t cert) { log_error ("certificate has a BAD signature: %s\n", gpg_strerror (rc)); + if (DBG_X509) + { + gpgsm_dump_cert ("signing issuer", issuer_cert); + gpgsm_dump_cert ("signed subject", cert); + } rc = gpg_error (GPG_ERR_BAD_CERT); goto leave; } diff --git a/sm/certcheck.c b/sm/certcheck.c index 4f667cbbe..611d3219c 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -101,7 +101,7 @@ do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len; assert ( n == nframe ); } - if (DBG_X509) + if (DBG_CRYPTO) { int j; log_debug ("encoded hash:"); @@ -196,7 +196,7 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) ksba_free (p); return gpg_error (GPG_ERR_BUG); } - if (DBG_X509) + if (DBG_CRYPTO) { int j; log_debug ("signature value:"); @@ -251,7 +251,7 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) rc = gcry_pk_verify (s_sig, s_hash, s_pkey); - if (DBG_CRYPTO) + if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_md_close (md); gcry_sexp_release (s_sig); @@ -294,7 +294,7 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, gcry_sexp_release (s_sig); return gpg_error (GPG_ERR_BUG); } - if (DBG_X509) + if (DBG_CRYPTO) log_printhex ("public key: ", p, n); rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); @@ -321,7 +321,7 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, gcry_mpi_release (frame); rc = gcry_pk_verify (s_sig, s_hash, s_pkey); - if (DBG_CRYPTO) + if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash);