Initial OCSP server support, using index.txt format.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 12 Jul 2001 20:41:51 +0000 (20:41 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 12 Jul 2001 20:41:51 +0000 (20:41 +0000)
This can process internal requests or behave like a
mini responder.

Todo: documentation, update usage info.

CHANGES
apps/apps.h
apps/ca.c
apps/ocsp.c

diff --git a/CHANGES b/CHANGES
index c5dffa6280a7cf32b258f5aaaf76b4dbaef93882..b1929cace8fb341b664a70f03d9d6bd4115ed168 100644 (file)
--- a/CHANGES
+++ b/CHANGES
          *) applies to 0.9.6a/0.9.6b and 0.9.7
          +) applies to 0.9.7 only
 
+  +) Add initial OCSP responder support to ocsp application. The
+     revocation information is handled using the text based index
+     use by the ca application. The responder can either handle
+     requests generated internally, supplied in files (for example
+     via a CGI script) or using an internal minimal server.
+     [Steve Henson]
+
   +) Add configuration choices to get zlib compression for TLS.
      [Richard Levitte]
 
index ae2f7f083337d437a4ae714cb8e530ae19da0e01..de136f453bd9aa2d89107590f7a02a9160000d49 100644 (file)
@@ -68,6 +68,7 @@
 #include <openssl/lhash.h>
 #include <openssl/conf.h>
 #include <openssl/engine.h>
+#include <openssl/txt_db.h>
 
 int app_RAND_load_file(const char *file, BIO *bio_e, int dont_warn);
 int app_RAND_write_file(const char *file, BIO *bio_e);
@@ -187,6 +188,11 @@ STACK_OF(X509) *load_certs(BIO *err, const char *file, int format,
 X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath);
 ENGINE *setup_engine(BIO *err, const char *engine, int debug);
 
+/* Functions defined in ca.c and also used in ocsp.c */
+int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold,
+                       ASN1_GENERALIZEDTIME **pinvtm, char *str);
+int make_serial_index(TXT_DB *db);
+
 #define FORMAT_UNDEF    0
 #define FORMAT_ASN1     1
 #define FORMAT_TEXT     2
index e0a9ef9eae26da0d9ad992720d589fc970d12cf2..7bee4b625bdd7fd5b7b55ac2a33d2beb15829c6c 100644 (file)
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -658,15 +658,8 @@ bad:
                db=TXT_DB_read(in,DB_NUMBER);
                if (db == NULL) goto err;
 
-               if (!TXT_DB_create_index(db, DB_serial, NULL,
-                                       LHASH_HASH_FN(index_serial_hash),
-                                       LHASH_COMP_FN(index_serial_cmp)))
-                       {
-                       BIO_printf(bio_err,
-                         "error creating serial number index:(%ld,%ld,%ld)\n",
-                                               db->error,db->arg1,db->arg2);
+               if (!make_serial_index(db))
                        goto err;
-                       }
 
                if (get_certificate_status(ser_status,db) != 1)
                        BIO_printf(bio_err,"Error verifying serial %s!\n",
@@ -891,13 +884,8 @@ bad:
                BIO_printf(bio_err,"generating index\n");
                }
        
