From da89d93c77f695df5f7c1adf9f83bd8a8080cecf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 5 Apr 2004 17:25:21 +0000 Subject: [PATCH] * verify.c (gpgsm_verify): Print STATUS_NEWSIG for each signature. * certchain.c (gpgsm_validate_chain) : Do not just warn if a cert is not suitable; bail out immediately. * call-dirmngr.c (isvalid_status_cb): New. (unhexify_fpr): New. Taken from ../g10/call-agent.c (gpgsm_dirmngr_isvalid): Add new arg CTRL, changed caller to pass it thru. Detect need to check the respondert cert and do that. * certchain.c (gpgsm_validate_chain): Add new arg FLAGS. Changed all callers. --- sm/ChangeLog | 16 +++++++ sm/call-dirmngr.c | 111 ++++++++++++++++++++++++++++++++++++++++++++-- sm/certchain.c | 32 ++++++++----- sm/certlist.c | 5 ++- sm/gpgsm.h | 6 ++- sm/keylist.c | 4 +- sm/sign.c | 2 +- sm/verify.c | 5 ++- 8 files changed, 159 insertions(+), 22 deletions(-) diff --git a/sm/ChangeLog b/sm/ChangeLog index ecf1125c4..c1ca076dd 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,19 @@ +2004-04-05 Werner Koch + + * verify.c (gpgsm_verify): Print STATUS_NEWSIG for each signature. + + * certchain.c (gpgsm_validate_chain) : Do + not just warn if a cert is not suitable; bail out immediately. + +2004-04-01 Werner Koch + + * call-dirmngr.c (isvalid_status_cb): New. + (unhexify_fpr): New. Taken from ../g10/call-agent.c + (gpgsm_dirmngr_isvalid): Add new arg CTRL, changed caller to pass + it thru. Detect need to check the respondert cert and do that. + * certchain.c (gpgsm_validate_chain): Add new arg FLAGS. Changed + all callers. + 2004-03-24 Werner Koch * sign.c (gpgsm_sign): Include a short list of capabilities. diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 4f07fec24..0e8f67f28 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -33,6 +33,8 @@ #include #include "i18n.h" +#include "keydb.h" + struct membuf { size_t len; @@ -52,6 +54,12 @@ struct inq_certificate_parm_s { ksba_cert_t issuer_cert; }; +struct isvalid_status_parm_s { + int seen; + unsigned char fpr[20]; +}; + + struct lookup_parm_s { CTRL ctrl; ASSUAN_CONTEXT ctx; @@ -300,6 +308,42 @@ inq_certificate (void *opaque, const char *line) } +/* Take a 20 byte hexencoded string and put it into the the provided + 20 byte buffer FPR in binary format. */ +static int +unhexify_fpr (const char *hexstr, unsigned char *fpr) +{ + const char *s; + int n; + + for (s=hexstr, n=0; hexdigitp (s); s++, n++) + ; + if (*s || (n != 40)) + return 0; /* no fingerprint (invalid or wrong length). */ + n /= 2; + for (s=hexstr, n=0; *s; s += 2, n++) + fpr[n] = xtoi_2 (s); + return 1; /* okay */ +} + + +static assuan_error_t +isvalid_status_cb (void *opaque, const char *line) +{ + struct isvalid_status_parm_s *parm = opaque; + + if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24) + && (line[24]==' ' || !line[24])) + { + parm->seen++; + if (!line[24] || !unhexify_fpr (line+25, parm->fpr)) + parm->seen++; /* Bumb it to indicate an error. */ + } + return 0; +} + + + /* Call the directory manager to check whether the certificate is valid Returns 0 for valid or usually one of the errors: @@ -312,12 +356,14 @@ inq_certificate (void *opaque, const char *line) request first. */ int -gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp) +gpgsm_dirmngr_isvalid (ctrl_t ctrl, + ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp) { int rc; char *certid; char line[ASSUAN_LINELENGTH]; struct inq_certificate_parm_s parm; + struct isvalid_status_parm_s stparm; rc = start_dirmngr (); if (rc) @@ -349,6 +395,9 @@ gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp) parm.cert = cert; parm.issuer_cert = issuer_cert; + stparm.seen = 0; + memset (stparm.fpr, 0, 20); + /* FIXME: If --disable-crl-checks has been set, we should pass an option to dirmngr, so that no fallback CRL check is done after an ocsp check. */ @@ -358,10 +407,66 @@ gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp) xfree (certid); rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, - inq_certificate, &parm, NULL, NULL); + inq_certificate, &parm, + isvalid_status_cb, &stparm); if (opt.verbose > 1) log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay"); - return map_assuan_err (rc); + rc = map_assuan_err (rc); + + if (!rc && stparm.seen) + { + /* Need to also check the certificate validity. */ + if (stparm.seen != 1) + { + log_error ("communication problem with dirmngr detected\n"); + rc = gpg_error (GPG_ERR_INV_CRL); + } + else + { + KEYDB_HANDLE kh; + ksba_cert_t rspcert = NULL; + + /* Fixme: First try to get the certificate from the + dirmngr's cache - it should be there. */ + kh = keydb_new (0); + if (!kh) + rc = gpg_error (GPG_ERR_ENOMEM); + if (!rc) + rc = keydb_search_fpr (kh, stparm.fpr); + if (!rc) + rc = keydb_get_cert (kh, &rspcert); + if (rc) + { + log_error ("unable to find the certificate used " + "by the dirmngr: %s\n", gpg_strerror (rc)); + rc = gpg_error (GPG_ERR_INV_CRL); + } + keydb_release (kh); + + if (!rc) + { + /* fixme: We should refine the check to check for + certificates allowed for CRL/OCPS. */ + rc = gpgsm_cert_use_verify_p (rspcert); + if (rc) + rc = gpg_error (GPG_ERR_INV_CRL); + else + { + /* Note, the flag = 1: This avoids checking this + certificate over and over again. */ + rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1); + if (rc) + { + log_error ("invalid certificate used for CRL/OCSP: %s\n", + gpg_strerror (rc)); + rc = gpg_error (GPG_ERR_INV_CRL); + } + } + } + ksba_cert_release (rspcert); + } + } + return rc; } diff --git a/sm/certchain.c b/sm/certchain.c index 5056139df..3bdba2a9d 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -480,7 +480,8 @@ is_cert_still_valid (ctrl_t ctrl, int lm, FILE *fp, { gpg_error_t err; - err = gpgsm_dirmngr_isvalid (subject_cert, issuer_cert, ctrl->use_ocsp); + err = gpgsm_dirmngr_isvalid (ctrl, + subject_cert, issuer_cert, ctrl->use_ocsp); if (err) { /* Fixme: We should change the wording because we may @@ -522,10 +523,13 @@ is_cert_still_valid (ctrl_t ctrl, int lm, FILE *fp, /* Validate a chain and optionally return the nearest expiration time in R_EXPTIME. With LISTMODE set to 1 a special listmode is activated where only information about the certificate is printed - to FP and no outputis send to the usual log stream. */ + to FP and no output is send to the usual log stream. + + Defined flag bits: 0 - do not do any dirmngr isvalid checks. +*/ int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, - int listmode, FILE *fp) + int listmode, FILE *fp, unsigned int flags) { int rc = 0, depth = 0, maxdepth; char *issuer = NULL; @@ -698,10 +702,13 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, } /* Check for revocations etc. */ - rc = is_cert_still_valid (ctrl, lm, fp, - subject_cert, subject_cert, - &any_revoked, &any_no_crl, - &any_crl_too_old); + if ((flags & 1)) + rc = 0; + else + rc = is_cert_still_valid (ctrl, lm, fp, + subject_cert, subject_cert, + &any_revoked, &any_no_crl, + &any_crl_too_old); if (rc) goto leave; @@ -818,14 +825,17 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, sprintf (numbuf, "%d", rc); gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage", numbuf, NULL); - rc = 0; + goto leave; } } /* Check for revocations etc. */ - rc = is_cert_still_valid (ctrl, lm, fp, - subject_cert, issuer_cert, - &any_revoked, &any_no_crl, &any_crl_too_old); + if ((flags & 1)) + rc = 0; + else + rc = is_cert_still_valid (ctrl, lm, fp, + subject_cert, issuer_cert, + &any_revoked, &any_no_crl, &any_crl_too_old); if (rc) goto leave; diff --git a/sm/certlist.c b/sm/certlist.c index 6e694b781..0394a584f 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -130,7 +130,8 @@ cert_usage_p (ksba_cert_t cert, int mode) { if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN))) return 0; - log_info ( _("certificate should have not been used certification\n")); + log_info (_("certificate should have not " + "been used for certification\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -347,7 +348,7 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret, } } if (!rc) - rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL); + rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0); if (!rc) { CERTLIST cl = xtrycalloc (1, sizeof *cl); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 62bc05354..93487f002 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -222,7 +222,8 @@ int gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next); int gpgsm_is_root_cert (ksba_cert_t cert); int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, - int listmode, FILE *listfp); + int listmode, FILE *listfp, + unsigned int flags); int gpgsm_basic_cert_check (ksba_cert_t cert); /*-- certlist.c --*/ @@ -288,7 +289,8 @@ int gpgsm_agent_learn (void); int gpgsm_agent_passwd (const char *hexkeygrip, const char *desc); /*-- call-dirmngr.c --*/ -int gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, +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 names, void (*cb)(void*, ksba_cert_t), void *cb_value); diff --git a/sm/keylist.c b/sm/keylist.c index 80cc675db..4e6f28db8 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -182,7 +182,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, gpg_error_t valerr; if (ctrl->with_validation) - valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL); + valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL, 0); else valerr = 0; @@ -483,7 +483,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret, if (with_validation) { - err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp); + err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp, 0); if (!err) fprintf (fp, " [certificate is good]\n"); else diff --git a/sm/sign.c b/sm/sign.c index 3cc1444b7..473cf93a2 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -378,7 +378,7 @@ gpgsm_sign (CTRL ctrl, CERTLIST signerlist, valid. */ rc = gpgsm_cert_use_sign_p (cert); if (!rc) - rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL); + rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0); if (rc) goto leave; diff --git a/sm/verify.c b/sm/verify.c index bd334908e..4b43ed064 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -263,6 +263,9 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) err = 0; break; } + + gpgsm_status (ctrl, STATUS_NEWSIG, NULL); + if (DBG_X509) { log_debug ("signer %d - issuer: `%s'\n", @@ -458,7 +461,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp) if (DBG_X509) log_debug ("signature okay - checking certs\n"); - rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL); + rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL, 0); if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED) { gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);