Initial OCSP server support, using index.txt format.
This can process internal requests or behave like a mini responder. Todo: documentation, update usage info.
This commit is contained in:
parent
45442167b0
commit
ee306a1332
7
CHANGES
7
CHANGES
@ -12,6 +12,13 @@
|
||||
*) 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]
|
||||
|
||||
|
@ -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
|
||||
|
211
apps/ca.c
211
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;
|
||||
i = unpack_revinfo(&rev->revocationDate, &reason_code, &hold, &comp_time, str);
|
||||
|
||||
if (p)
|
||||
{
|
||||
*p = '\0';
|
||||
p++;
|
||||
reason_str = p;
|
||||
p = strchr(p, ',');
|
||||
if (p)
|
||||
{
|
||||
*p = '\0';
|
||||
arg_str = p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
434
apps/ocsp.c
434
apps/ocsp.c
@ -67,6 +67,19 @@
|
||||
/* 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)
|
||||
{
|
||||
derbio = BIO_new_file(reqout, "wb");
|
||||
if (!derbio)
|
||||
{
|
||||
BIO_printf(bio_err, "Error opening file %s\n", reqout);
|
||||
goto end;
|
||||
}
|
||||
i2d_OCSP_REQUEST_bio(derbio, req);
|
||||
BIO_free(derbio);
|
||||
}
|
||||
|
||||
if (req_text && req) OCSP_REQUEST_print(out, req, 0);
|
||||
|
||||
if (host)
|
||||
if (rsignfile)
|
||||
{
|
||||
if (!rkeyfile) rkeyfile = rsignfile;
|
||||
rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM,
|
||||
NULL, e, "responder certificate");
|
||||
if (!rsigner)
|
||||
{
|
||||
BIO_printf(bio_err, "Error loading responder certificate\n");
|
||||
goto end;
|
||||
}
|
||||
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 (ridx_filename && (!rkey || !rsigner || !rca_cert))
|
||||
{
|
||||
BIO_printf(bio_err, "Need a responder certificate, key and CA for this operation!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user