-       if (!TXT_DB_create_index(db, DB_serial, NULL,
-                       LHASH_HASH_FN(index_serial_hash),
-                       LHASH_COMP_FN(index_serial_cmp)))
-               {
-               BIO_printf(bio_err,"error creating serial number index:(%ld,%ld,%ld)\n",db->error,db->arg1,db->arg2);
+       if (!make_serial_index(db))
                goto err;
-               }
 
        if (!TXT_DB_create_index(db, DB_name, index_name_qual,
                        LHASH_HASH_FN(index_name_hash),
@@ -2889,92 +2877,21 @@ char *make_revocation_str(int rev_type, char *rev_arg)
  * 2 OK and some extensions added (i.e. V2 CRL)
  */
 
+
 int make_revoked(X509_REVOKED *rev, char *str)
        {
        char *tmp = NULL;
-       char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p;
        int reason_code = -1;
        int i, ret = 0;
        ASN1_OBJECT *hold = NULL;
        ASN1_GENERALIZEDTIME *comp_time = NULL;
        ASN1_ENUMERATED *rtmp = NULL;
-       tmp = BUF_strdup(str);
 
-       p = strchr(tmp, ',');
-
-       rtime_str = tmp;
 
-       if (p)
-               {
-               *p = '\0';
-               p++;
-               reason_str = p;
-               p = strchr(p, ',');
-               if (p)
-                       {
-                       *p = '\0';
-                       arg_str = p + 1;
-                       }
-               }
+       i = unpack_revinfo(&rev->revocationDate, &reason_code, &hold, &comp_time, str);
 
-       if (rev && !ASN1_UTCTIME_set_string(rev->revocationDate, rtime_str))
-               {
-               BIO_printf(bio_err, "invalid revocation date %s\n", rtime_str);
+       if (i == 0)
                goto err;
-               }
-       if (reason_str)
-               {
-               for (i = 0; i < NUM_REASONS; i++)
-                       {
-                       if(!strcasecmp(reason_str, crl_reasons[i]))
-                               {
-                               reason_code = i;
-                               break;
-                               }
-                       }
-               if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS)
-                       {
-                       BIO_printf(bio_err, "invalid reason code %s\n", reason_str);
-                       goto err;
-                       }
-
-               if (reason_code == 7)
-                       reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL;
-               else if (reason_code == 8)              /* Hold instruction */
-                       {
-                       if (!arg_str)
-                               {       
-                               BIO_printf(bio_err, "missing hold instruction\n");
-                               goto err;
-                               }
-                       reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD;
-                       hold = OBJ_txt2obj(arg_str, 0);
-
-                       if (!hold)
-                               {
-                               BIO_printf(bio_err, "invalid object identifier %s\n", arg_str);
-                               goto err;
-                               }
-                       }
-               else if ((reason_code == 9) || (reason_code == 10))
-                       {
-                       if (!arg_str)
-                               {       
-                               BIO_printf(bio_err, "missing compromised time\n");
-                               goto err;
-                               }
-                       comp_time = ASN1_GENERALIZEDTIME_new();
-                       if (!ASN1_GENERALIZEDTIME_set_string(comp_time, arg_str))
-                               {       
-                               BIO_printf(bio_err, "invalid compromised time %s\n", arg_str);
-                               goto err;
-                               }
-                       if (reason_code == 9)
-                               reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
-                       else
-                               reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE;
-                       }
-               }
 
        if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS))
                {
@@ -3108,3 +3025,121 @@ int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)
        BIO_printf(bp,"'\n");
        return 1;
        }
+
+int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_GENERALIZEDTIME **pinvtm, char *str)
+       {
+       char *tmp = NULL;
+       char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p;
+       int reason_code = -1;
+       int i, ret = 0;
+       ASN1_OBJECT *hold = NULL;
+       ASN1_GENERALIZEDTIME *comp_time = NULL;
+       tmp = BUF_strdup(str);
+
+       p = strchr(tmp, ',');
+
+       rtime_str = tmp;
+
+       if (p)
+               {
+               *p = '\0';
+               p++;
+               reason_str = p;
+               p = strchr(p, ',');
+               if (p)
+                       {
+                       *p = '\0';
+                       arg_str = p + 1;
+                       }
+               }
+
+       if (prevtm)
+               {
+               *prevtm = ASN1_UTCTIME_new();
+               if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str))
+                       {
+                       BIO_printf(bio_err, "invalid revocation date %s\n", rtime_str);
+                       goto err;
+                       }
+               }
+       if (reason_str)
+               {
+               for (i = 0; i < NUM_REASONS; i++)
+                       {
+                       if(!strcasecmp(reason_str, crl_reasons[i]))
+                               {
+                               reason_code = i;
+                               break;
+                               }
+                       }
+               if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS)
+                       {
+                       BIO_printf(bio_err, "invalid reason code %s\n", reason_str);
+                       goto err;
+                       }
+
+               if (reason_code == 7)
+                       reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL;
+               else if (reason_code == 8)              /* Hold instruction */
+                       {
+                       if (!arg_str)
+                               {       
+                               BIO_printf(bio_err, "missing hold instruction\n");
+                               goto err;
+                               }
+                       reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD;
+                       hold = OBJ_txt2obj(arg_str, 0);
+
+                       if (!hold)
+                               {
+                               BIO_printf(bio_err, "invalid object identifier %s\n", arg_str);
+                               goto err;
+                               }
+                       if (phold) *phold = hold;
+                       }
+               else if ((reason_code == 9) || (reason_code == 10))
+                       {
+                       if (!arg_str)
+                               {       
+                               BIO_printf(bio_err, "missing compromised time\n");
+                               goto err;
+                               }
+                       comp_time = ASN1_GENERALIZEDTIME_new();
+                       if (!ASN1_GENERALIZEDTIME_set_string(comp_time, arg_str))
+                               {       
+                               BIO_printf(bio_err, "invalid compromised time %s\n", arg_str);
+                               goto err;
+                               }
+                       if (reason_code == 9)
+                               reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
+                       else
+                               reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE;
+                       }
+               }
+
+       if (preason) *preason = reason_code;
+       if (pinvtm) *pinvtm = comp_time;
+       else ASN1_GENERALIZEDTIME_free(comp_time);
+
+       err:
+
+       if (tmp) OPENSSL_free(tmp);
+       if (!phold) ASN1_OBJECT_free(hold);
+       if (!pinvtm) ASN1_GENERALIZEDTIME_free(comp_time);
+
+       return ret;
+       }
+
+int make_serial_index(TXT_DB *db)
+       {
+       if (!TXT_DB_create_index(db, DB_serial, NULL,
+                               LHASH_HASH_FN(index_serial_hash),
+                               LHASH_COMP_FN(index_serial_cmp)))
+               {
+               BIO_printf(bio_err,
+                 "error creating serial number index:(%ld,%ld,%ld)\n",
+                                       db->error,db->arg1,db->arg2);
+                       return 0;
+               }
+       return 1;
+       }
index 16207a62837cbe1edf2f9822c80a37dda25828e8..e11e7b1f9a6f914bb3ba59e843864c38227303ff 100644 (file)
 /* Maximum leeway in validity period: default 5 minutes */
 #define MAX_VALIDITY_PERIOD    (5 * 60)
 
