/* Check the signature of an OCSP repsonse. OCSP is the context, S_SIG the signature value and MD the handle of the hash we used for the response. This function automagically finds the correct public key. If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been used and thus the certificate is one of those identified by the fingerprints. */ static gpg_error_t check_signature (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_sexp_t s_sig, gcry_md_hd_t md, fingerprint_list_t signer_fpr_list) { gpg_error_t err; int algo, cert_idx; gcry_sexp_t s_hash; ksba_cert_t cert; /* Create a suitable S-expression with the hash value of our response. */ gcry_md_final (md); algo = gcry_md_get_algo (md); if (algo != GCRY_MD_SHA1 ) { log_error (_("only SHA-1 is supported for OCSP responses\n")); return gpg_error (GPG_ERR_DIGEST_ALGO); } err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))", gcry_md_get_algo_dlen (algo), gcry_md_read (md, algo)); if (err) { log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err)); return err; } /* Get rid of old OCSP specific certificate references. */ release_ctrl_ocsp_certs (ctrl); if (signer_fpr_list && !signer_fpr_list->next) { /* There is exactly one signer fingerprint given. Thus we use the default OCSP responder's certificate and instantly know the certificate to use. */ cert = get_cert_byhexfpr (signer_fpr_list->hexfpr); if (!cert) cert = get_cert_local (ctrl, signer_fpr_list->hexfpr); if (cert) { err = check_signature_core (ctrl, cert, s_sig, s_hash, signer_fpr_list); ksba_cert_release (cert); cert = NULL; if (!err) { gcry_sexp_release (s_hash); return 0; /* Successfully verified the signature. */ } } } else { char *name; ksba_sexp_t keyid; /* Put all certificates included in the response into the cache and setup a list of those certificate which will later be preferred used when locating certificates. */ for (cert_idx=0; (cert = ksba_ocsp_get_cert (ocsp, cert_idx)); cert_idx++) { cert_ref_t cref; cref = xtrymalloc (sizeof *cref); if (!cref) log_error (_("allocating list item failed: %s\n"), gcry_strerror (err)); else if (!cache_cert_silent (cert, &cref->fpr)) { cref->next = ctrl->ocsp_certs; ctrl->ocsp_certs = cref; } else xfree (cref); } /* Get the certificate by means of the responder ID. */ err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid); if (err) { log_error (_("error getting responder ID: %s\n"), gcry_strerror (err)); return err; } cert = find_cert_bysubject (ctrl, name, keyid); if (!cert) { log_error ("responder certificate "); if (name) log_printf ("'/%s' ", name); if (keyid) { log_printf ("{"); dump_serial (keyid); log_printf ("} "); } log_printf ("not found\n"); } ksba_free (name); ksba_free (keyid); if (cert) { err = check_signature_core (ctrl, cert, s_sig, s_hash, signer_fpr_list); ksba_cert_release (cert); if (!err) { gcry_sexp_release (s_hash); return 0; /* Successfully verified the signature. */ } } } gcry_sexp_release (s_hash); log_error (_("no suitable certificate found to verify the OCSP response\n")); return gpg_error (GPG_ERR_NO_PUBKEY); }
void one_response (const char *cert_fname, const char *issuer_cert_fname, char *response_fname) { gpg_error_t err; ksba_ocsp_t ocsp; unsigned char *request, *response; size_t requestlen, responselen; ksba_cert_t cert = get_one_cert (cert_fname); ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname); ksba_ocsp_response_status_t response_status; const char *t; err = ksba_ocsp_new (&ocsp); fail_if_err (err); /* We need to build a request, so that the context is properly prepared for the response. */ err = ksba_ocsp_add_target (ocsp, cert, issuer_cert); fail_if_err (err); ksba_cert_release (issuer_cert); if (!no_nonce) ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16); err = ksba_ocsp_build_request (ocsp, &request, &requestlen); fail_if_err (err); xfree (request); /* Now for the response. */ response = read_file (response_fname, &responselen); if (!response) fail ("file error"); err = ksba_ocsp_parse_response (ocsp, response, responselen, &response_status); fail_if_err (err); switch (response_status) { case KSBA_OCSP_RSPSTATUS_SUCCESS: t = "success"; break; case KSBA_OCSP_RSPSTATUS_MALFORMED: t = "malformed"; break; case KSBA_OCSP_RSPSTATUS_INTERNAL: t = "internal error"; break; case KSBA_OCSP_RSPSTATUS_TRYLATER: t = "try later"; break; case KSBA_OCSP_RSPSTATUS_SIGREQUIRED: t = "must sign request"; break; case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break; case KSBA_OCSP_RSPSTATUS_REPLAYED: t = "replay detected"; break; case KSBA_OCSP_RSPSTATUS_OTHER: t = "other (unknown)"; break; case KSBA_OCSP_RSPSTATUS_NONE: t = "no status"; break; default: fail ("impossible response_status"); break; } printf ("response status ..: %s\n", t); if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS || response_status == KSBA_OCSP_RSPSTATUS_REPLAYED) { ksba_status_t status; ksba_crl_reason_t reason; ksba_isotime_t this_update, next_update, revocation_time, produced_at; ksba_sexp_t sigval; char *name; ksba_sexp_t keyid; err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid); fail_if_err (err); printf ("responder id .....: "); if (name) printf ("`%s'", name); else print_sexp (keyid); putchar ('\n'); ksba_free (name); ksba_free (keyid); sigval = ksba_ocsp_get_sig_val (ocsp, produced_at); printf ("signature value ..: "); print_sexp (sigval); printf ("\nproduced at ......: "); print_time (produced_at); putchar ('\n'); err = ksba_ocsp_get_status (ocsp, cert, &status, this_update, next_update, revocation_time, &reason); fail_if_err (err); printf ("certificate status: %s\n", status == KSBA_STATUS_GOOD? "good": status == KSBA_STATUS_REVOKED? "revoked": status == KSBA_STATUS_UNKNOWN? "unknown": status == KSBA_STATUS_NONE? "none": "?"); if (status == KSBA_STATUS_REVOKED) { printf ("revocation time ..: "); print_time (revocation_time); printf ("\nrevocation reason : %s\n", reason == KSBA_CRLREASON_UNSPECIFIED? "unspecified": reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise": reason == KSBA_CRLREASON_CA_COMPROMISE? "CA compromise": reason == KSBA_CRLREASON_AFFILIATION_CHANGED? "affiliation changed": reason == KSBA_CRLREASON_SUPERSEDED? "superseeded": reason == KSBA_CRLREASON_CESSATION_OF_OPERATION? "cessation of operation": reason == KSBA_CRLREASON_CERTIFICATE_HOLD? "certificate on hold": reason == KSBA_CRLREASON_REMOVE_FROM_CRL? "removed from CRL": reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN? "privilege withdrawn": reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise": reason == KSBA_CRLREASON_OTHER? "other":"?"); } printf ("this update ......: "); print_time (this_update); printf ("\nnext update ......: "); print_time (next_update); putchar ('\n'); { int cert_idx; ksba_cert_t acert; for (cert_idx=0; (acert = ksba_ocsp_get_cert (ocsp, cert_idx)); cert_idx++) ksba_cert_release (acert); printf ("extra certificates: %d\n", cert_idx ); } { int idx, crit; const char *oid; const unsigned char *der; size_t derlen; for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, NULL, idx, &oid, &crit, &der, &derlen)); idx++) { const char *s = get_oid_desc (oid); printf ("%sresp-extn ..%s: %s%s%s%s (", crit? "crit. ":"", crit?"":"......", s?"(":"", s?s:"", s?") ":"", oid); print_hex (der, derlen); putchar (')'); putchar ('\n'); } if (err && gpg_err_code (err) != GPG_ERR_EOF) fail_if_err (err); for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, cert, idx, &oid, &crit, &der, &derlen)); idx++) { const char *s = get_oid_desc (oid); printf ("%ssngl-extn ..%s: %s%s%s%s (", crit? "crit. ":"", crit?"":"......", s?"(":"", s?s:"", s?") ":"", oid); print_hex (der, derlen); putchar (')'); putchar ('\n'); } if (err && gpg_err_code (err) != GPG_ERR_EOF) fail_if_err (err); } } ksba_cert_release (cert); ksba_ocsp_release (ocsp); xfree (response); }