This patch provides OCSP request handler using non blocking BIOs. The new added library routine is
OCSP_RESPONSE * OCSP_sendreq_bio_with_timeout(BIO *b, char *path, OCSP_REQUEST *req, long timeout)
*BIO *b* is a non blocking bio. The number of seconds you wish to use for timeout can be passed using *long timeout*.
It also provides *-timeout* option for OCSP client utilility.
It is against openssl-0.9.7d and it is tested on Solaris using gcc and on Windows using VC++.
Thanks, Amar Desai
diff -ur ./openssl-0.9.7d-orig/apps/ocsp.c ./openssl-0.9.7d/apps/ocsp.c
--- ./openssl-0.9.7d-orig/apps/ocsp.c 2004-04-19 18:18:47.390001000 -0100
+++ ./openssl-0.9.7d/apps/ocsp.c 2004-04-20 10:57:26.470003000 -0100
@@ -112,7 +112,7 @@
BIO *derbio = NULL;
BIO *out = NULL;
int req_text = 0, resp_text = 0;
- long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
+ long nsec = MAX_VALIDITY_PERIOD, maxage = -1, timeout = 90;
char *CAfile = NULL, *CApath = NULL;
X509_STORE *store = NULL;
SSL_CTX *ctx = NULL;
@@ -325,6 +325,22 @@
}
else badarg = 1;
}
+ else if (!strcmp (*args, "-timeout"))
+ {
+ if (args[1])
+ {
+ args++;
+ timeout = atol(*args);
+ if (timeout < 0)
+ {
+ BIO_printf(bio_err,
+ "Illegal timeout %s\n",
+ *args);
+ badarg = 1;
+ }
+ }
+ else badarg = 1;
+ }
else if (!strcmp(*args, "-signkey"))
{
if (args[1])
@@ -533,6 +549,7 @@
BIO_printf (bio_err, "-VAfile file validator certificates
file\n");
BIO_printf (bio_err, "-validity_period n maximum validity discrepancy
in seconds\n");
BIO_printf (bio_err, "-status_age n maximum status age in
seconds\n");
+ BIO_printf (bio_err, "-timeout n timeout in seconds for ocsp
client \n");
BIO_printf (bio_err, "-noverify don't verify response at
all\n");
BIO_printf (bio_err, "-verify_other file additional certificates to
search for signer\n");
BIO_printf (bio_err, "-trust_other don't verify additional
certificates\n");
@@ -712,6 +729,7 @@
goto end;
}
if (port) BIO_set_conn_port(cbio, port);
+ BIO_set_nbio(cbio,1);
if (use_ssl == 1)
{
BIO *sbio;
@@ -731,10 +749,11 @@
}
if (BIO_do_connect(cbio) <= 0)
{
- BIO_printf(bio_err, "Error connecting BIO\n");
- goto end;
+ /*BIO_printf(bio_err, "Error connecting BIO\n");
+ goto end;*/
+ resp = OCSP_sendreq_bio_with_timeout(cbio,
path,req,timeout);
}
- resp = OCSP_sendreq_bio(cbio, path, req);
+
BIO_free_all(cbio);
cbio = NULL;
if (!resp)
@@ -873,7 +892,7 @@
X509_free(cert);
X509_free(rsigner);
X509_free(rca_cert);
- free_index(rdb);
+ if(rdb != NULL) free_index(rdb);
BIO_free_all(cbio);
BIO_free_all(acbio);
BIO_free(out);
diff -ur ./openssl-0.9.7d-orig/crypto/ocsp/ocsp.h ./openssl-0.9.7d/crypto/ocsp/ocsp.h
--- ./openssl-0.9.7d-orig/crypto/ocsp/ocsp.h 2004-04-19 18:19:04.840002000 -0100
+++ ./openssl-0.9.7d/crypto/ocsp/ocsp.h 2004-04-20 10:48:10.900002000 -0100
@@ -404,6 +404,8 @@
(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
+OCSP_RESPONSE *OCSP_sendreq_bio_with_timeout(BIO *b, char *path, OCSP_REQUEST *req,
long timeout);
+
OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
@@ -579,6 +581,7 @@
#define OCSP_F_OCSP_REQUEST_VERIFY 116
#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
#define OCSP_F_OCSP_SENDREQ_BIO 112
+#define OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT 117
#define OCSP_F_REQUEST_VERIFY 113
/* Reason codes. */
@@ -612,6 +615,9 @@
#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119
#define OCSP_R_UNKNOWN_NID 120
#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129
+#define OCSP_R_SERVER_CONNECT_ERROR 130
+#define OCSP_R_SERVER_TIMEOUT_ERROR 131
+
#ifdef __cplusplus
}
diff -ur ./openssl-0.9.7d-orig/crypto/ocsp/ocsp_err.c
./openssl-0.9.7d/crypto/ocsp/ocsp_err.c
--- ./openssl-0.9.7d-orig/crypto/ocsp/ocsp_err.c 2004-04-19 18:19:04.800000000
-0100
+++ ./openssl-0.9.7d/crypto/ocsp/ocsp_err.c 2004-04-20 10:14:25.270002000 -0100
@@ -82,6 +82,7 @@
{ERR_PACK(0,OCSP_F_OCSP_REQUEST_VERIFY,0), "OCSP_request_verify"},
{ERR_PACK(0,OCSP_F_OCSP_RESPONSE_GET1_BASIC,0), "OCSP_response_get1_basic"},
{ERR_PACK(0,OCSP_F_OCSP_SENDREQ_BIO,0), "OCSP_sendreq_bio"},
+{ERR_PACK(0,OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,0),"OCSP_sendreq_bio_with_timeout"},
{ERR_PACK(0,OCSP_F_REQUEST_VERIFY,0), "REQUEST_VERIFY"},
{0,NULL}
};
@@ -110,6 +111,8 @@
{OCSP_R_SERVER_RESPONSE_ERROR ,"server response error"},
{OCSP_R_SERVER_RESPONSE_PARSE_ERROR ,"server response parse error"},
{OCSP_R_SERVER_WRITE_ERROR ,"server write error"},
+{OCSP_R_SERVER_CONNECT_ERROR ,"server connect error"},
+{OCSP_R_SERVER_TIMEOUT_ERROR ,"server timeout error"},
{OCSP_R_SIGNATURE_FAILURE ,"signature failure"},
{OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND ,"signer certificate not found"},
{OCSP_R_STATUS_EXPIRED ,"status expired"},
diff -ur ./openssl-0.9.7d-orig/crypto/ocsp/ocsp_ht.c
./openssl-0.9.7d/crypto/ocsp/ocsp_ht.c
--- ./openssl-0.9.7d-orig/crypto/ocsp/ocsp_ht.c 2004-04-19 18:19:04.859999000 -0100
+++ ./openssl-0.9.7d/crypto/ocsp/ocsp_ht.c 2004-04-20 10:49:14.990000000 -0100
@@ -61,9 +61,11 @@
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
+#include <time.h>
#include <openssl/ocsp.h>
#include <openssl/err.h>
#include <openssl/buffer.h>
+#include <openssl/bio.h>
#ifdef OPENSSL_SYS_SUNOS
#define strtoul (unsigned long)strtol
#endif /* OPENSSL_SYS_SUNOS */
@@ -171,3 +173,176 @@
BIO_free(mem);
return resp;
}
+OCSP_RESPONSE *OCSP_sendreq_bio_with_timeout(BIO *b, char *path, OCSP_REQUEST
+*req, long timeout)
+{
+ BIO *mem = NULL;
+ char tmpbuf[1024];
+ OCSP_RESPONSE *resp = NULL;
+ char *p, *q, *r,*buf=NULL;
+ int len=0, i ,retcode,offSet,socketDes;
+ fd_set rs,ws,wset,rset;
+ struct timeval tval, tmp;
+ static char req_txt[] =
+"POST %s HTTP/1.0\r\n\
+Content-Type: application/ocsp-request\r\n\
+Content-Length: %d\r\n\r\n";
+
+
+
+ if(!(mem = BIO_new(BIO_s_mem()))) goto err;
+
+ i = i2d_OCSP_REQUEST(req, NULL);
+
+ if((len = BIO_printf(mem, req_txt, path, i)) < 0) goto err;
+
+ if(i2d_OCSP_REQUEST_bio(mem, req) <= 0) goto err;
+
+ len += i;
+
+ if(!(buf = (char *)OPENSSL_malloc(len))) goto err;
+
+ len = BIO_read(mem,buf,len);
+
+ BIO_free(mem);
+
+ if(len <= 0)
+ goto err;
+
+ BIO_get_fd(b,&socketDes);
+
+ FD_ZERO(&wset);
+ FD_SET(socketDes,&wset);
+ FD_ZERO(&rset);
+
+
+ tval.tv_sec = timeout;
+ tval.tv_usec = 0;
+
+ if(!(mem = BIO_new(BIO_s_mem()))) goto err;
+
+ offSet = 0;
+ while(1)
+ {
+ FD_ZERO(&rs);
+ FD_ZERO(&ws);
+
+ rs = rset;
+ ws = wset;
+
+ tmp = tval;
+
+ if(select(socketDes+1,&rs,&ws,NULL,&tmp) == 0){
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_TIMEOUT_ERROR);
+ goto err;
+ }
+ else
+ {
+ if(FD_ISSET(socketDes,&rs) || FD_ISSET(socketDes,&ws)){
+ retcode = BIO_sock_error(socketDes);
+ if(retcode<0){
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_CONNECT_ERROR);
+ goto err;
+ }
+ }
+ if(FD_ISSET(socketDes,&rs)){
+ i = BIO_read(b, tmpbuf, sizeof tmpbuf);
+ if(i == 0) break;
+ if(i < 0) {
+ if(!BIO_should_retry(b)){
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_READ_ERROR);
+ goto err;
+ }
+
+ }
+ BIO_write(mem,tmpbuf,i);
+ }
+ if(FD_ISSET(socketDes,&ws)){
+
+ if((i = BIO_write(b,buf+offSet,len)) <= 0){
+ if(!BIO_should_retry(b)){
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_WRITE_ERROR);
+ goto err;
+ }
+
+ }
+ offSet += i;
+ len -= i;
+ if(len <= 0){
+ FD_CLR(socketDes,&wset);
+ FD_SET(socketDes,&rset);
+ }
+ }
+ }
+ }
+
+ if(BIO_gets(mem, tmpbuf, 512) <= 0) {
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Parse the HTTP response. This will look like this:
+ * "HTTP/1.0 200 OK". We need to obtain the numeric code and
+ * (optional) informational message.
+ */
+
+ /* Skip to first white space (passed protocol info) */
+ for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
+ if(!*p) {
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Skip past white space to start of response code */
+ while(*p && isspace((unsigned char)*p)) p++;
+ if(!*p) {
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Find end of response code: first whitespace after start of code */
+ for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
+ if(!*q) {
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Set end of response code and start of message */
+ *q++ = 0;
+ /* Attempt to parse numeric code */
+ retcode = strtoul(p, &r, 10);
+ if(*r) goto err;
+ /* Skip over any leading white space in message */
+ while(*q && isspace((unsigned char)*q)) q++;
+ if(*q) {
+ /* Finally zap any trailing white space in message (include CRLF) */
+ /* We know q has a non white space character so this is OK */
+ for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
+ }
+ if(retcode != 200) {
+
OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_SERVER_RESPONSE_ERROR);
+ if(!*q) {
+ ERR_add_error_data(2, "Code=", p);
+ }
+ else {
+ ERR_add_error_data(4, "Code=", p, ",Reason=", q);
+ }
+ goto err;
+ }
+ /* Find blank line marking beginning of content */
+ while(BIO_gets(mem, tmpbuf, 512) > 0)
+ {
+ for(p = tmpbuf; *p && isspace((unsigned char)*p); p++) continue;
+ if(!*p) break;
+ }
+ if(*p) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,OCSP_R_NO_CONTENT);
+ goto err;
+ }
+ if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT,ERR_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ err:
+ if(buf != NULL) OPENSSL_free(buf);
+ if(mem != NULL) BIO_free(mem);
+ return resp;
+}
+
+
diff -ur ./openssl-0.9.7d-orig/include/openssl/ocsp.h
./openssl-0.9.7d/include/openssl/ocsp.h
--- ./openssl-0.9.7d-orig/include/openssl/ocsp.h 2004-04-19 18:19:23.210001000
-0100
+++ ./openssl-0.9.7d/include/openssl/ocsp.h 2004-04-20 10:48:10.900002000 -0100
@@ -404,6 +404,8 @@
(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
+OCSP_RESPONSE *OCSP_sendreq_bio_with_timeout(BIO *b, char *path, OCSP_REQUEST *req,
long timeout);
+
OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
@@ -579,6 +581,7 @@
#define OCSP_F_OCSP_REQUEST_VERIFY 116
#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111
#define OCSP_F_OCSP_SENDREQ_BIO 112
+#define OCSP_F_OCSP_SENDREQ_BIO_WITH_TIMEOUT 117
#define OCSP_F_REQUEST_VERIFY 113
/* Reason codes. */
@@ -612,6 +615,9 @@
#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119
#define OCSP_R_UNKNOWN_NID 120
#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129
+#define OCSP_R_SERVER_CONNECT_ERROR 130
+#define OCSP_R_SERVER_TIMEOUT_ERROR 131
+
#ifdef __cplusplus
}
smime.p7s
Description: S/MIME Cryptographic Signature