+/* CA index.txt definitions */
+#define DB_type         0
+#define DB_exp_date     1
+#define DB_rev_date     2
+#define DB_serial       3       /* index - unique */
+#define DB_file         4       
+#define DB_name         5       /* index - unique for active */
+#define DB_NUMBER       6
+
+#define DB_TYPE_REV    'R'
+#define DB_TYPE_EXP    'E'
+#define DB_TYPE_VAL    'V'
+
 static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
                                STACK_OF(OCSP_CERTID) *ids);
 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer,
@@ -75,6 +88,15 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
                                STACK *names, STACK_OF(OCSP_CERTID) *ids,
                                long nsec, long maxage);
 
+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);
+
+static char **lookup_serial(TXT_DB *db, ASN1_INTEGER *ser);
+static OCSP_REQUEST *do_responder(BIO **cbio, char *port);
+static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
+
 #undef PROG
 #define PROG ocsp_main
 
@@ -88,14 +110,15 @@ int MAIN(int argc, char **argv)
        char *reqin = NULL, *respin = NULL;
        char *reqout = NULL, *respout = NULL;
        char *signfile = NULL, *keyfile = NULL;
+       char *rsignfile = NULL, *rkeyfile = NULL;
        char *outfile = NULL;
        int add_nonce = 1, noverify = 0, use_ssl = -1;
        OCSP_REQUEST *req = NULL;
        OCSP_RESPONSE *resp = NULL;
        OCSP_BASICRESP *bs = NULL;
        X509 *issuer = NULL, *cert = NULL;
-       X509 *signer = NULL;
-       EVP_PKEY *key = NULL;
+       X509 *signer = NULL, *rsigner = NULL;
+       EVP_PKEY *key = NULL, *rkey = NULL;
        BIO *cbio = NULL, *derbio = NULL;
        BIO *out = NULL;
        int req_text = 0, resp_text = 0;
@@ -103,14 +126,21 @@ int MAIN(int argc, char **argv)
        char *CAfile = NULL, *CApath = NULL;
        X509_STORE *store = NULL;
        SSL_CTX *ctx = NULL;
-       STACK_OF(X509) *sign_other = NULL, *verify_other = NULL;
-       char *sign_certfile = NULL, *verify_certfile = NULL;
-       unsigned long sign_flags = 0, verify_flags = 0;
+       STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
+       char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
+       unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
        int ret = 1;
        int badarg = 0;
        int i;
        STACK *reqnames = NULL;
        STACK_OF(OCSP_CERTID) *ids = NULL;
