/* Create a request for the DER encoded certificate in the file CERT_FNAME and its issuer's certificate in the file ISSUER_CERT_FNAME. */ void one_request (const char *cert_fname, const char *issuer_cert_fname) { gpg_error_t err; ksba_cert_t cert = get_one_cert (cert_fname); ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname); ksba_ocsp_t ocsp; unsigned char *request; size_t requestlen; err = ksba_ocsp_new (&ocsp); fail_if_err (err); err = ksba_ocsp_add_target (ocsp, cert, issuer_cert); fail_if_err (err); ksba_cert_release (cert); 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); ksba_ocsp_release (ocsp); printf ("OCSP request of length %u created\n", (unsigned int)requestlen); { FILE *fp = fopen ("a.req", "wb"); if (!fp) fail ("can't create output file `a.req'"); if (fwrite (request, requestlen, 1, fp) != 1) fail ("can't write output"); fclose (fp); } xfree (request); }
/* Construct an OCSP request, send it to the configured OCSP responder and parse the response. On success the OCSP context may be used to further process the reponse. */ static gpg_error_t do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert) { gpg_error_t err; unsigned char *request, *response; size_t requestlen, responselen; http_t http; ksba_ocsp_response_status_t response_status; const char *t; int redirects_left = 2; char *free_this = NULL; (void)ctrl; if (opt.disable_http) { log_error (_("OCSP request not possible due to disabled HTTP\n")); return gpg_error (GPG_ERR_NOT_SUPPORTED); } err = ksba_ocsp_add_target (ocsp, cert, issuer_cert); if (err) { log_error (_("error setting OCSP target: %s\n"), gpg_strerror (err)); return err; } { size_t n; unsigned char nonce[32]; n = ksba_ocsp_set_nonce (ocsp, NULL, 0); if (n > sizeof nonce) n = sizeof nonce; gcry_create_nonce (nonce, n); ksba_ocsp_set_nonce (ocsp, nonce, n); } err = ksba_ocsp_build_request (ocsp, &request, &requestlen); if (err) { log_error (_("error building OCSP request: %s\n"), gpg_strerror (err)); return err; } once_more: err = http_open (&http, HTTP_REQ_POST, url, NULL, (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0), opt.http_proxy, NULL, NULL, NULL); if (err) { log_error (_("error connecting to '%s': %s\n"), url, gpg_strerror (err)); xfree (free_this); return err; } es_fprintf (http_get_write_ptr (http), "Content-Type: application/ocsp-request\r\n" "Content-Length: %lu\r\n", (unsigned long)requestlen ); http_start_data (http); if (es_fwrite (request, requestlen, 1, http_get_write_ptr (http)) != 1) { err = gpg_error_from_errno (errno); log_error ("error sending request to '%s': %s\n", url, strerror (errno)); http_close (http, 0); xfree (request); xfree (free_this); return err; } xfree (request); request = NULL; err = http_wait_response (http); if (err || http_get_status_code (http) != 200) { if (err) log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); else { switch (http_get_status_code (http)) { case 301: case 302: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), url, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (free_this); url = NULL; free_this = xtrystrdup (s); if (!free_this) err = gpg_error_from_errno (errno); else { url = free_this; http_close (http, 0); goto once_more; } } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } break; default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); break; } } http_close (http, 0); xfree (free_this); return err; } err = read_response (http_get_read_ptr (http), &response, &responselen); http_close (http, 0); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); xfree (free_this); return err; } err = ksba_ocsp_parse_response (ocsp, response, responselen, &response_status); if (err) { log_error (_("error parsing OCSP response for '%s': %s\n"), url, gpg_strerror (err)); xfree (response); xfree (free_this); return 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: t = "[unknown status]"; break; } if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS) { if (opt.verbose) log_info (_("OCSP responder at '%s' status: %s\n"), url, t); err = ksba_ocsp_hash_response (ocsp, response, responselen, HASH_FNC, md); if (err) log_error (_("hashing the OCSP response for '%s' failed: %s\n"), url, gpg_strerror (err)); } else { log_error (_("OCSP responder at '%s' status: %s\n"), url, t); err = gpg_error (GPG_ERR_GENERAL); } xfree (response); xfree (free_this); return err; }
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); }