From cd8531210b6cd768a0be29e0c8b6138c631172a7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 26 Feb 2004 22:08:58 +0000 Subject: [PATCH] (compare_certs): New. (gpgsm_validate_chain): Fixed infinite certificate checks after bad signatures. --- sm/ChangeLog | 6 ++++++ sm/certchain.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/sm/ChangeLog b/sm/ChangeLog index 30c3d53df..f6716b0a4 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,9 @@ +2004-02-26 Werner Koch + + * certchain.c (compare_certs): New. + (gpgsm_validate_chain): Fixed infinite certificate checks after + bad signatures. + 2004-02-24 Werner Koch * keylist.c (list_cert_colon): Print the fingerprint as the diff --git a/sm/certchain.c b/sm/certchain.c index 2a59c559d..bb3fd0339 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -65,6 +65,22 @@ do_list (int is_error, int listmode, FILE *fp, const char *format, ...) va_end (arg_ptr); } +/* Return 0 if A and B are equal. */ +static int +compare_certs (ksba_cert_t a, ksba_cert_t b) +{ + const unsigned char *img_a, *img_b; + size_t len_a, len_b; + + img_a = ksba_cert_get_image (a, &len_a); + if (!img_a) + return 1; + img_b = ksba_cert_get_image (b, &len_b); + if (!img_b) + return 1; + return !(len_a == len_b && !memcmp (img_a, img_b, len_a)); +} + static int unknown_criticals (ksba_cert_t cert, int listmode, FILE *fp) @@ -700,7 +716,6 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, goto leave; } - try_another_cert: ksba_cert_release (issuer_cert); issuer_cert = NULL; rc = keydb_get_cert (kh, &issuer_cert); if (rc) @@ -710,6 +725,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, goto leave; } + try_another_cert: if (DBG_X509) { log_debug ("got issuer's certificate:\n"); @@ -722,12 +738,32 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, do_list (0, lm, fp, _("certificate has a BAD signature")); if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) { + /* We now try to find other issuer certificates which + might have been used. This is rquired because some + CAs are reusing the issuer and subject DN for new + root certificates. */ rc = find_up (kh, subject_cert, issuer, 1); if (!rc) { - do_list (0, lm, fp, _("found another possible matching " - "CA certificate - trying again")); - goto try_another_cert; + ksba_cert_t tmp_cert; + + rc = keydb_get_cert (kh, &tmp_cert); + if (rc || !compare_certs (issuer_cert, tmp_cert)) + { + /* The find next did not work or returned an + identical certificate. We better stop here + to avoid infinite checks. */ + rc = gpg_error (GPG_ERR_BAD_SIGNATURE); + ksba_cert_release (tmp_cert); + } + else + { + do_list (0, lm, fp, _("found another possible matching " + "CA certificate - trying again")); + ksba_cert_release (issuer_cert); + issuer_cert = tmp_cert; + goto try_another_cert; + } } }