+
+       X509 *rca_cert = NULL;
+       char *ridx_filename = NULL;
+       char *rca_filename = NULL;
+       TXT_DB *rdb = NULL;
+       int nmin = 0, ndays = -1;
+
        if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
        SSL_load_error_strings();
        args = argv + 1;
@@ -149,12 +179,27 @@ int MAIN(int argc, char **argv)
                                }
                        else badarg = 1;
                        }
+               else if (!strcmp(*args, "-port"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               port = *args;
+                               }
+                       else badarg = 1;
+                       }
                else if (!strcmp(*args, "-noverify"))
                        noverify = 1;
                else if (!strcmp(*args, "-nonce"))
                        add_nonce = 2;
                else if (!strcmp(*args, "-no_nonce"))
                        add_nonce = 0;
+               else if (!strcmp(*args, "-responder_no_certs"))
+                       rflags |= OCSP_NOCERTS;
+               else if (!strcmp(*args, "-responder_no_time"))
+                       rflags |= OCSP_NOTIME;
+               else if (!strcmp(*args, "-responder_key_id"))
+                       rflags |= OCSP_RESPID_KEY;
                else if (!strcmp(*args, "-no_certs"))
                        sign_flags |= OCSP_NOCERTS;
                else if (!strcmp(*args, "-no_signature_verify"))
@@ -361,12 +406,91 @@ int MAIN(int argc, char **argv)
                                }
                        else badarg = 1;
                        }
+               else if (!strcmp(*args, "-index"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               ridx_filename = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp(*args, "-CA"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               rca_filename = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp (*args, "-nmin"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               nmin = atol(*args);
+                               if (nmin < 0)
+                                       {
+                                       BIO_printf(bio_err,
+                                               "Illegal update period %s\n",
+                                               *args);
+                                       badarg = 1;
+                                       }
+                               }
+                               if (ndays == -1)
+                                       ndays = 0;
+                       else badarg = 1;
+                       }
+               else if (!strcmp (*args, "-ndays"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               ndays = atol(*args);
+                               if (ndays < 0)
+                                       {
+                                       BIO_printf(bio_err,
+                                               "Illegal update period %s\n",
+                                               *args);
+                                       badarg = 1;
+                                       }
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp(*args, "-rsigner"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               rsignfile = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp(*args, "-rkey"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               rkeyfile = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp(*args, "-rother"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               rcertfile = *args;
+                               }
+                       else badarg = 1;
+                       }
                else badarg = 1;
                args++;
                }
 
        /* Have we anything to do? */
-       if (!req && !reqin && !respin) badarg = 1;
+       if (!req && !reqin && !respin && !(port && ridx_filename)) badarg = 1;
 
        if (badarg)
                {
@@ -437,7 +561,20 @@ int MAIN(int argc, char **argv)
                        }
                }
 
-       if (!req && (signfile || reqout || host || add_nonce))
+       if (!req && port)
+               {
+               req = do_responder(&cbio, port);
+               if (!req && !cbio)
+                       goto end;
+               if (!req && cbio)
+                       {
+                       resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
+                       send_ocsp_response(cbio, resp);
+                       goto done_resp;
+                       }
+               }
+
+       if (!req && (signfile || reqout || host || add_nonce || ridx_filename))
                {
                BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
                goto end;
@@ -464,12 +601,7 @@ int MAIN(int argc, char **argv)
                key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL,
                        "signer private key");
                if (!key)
-                       {
-#if 0                  /* An appropriate message has already been printed */
-                       BIO_printf(bio_err, "Error loading signer private key\n");
-#endif
                        goto end;
-                       }
                if (!OCSP_request_sign(req, signer, key, EVP_sha1(), sign_other, sign_flags))
                        {
                        BIO_printf(bio_err, "Error signing OCSP request\n");
@@ -477,21 +609,61 @@ int MAIN(int argc, char **argv)
                        }
                }
 
-       if (reqout)
+       if (req_text && req) OCSP_REQUEST_print(out, req, 0);
+
+       if (rsignfile)
                {
-               derbio = BIO_new_file(reqout, "wb");
-               if (!derbio)
+               if (!rkeyfile) rkeyfile = rsignfile;
+               rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM,
+                       NULL, e, "responder certificate");
+               if (!rsigner)
                        {
-                       BIO_printf(bio_err, "Error opening file %s\n", reqout);
+                       BIO_printf(bio_err, "Error loading responder certificate\n");
                        goto end;
                        }
-               i2d_OCSP_REQUEST_bio(derbio, req);
-               BIO_free(derbio);
+               rca_cert = load_cert(bio_err, rca_filename, FORMAT_PEM,
+                       NULL, e, "CA certificate");
+               if (rcertfile)
+                       {
+                       rother = load_certs(bio_err, sign_certfile, FORMAT_PEM,
+                               NULL, e, "responder other certificates");
+                       if (!sign_other) goto end;
+                       }
+               rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, NULL, NULL,
+                       "responder private key");
+               if (!rkey)
+                       goto end;
                }
 
