+
+static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, TXT_DB *db,
+ X509 *ca, X509 *rcert, EVP_PKEY *rkey,
+ STACK_OF(X509) *rother, unsigned long flags,
+ int nmin, int ndays)
+ {
+ ASN1_TIME *thisupd = NULL, *nextupd = NULL;
+ OCSP_CERTID *cid, *ca_id = NULL;
+ OCSP_BASICRESP *bs = NULL;
+ int i, id_count, ret = 1;
+
+
+ id_count = OCSP_request_onereq_count(req);
+
+ if (id_count <= 0)
+ {
+ *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
+ goto end;
+ }
+
+ ca_id = OCSP_cert_to_id(EVP_sha1(), NULL, ca);
+
+ bs = OCSP_BASICRESP_new();
+ thisupd = X509_gmtime_adj(NULL, 0);
+ if (ndays != -1)
+ nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24 );
+
+ /* Examine each certificate id in the request */
+ for (i = 0; i < id_count; i++)
+ {
+ OCSP_ONEREQ *one;
+ ASN1_INTEGER *serial;
+ char **inf;
+ one = OCSP_request_onereq_get0(req, i);
+ cid = OCSP_onereq_get0_id(one);
+ /* Is this request about our CA? */
+ if (OCSP_id_issuer_cmp(ca_id, cid))
+ {
+ OCSP_basic_add1_status(bs, cid,
+ V_OCSP_CERTSTATUS_UNKNOWN,
+ 0, NULL,
+ thisupd, nextupd);
+ continue;
+ }
+ OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
+ inf = lookup_serial(db, serial);
+ if (!inf)
+ OCSP_basic_add1_status(bs, cid,
+ V_OCSP_CERTSTATUS_UNKNOWN,
+ 0, NULL,
+ thisupd, nextupd);
+ else if (inf[DB_type][0] == DB_TYPE_VAL)
+ OCSP_basic_add1_status(bs, cid,
+ V_OCSP_CERTSTATUS_GOOD,
+ 0, NULL,
+ thisupd, nextupd);
+ else if (inf[DB_type][0] == DB_TYPE_REV)
+ {
+ ASN1_OBJECT *inst = NULL;
+ ASN1_TIME *revtm = NULL;
+ ASN1_GENERALIZEDTIME *invtm = NULL;
+ OCSP_SINGLERESP *single;
+ int reason = -1;
+ unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]);
+ single = OCSP_basic_add1_status(bs, cid,
+ V_OCSP_CERTSTATUS_REVOKED,
+ reason, revtm,
+ thisupd, nextupd);
+ if (invtm)
+ OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, invtm, 0, 0);
+ else if (inst)
+ OCSP_SINGLERESP_add1_ext_i2d(single, NID_hold_instruction_code, inst, 0, 0);
+ ASN1_OBJECT_free(inst);
+ ASN1_TIME_free(revtm);
+ ASN1_GENERALIZEDTIME_free(invtm);
+ }
+ }
+
+ OCSP_copy_nonce(bs, req);
+
+ OCSP_basic_sign(bs, rcert, rkey, EVP_sha1(), rother, flags);
+
+ *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
+
+ end:
+ ASN1_TIME_free(thisupd);
+ ASN1_TIME_free(nextupd);
+ OCSP_CERTID_free(ca_id);
+ OCSP_BASICRESP_free(bs);
+ return ret;
+
+ }
+
+static char **lookup_serial(TXT_DB *db, ASN1_INTEGER *ser)
+ {
+ int i;
+ BIGNUM *bn = NULL;
+ char *itmp, *row[DB_NUMBER],**rrow;
+ for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
+ bn = ASN1_INTEGER_to_BN(ser,NULL);
+ if (BN_is_zero(bn))
+ itmp = BUF_strdup("00");
+ else
+ itmp = BN_bn2hex(bn);
+ row[DB_serial] = itmp;
+ BN_free(bn);
+ rrow=TXT_DB_get_by_index(db,DB_serial,row);
+ OPENSSL_free(itmp);
+ return rrow;
+ }
+
+/* Quick and dirty OCSP server: read in and parse input request */
+
+static BIO *init_responder(char *port)
+ {
+ BIO *acbio = NULL, *bufbio = NULL;
+ bufbio = BIO_new(BIO_f_buffer());
+ if (!bufbio)
+ goto err;
+ acbio = BIO_new_accept(port);
+ if (!acbio)
+ goto err;
+ BIO_set_accept_bios(acbio, bufbio);
+ bufbio = NULL;
+
+ if (BIO_do_accept(acbio) <= 0)
+ {
+ BIO_printf(bio_err, "Error setting up accept BIO\n");
+ ERR_print_errors(bio_err);
+ goto err;
+ }
+
+ return acbio;
+
+ err:
+ BIO_free_all(acbio);
+ BIO_free(bufbio);
+ return NULL;
+ }
+
+static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port)
+ {
+ int have_post = 0, len;
+ OCSP_REQUEST *req = NULL;
+ char inbuf[1024];
+ BIO *cbio = NULL;
+
+ if (BIO_do_accept(acbio) <= 0)
+ {
+ BIO_printf(bio_err, "Error accepting connection\n");
+ ERR_print_errors(bio_err);
+ return 0;
+ }
+
+ cbio = BIO_pop(acbio);
+ *pcbio = cbio;
+
+ for(;;)
+ {
+ len = BIO_gets(cbio, inbuf, sizeof inbuf);
+ if (len <= 0)
+ return 1;
+ /* Look for "POST" signalling start of query */
+ if (!have_post)
+ {
+ if(strncmp(inbuf, "POST", 4))
+ {
+ BIO_printf(bio_err, "Invalid request\n");
+ return 1;
+ }
+ have_post = 1;
+ }
+ /* Look for end of headers */
+ if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
+ break;
+ }
+
+ /* Try to read OCSP request */
+
+ req = d2i_OCSP_REQUEST_bio(cbio, NULL);
+
+ if (!req)
+ {
+ BIO_printf(bio_err, "Error parsing OCSP request\n");
+ ERR_print_errors(bio_err);
+ }
+
+ *preq = req;
+
+ return 1;
+
+ }
+
+static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
+ {
+ char http_resp[] =
+ "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
+ "Content-Length: %d\r\n\r\n";
+ if (!cbio)
+ return 0;
+ BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
+ i2d_OCSP_RESPONSE_bio(cbio, resp);
+ BIO_flush(cbio);
+ return 1;
+ }
+