diff options
Diffstat (limited to 'sm')
-rw-r--r-- | sm/Makefile.am | 4 | ||||
-rw-r--r-- | sm/call-dirmngr.c | 55 | ||||
-rw-r--r-- | sm/certchain.c | 54 | ||||
-rw-r--r-- | sm/gpgsm.c | 4 | ||||
-rw-r--r-- | sm/gpgsm.h | 12 | ||||
-rw-r--r-- | sm/keydb.c | 2 | ||||
-rw-r--r-- | sm/keylist.c | 18 | ||||
-rw-r--r-- | sm/verify.c | 17 |
8 files changed, 140 insertions, 26 deletions
diff --git a/sm/Makefile.am b/sm/Makefile.am index c676adac9..cfcc36c63 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -70,8 +70,8 @@ common_libs = ../kbx/libkeybox509.a $(libcommonpth) gpgsm_LDADD = $(common_libs) ../common/libgpgrl.a \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ $(NPTH_LIBS) $(GPG_ERROR_LIBS) $(LIBREADLINE) $(LIBINTL) \ - $(LIBICONV) $(resource_objs) $(extra_sys_libs) $(NETLIBS) -gpgsm_LDFLAGS = $(extra_bin_ldflags) + $(LIBICONV) $(resource_objs) $(NETLIBS) +gpgsm_LDFLAGS = module_tests = diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 5dd8a3938..cc958ccf8 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -64,6 +64,8 @@ struct isvalid_status_parm_s { ctrl_t ctrl; int seen; unsigned char fpr[20]; + gnupg_isotime_t revoked_at; + char *revocation_reason; /* malloced or NULL */ }; @@ -491,6 +493,19 @@ isvalid_status_cb (void *opaque, const char *line) if (!*s || !unhexify_fpr (s, parm->fpr)) parm->seen++; /* Bump it to indicate an error. */ } + else if ((s = has_leading_keyword (line, "REVOCATIONINFO"))) + { + if (*s && strlen (s) >= 15) + { + memcpy (parm->revoked_at, s, 15); + parm->revoked_at[15] = 0; + } + s += 15; + while (*s && spacep (s)) + s++; + xfree (parm->revocation_reason); + parm->revocation_reason = *s? xtrystrdup (s) : NULL; + } else if (warning_and_note_printer (line)) { } @@ -510,12 +525,17 @@ isvalid_status_cb (void *opaque, const char *line) Values for USE_OCSP: 0 = Do CRL check. - 1 = Do an OCSP check but fallback to CRL unless CRLS are disabled. - 2 = Do only an OCSP check using only the default responder. + 1 = Do an OCSP check but fallback to CRL unless CRLs are disabled. + 2 = Do only an OCSP check (used for the chain model). + + If R_REVOKED_AT pr R_REASON are not NULL and the certificate has + been revoked the revocation time and the reason are copied to there. + The caller needs to free R_REASON. */ -int +gpg_error_t gpgsm_dirmngr_isvalid (ctrl_t ctrl, - ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp) + ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp, + gnupg_isotime_t r_revoked_at, char **r_reason) { static int did_options; int rc; @@ -524,6 +544,11 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, struct inq_certificate_parm_s parm; struct isvalid_status_parm_s stparm; + if (r_revoked_at) + *r_revoked_at = 0; + if (r_reason) + *r_reason = NULL; + rc = start_dirmngr (ctrl); if (rc) return rc; @@ -553,6 +578,8 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, stparm.ctrl = ctrl; stparm.seen = 0; memset (stparm.fpr, 0, 20); + stparm.revoked_at[0] = 0; + stparm.revocation_reason = NULL; /* It is sufficient to send the options only once because we have * one connection per process only. */ @@ -563,9 +590,8 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, NULL, NULL, NULL, NULL, NULL, NULL); did_options = 1; } - snprintf (line, DIM(line), "ISVALID%s%s %s%s%s", - use_ocsp == 2 || opt.no_crl_check ? " --only-ocsp":"", - use_ocsp == 2? " --force-default-responder":"", + snprintf (line, DIM(line), "ISVALID%s %s%s%s", + (use_ocsp == 2 || opt.no_crl_check) ? " --only-ocsp":"", certid, use_ocsp? " ":"", use_ocsp? certfpr:""); @@ -578,6 +604,19 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, if (opt.verbose > 1) log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay"); + if (gpg_err_code (rc) == GPG_ERR_CERT_REVOKED + && !check_isotime (stparm.revoked_at)) + { + if (r_revoked_at) + gnupg_copy_time (r_revoked_at, stparm.revoked_at); + if (r_reason) + { + *r_reason = stparm.revocation_reason; + stparm.revocation_reason = NULL; + } + + } + if (!rc && stparm.seen) { /* Need to also check the certificate validity. */ @@ -635,7 +674,9 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, ksba_cert_release (rspcert); } } + release_dirmngr (ctrl); + xfree (stparm.revocation_reason); return rc; } diff --git a/sm/certchain.c b/sm/certchain.c index 4050680e8..cbb6e1127 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -350,7 +350,7 @@ check_cert_policy (ksba_cert_t cert, int listmode, estream_t fplist) /* With no critical policies this is only a warning */ if (!any_critical) { - if (!opt.quiet) + if (opt.verbose) do_list (0, listmode, fplist, _("Note: non-critical certificate policy not allowed")); return 0; @@ -380,7 +380,8 @@ check_cert_policy (ksba_cert_t cert, int listmode, estream_t fplist) /* With no critical policies this is only a warning */ if (!any_critical) { - do_list (0, listmode, fplist, + if (opt.verbose) + do_list (0, listmode, fplist, _("Note: non-critical certificate policy not allowed")); return 0; } @@ -1187,11 +1188,13 @@ gpgsm_is_root_cert (ksba_cert_t cert) /* This is a helper for gpgsm_validate_chain. */ static gpg_error_t -is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp, +is_cert_still_valid (ctrl_t ctrl, int chain_model, int lm, estream_t fp, ksba_cert_t subject_cert, ksba_cert_t issuer_cert, int *any_revoked, int *any_no_crl, int *any_crl_too_old) { gpg_error_t err; + gnupg_isotime_t revoked_at; + char *reason; if (ctrl->offline || (opt.no_crl_check && !ctrl->use_ocsp)) { @@ -1201,7 +1204,7 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp, } - if (!(force_ocsp || ctrl->use_ocsp) + if (!(chain_model || ctrl->use_ocsp) && !opt.enable_issuer_based_crl_check) { err = ksba_cert_get_crl_dist_point (subject_cert, 0, NULL, NULL, NULL); @@ -1220,7 +1223,20 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp, err = gpgsm_dirmngr_isvalid (ctrl, subject_cert, issuer_cert, - force_ocsp? 2 : !!ctrl->use_ocsp); + chain_model? 2 : !!ctrl->use_ocsp, + revoked_at, &reason); + if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED) + { + gnupg_copy_time (ctrl->revoked_at, revoked_at); + xfree (ctrl->revocation_reason); + ctrl->revocation_reason = reason; + reason = NULL; + } + else + { + xfree (reason); + reason = (NULL); + } audit_log_ok (ctrl->audit, AUDIT_CRL_CHECK, err); if (err) @@ -1230,7 +1246,22 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp, switch (gpg_err_code (err)) { case GPG_ERR_CERT_REVOKED: - do_list (1, lm, fp, _("certificate has been revoked")); + if (!check_isotime (ctrl->revoked_at)) + { + char *tmpstr; + const unsigned char *t = ctrl->revoked_at; + + tmpstr = xtryasprintf ("%.4s-%.2s-%.2s %.2s:%.2s:%s (%s)", + t, t+4, t+6, t+9, t+11, t+13, + ctrl->revocation_reason? + ctrl->revocation_reason : ""); + + do_list (1, lm, fp, "%s: %s", + _("certificate has been revoked"), tmpstr); + xfree (tmpstr); + } + else + do_list (1, lm, fp, _("certificate has been revoked")); *any_revoked = 1; /* Store that in the keybox so that key listings are able to return the revoked flag. We don't care about error, @@ -2158,11 +2189,14 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime, { *retflags |= VALIDATE_FLAG_STEED; } - else if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED - && !(flags & VALIDATE_FLAG_CHAIN_MODEL) - && (rootca_flags.valid && rootca_flags.chain_model)) + else if (!(flags & VALIDATE_FLAG_CHAIN_MODEL) + && (rootca_flags.valid && rootca_flags.chain_model)) { - do_list (0, listmode, listfp, _("switching to chain model")); + /* The root CA indicated that the chain model is to be used but + * we have not yet used it. Thus do the validation again using + * the chain model. */ + if (opt.verbose) + do_list (0, listmode, listfp, _("switching to chain model")); rc = do_validate_chain (ctrl, cert, checktime, r_exptime, listmode, listfp, (flags |= VALIDATE_FLAG_CHAIN_MODEL), diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 3247a0f2e..f8b3856c2 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -2228,6 +2228,8 @@ gpgsm_init_default_ctrl (struct server_control_s *ctrl) ctrl->use_ocsp = opt.enable_ocsp; ctrl->validation_model = default_validation_model; ctrl->offline = opt.disable_dirmngr; + ctrl->revoked_at[0] = 0; + ctrl->revocation_reason = NULL; } @@ -2237,6 +2239,8 @@ void gpgsm_deinit_default_ctrl (ctrl_t ctrl) { gpgsm_keydb_deinit_session_data (ctrl); + xfree (ctrl->revocation_reason); + ctrl->revocation_reason = NULL; } diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 9fbb53a29..ced2d679f 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -264,6 +264,10 @@ struct server_control_s /* The current time. Used as a helper in certchain.c. */ ksba_isotime_t current_time; + + /* The revocation info. Used as a helper inc ertchain.c */ + gnupg_isotime_t revoked_at; + char *revocation_reason; }; @@ -494,9 +498,11 @@ gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, size_t *r_resultlen); /*-- call-dirmngr.c --*/ -int gpgsm_dirmngr_isvalid (ctrl_t ctrl, - ksba_cert_t cert, ksba_cert_t issuer_cert, - int use_ocsp); +gpg_error_t gpgsm_dirmngr_isvalid (ctrl_t ctrl, + ksba_cert_t cert, ksba_cert_t issuer_cert, + int use_ocsp, + gnupg_isotime_t r_revoked_at, + char **r_reason); int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri, int cache_only, void (*cb)(void*, ksba_cert_t), void *cb_value); diff --git a/sm/keydb.c b/sm/keydb.c index 5b28df7ab..fbe28f2b9 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -2027,7 +2027,7 @@ keydb_set_cert_flags (ctrl_t ctrl, ksba_cert_t cert, int ephemeral, err = keydb_search_fpr (ctrl, kh, fpr); if (err) { - if (gpg_err_code (err) != gpg_error (GPG_ERR_NOT_FOUND)) + if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) log_error (_("problem re-searching certificate: %s\n"), gpg_strerror (err)); keydb_release (kh); diff --git a/sm/keylist.c b/sm/keylist.c index fb2c3bad5..fabd82224 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -1201,6 +1201,15 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, { err = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL, 1, fp, 0, NULL); + if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED + && !check_isotime (ctrl->revoked_at)) + { + es_fputs (" revoked: ", fp); + gpgsm_print_time (fp, ctrl->revoked_at); + if (ctrl->revocation_reason) + es_fprintf (fp, " (%s)", ctrl->revocation_reason); + es_putc ('\n', fp); + } if (!err) es_fprintf (fp, " [certificate is good]\n"); else @@ -1451,6 +1460,15 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, err = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL, 1, fp, 0, NULL); + if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED + && !check_isotime (ctrl->revoked_at)) + { + es_fputs (" revoked: ", fp); + gpgsm_print_time (fp, ctrl->revoked_at); + if (ctrl->revocation_reason) + es_fprintf (fp, " (%s)", ctrl->revocation_reason); + es_putc ('\n', fp); + } tmperr = ksba_cert_get_user_data (cert, "is_qualified", &buffer, sizeof (buffer), &buflen); if (!tmperr && buflen) diff --git a/sm/verify.c b/sm/verify.c index 2e40c021f..9f1216f83 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -299,6 +299,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) unsigned int nbits; int pkalgo; char *pkalgostr = NULL; + char *pkcurve = NULL; char *pkfpr = NULL; unsigned int pkalgoflags, verifyflags; @@ -457,7 +458,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); - pkalgo = gpgsm_get_key_algo_info (cert, &nbits); + pkalgo = gpgsm_get_key_algo_info2 (cert, &nbits, &pkcurve); /* Remap the ECC algo to the algo we use. Note that EdDSA has * already been mapped. */ if (pkalgo == GCRY_PK_ECC) @@ -513,9 +514,19 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) goto next_signer; } + /* Print compliance warning for the key. */ + if (!opt.quiet + && !gnupg_pk_is_compliant (opt.compliance, pkalgo, pkalgoflags, + NULL, nbits, pkcurve)) + { + log_info (_("WARNING: This key is not suitable for signing" + " in %s mode\n"), + gnupg_compliance_option_string (opt.compliance)); + } + /* Check compliance with CO_DE_VS. */ if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags, - NULL, nbits, NULL) + NULL, nbits, pkcurve) && gnupg_gcrypt_is_compliant (CO_DE_VS) && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo)) gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE, @@ -528,7 +539,6 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) gpgsm_errors_seen = 1; } - /* Now we can check the signature. */ if (msgdigest) { /* Signed attributes are available. */ @@ -715,6 +725,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) gcry_sexp_release (sigval); xfree (msgdigest); xfree (pkalgostr); + xfree (pkcurve); xfree (pkfpr); ksba_cert_release (cert); cert = NULL; |