-       if (req_text && req) OCSP_REQUEST_print(out, req, 0);
+       if (ridx_filename && (!rkey || !rsigner || !rca_cert))
+               {
+               BIO_printf(bio_err, "Need a responder certificate, key and CA for this operation!\n");
+               goto end;
+               }
 
-       if (host)
+       if (ridx_filename)
+               {
+               BIO *db_bio = NULL;
+               db_bio = BIO_new_file(ridx_filename, "r");
+               if (!db_bio)
+                       {
+                       BIO_printf(bio_err, "Error opening index file %s\n", ridx_filename);
+                       goto end;
+                       }
+               rdb = TXT_DB_read(db_bio, DB_NUMBER);
+               BIO_free(db_bio);
+               if (!rdb)
+                       {
+                       BIO_printf(bio_err, "Error reading index file %s\n", ridx_filename);
+                       goto end;
+                       }
+               if (!make_serial_index(rdb))
+                       goto end;
+               i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, rother, rflags, nmin, ndays);
+               if (cbio)
+                       send_ocsp_response(cbio, resp);
+               }
+       else if (host)
                {
                cbio = BIO_new_connect(host);
                if (!cbio)
@@ -545,6 +717,8 @@ int MAIN(int argc, char **argv)
                goto end;
                }
 
+       done_resp:
+
        if (respout)
                {
                derbio = BIO_new_file(respout, "wb");
@@ -569,6 +743,10 @@ int MAIN(int argc, char **argv)
 
        if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
 
+       /* If running as responder don't verify our own response */
+       if (cbio)
+               goto end;
+
        store = setup_verify(bio_err, CAfile, CApath);
        if(!store) goto end;
        if (verify_certfile)
@@ -622,8 +800,12 @@ end:
        X509_free(signer);
        X509_STORE_free(store);
        EVP_PKEY_free(key);
+       EVP_PKEY_free(rkey);
        X509_free(issuer);
        X509_free(cert);
+       X509_free(rsigner);
+       X509_free(rca_cert);
+       TXT_DB_free(rdb);
        BIO_free_all(cbio);
        BIO_free(out);
        OCSP_REQUEST_free(req);
@@ -763,3 +945,205 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
        return 1;
        }
 
+
+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);
+       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 OCSP_REQUEST *do_responder(BIO **pcbio, char *port)
+       {
+       int have_post = 0, len;
+       OCSP_REQUEST *req = NULL;
+       char inbuf[1024];
+       BIO *acbio = NULL, *bufbio = NULL, *cbio = 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;
+               }
+
+       BIO_printf(bio_err, "Waiting for OCSP client connection...\n");
+
+       if (BIO_do_accept(acbio) <= 0)
+               {
+                       BIO_printf(bio_err, "Error accepting connection\n");
+                       ERR_print_errors(bio_err);
+                       goto err;
+               }
+
+       BIO_printf(bio_err, "Connection Established\n");
+
+
+       cbio = BIO_pop(acbio);
+       BIO_free_all(acbio);
+       acbio = NULL;
+
+       for(;;)
+               {
+               len = BIO_gets(cbio, inbuf, 1024);
+               if (len <= 0) goto err;
+               /* Look for "POST" signalling start of query */
+               if (!have_post)
+                       {
+                       if(strncmp(inbuf, "POST", 4))
+                               {
+                               BIO_printf(bio_err, "Invalid request\n");
+                               goto err;
+                               }
+                       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);
+
+       *pcbio = cbio;
+
+       if (!req)
+               {
+               BIO_printf(bio_err, "Error parsing OCSP request\n");
+               ERR_print_errors(bio_err);
+               }
+
+       return req;
+
+       err:
+       BIO_free_all(acbio);
+       BIO_free_all(cbio);
+       BIO_free(bufbio);
+       OCSP_REQUEST_free(req);
+       return NULL;
+       }
+
+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;
+       }
+