OCSP Updates

1. Add option to example server and client to check the OCSP responder.
2. Add option to example server and client to override the URL to use
   when checking the OCSP responder.
3. Copy the certificate serial number correctly into OCSP request.
   Add leading zero only if MS bit is set.
4. Fix responder address used when Auth Info extension is present.
5. Update EmbedOcspLookup callback to better handle the HTTP
   response and obtain the complete OCSP response.
This commit is contained in:
John Safranek 2013-06-20 11:07:54 -07:00
parent e0a84521c5
commit 0c34ecb451
5 changed files with 202 additions and 77 deletions

View File

@ -4847,10 +4847,20 @@ static int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
if (snSz <= EXTERNAL_SERIAL_SIZE) {
output[0] = ASN_INTEGER;
output[1] = snSz + 1;
output[2] = 0;
XMEMCPY(&output[3], sn, snSz);
result = snSz + 3;
/* The serial number is always positive. When encoding the
* INTEGER, if the MSB is 1, add a padding zero to keep the
* number positive. */
if (sn[0] & 0x80) {
output[1] = snSz + 1;
output[2] = 0;
XMEMCPY(&output[3], sn, snSz);
result = snSz + 3;
}
else {
output[1] = snSz;
XMEMCPY(&output[2], sn, snSz);
result = snSz + 2;
}
}
return result;
}

View File

@ -131,6 +131,10 @@ static void Usage(void)
printf("-z Print structure sizes\n");
#endif
printf("-S <str> Use Host Name Indication\n");
#ifdef HAVE_OCSP
printf("-o Perform OCSP lookup on peer certificate\n");
printf("-O <url> Perform OCSP lookup using <url> as responder\n");
#endif
}
#ifdef CYASSL_MDK_SHELL
@ -186,6 +190,11 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args)
char* sniHostName = NULL;
#endif
#ifdef HAVE_OCSP
int useOcsp = 0;
char* ocspUrl = NULL;
#endif
int argc = ((func_args*)args)->argc;
char** argv = ((func_args*)args)->argv;
@ -203,7 +212,8 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args)
StackTrap();
while ((ch = mygetopt(argc, argv, "?gdusmNrtfxh:p:v:l:A:c:k:b:zS:")) != -1){
while ((ch = mygetopt(argc, argv,
"?gdusmNrtfxh:p:v:l:A:c:k:b:zS:oO:")) != -1) {
switch (ch) {
case '?' :
Usage();
@ -308,6 +318,19 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args)
#endif
break;
case 'o' :
#ifdef HAVE_OCSP
useOcsp = 1;
#endif
break;
case 'O' :
#ifdef HAVE_OCSP
useOcsp = 1;
ocspUrl = myoptarg;
#endif
break;
default:
Usage();
exit(MY_EX_USAGE);
@ -429,6 +452,15 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args)
}
#endif
#ifdef HAVE_OCSP
if (useOcsp) {
CyaSSL_CTX_OCSP_set_options(ctx,
CYASSL_OCSP_ENABLE | CYASSL_OCSP_NO_NONCE);
if (ocspUrl != NULL)
CyaSSL_CTX_OCSP_set_override_url(ctx, ocspUrl);
}
#endif
#ifdef USER_CA_CB
CyaSSL_CTX_SetCACb(ctx, CaCb);
#endif

View File

@ -123,6 +123,10 @@ static void Usage(void)
printf("-f Fewer packets/group messages\n");
printf("-N Use Non-blocking sockets\n");
printf("-S <str> Use Host Name Indication\n");
#ifdef HAVE_OCSP
printf("-o Perform OCSP lookup on peer certificate\n");
printf("-O <url> Perform OCSP lookup using <url> as responder\n");
#endif
}
#ifdef CYASSL_MDK_SHELL
@ -164,6 +168,11 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
char* sniHostName = NULL;
#endif
#ifdef HAVE_OCSP
int useOcsp = 0;
char* ocspUrl = NULL;
#endif
((func_args*)args)->return_code = -1; /* error state */
#ifdef NO_RSA
@ -173,7 +182,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#endif
(void)trackMemory;
while ((ch = mygetopt(argc, argv, "?dbstnNufp:v:l:A:c:k:S:")) != -1) {
while ((ch = mygetopt(argc, argv, "?dbstnNufp:v:l:A:c:k:S:oO:")) != -1) {
switch (ch) {
case '?' :
Usage();
@ -251,6 +260,19 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
#endif
break;
case 'o' :
#ifdef HAVE_OCSP
useOcsp = 1;
#endif
break;
case 'O' :
#ifdef HAVE_OCSP
useOcsp = 1;
ocspUrl = myoptarg;
#endif
break;
default:
Usage();
exit(MY_EX_USAGE);
@ -424,6 +446,15 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
CYASSL_CRL_START_MON);
CyaSSL_SetCRL_Cb(ssl, CRL_CallBack);
#endif
#ifdef HAVE_OCSP
if (useOcsp) {
CyaSSL_CTX_OCSP_set_options(ctx,
CYASSL_OCSP_ENABLE | CYASSL_OCSP_NO_NONCE);
if (ocspUrl != NULL)
CyaSSL_CTX_OCSP_set_override_url(ctx, ocspUrl);
}
#endif
tcp_accept(&sockfd, &clientfd, (func_args*)args, port, useAnyAddr, doDTLS);
if (!doDTLS)
CloseSocket(sockfd);

192
src/io.c
View File

@ -562,69 +562,6 @@ static int build_http_request(const char* domainName, const char* path,
}
static int decode_http_response(byte* httpBuf, int httpBufSz, byte** dst)
{
int idx = 0;
int stop = 0;
int len = 0;
byte* contentType = NULL;
byte* contentLength = NULL;
char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
if (XSTRNCASECMP(buf, "HTTP/1", 6) != 0)
return 0;
idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
* HTTP result code */
if (XSTRNCASECMP(&buf[idx], "200 OK", 6) != 0)
return 0;
idx += 8;
while (idx < httpBufSz && !stop) {
if (buf[idx] == '\r' && buf[idx+1] == '\n') {
stop = 1;
idx += 2;
}
else {
if (contentType == NULL &&
XSTRNCASECMP(&buf[idx], "Content-Type:", 13) == 0) {
idx += 13;
if (buf[idx] == ' ') idx++;
if (XSTRNCASECMP(&buf[idx],
"application/ocsp-response", 25) != 0) {
return 0;
}
idx += 27;
}
else if (contentLength == NULL &&
XSTRNCASECMP(&buf[idx], "Content-Length:", 15) == 0) {
idx += 15;
if (buf[idx] == ' ') idx++;
while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
len = (len * 10) + (buf[idx] - '0');
idx++;
}
idx += 2; /* skip the crlf */
}
else {
/* Advance idx past the next \r\n */
char* end = XSTRSTR(&buf[idx], "\r\n");
idx = (int)(end - buf + 2);
}
}
}
if (len > 0) {
*dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
XMEMCPY(*dst, httpBuf + idx, len);
}
return len;
}
static int decode_url(const char* url, int urlSz,
char* outName, char* outPath, int* outPort)
{
@ -694,7 +631,124 @@ static int decode_url(const char* url, int urlSz,
}
#define SCRATCH_BUFFER_SIZE 2048
/* return: >0 OCSP Response Size
* -1 error */
static int process_http_response(int sfd, byte** respBuf,
byte* httpBuf, int httpBufSz)
{
int result;
int len = 0;
char *start, *end;
byte *recvBuf = NULL;
int recvBufSz = 0;
enum phr_state { phr_init, phr_http_start, phr_have_length,
phr_have_type, phr_wait_end, phr_http_end
} state = phr_init;
start = end = NULL;
do {
if (end == NULL) {
result = (int)recv(sfd, httpBuf+len, httpBufSz-len-1, 0);
if (result > 0) {
len += result;
start = (char*)httpBuf;
start[len+1] = 0;
}
else {
CYASSL_MSG("process_http_response recv http from peer failed");
return -1;
}
}
end = XSTRSTR(start, "\r\n");
if (end == NULL) {
if (len != 0)
XMEMMOVE(httpBuf, start, len);
start = end = NULL;
}
else if (end == start) {
if (state == phr_wait_end) {
state = phr_http_end;
len -= 2;
start += 2;
}
else {
CYASSL_MSG("process_http_response header ended early");
return -1;
}
}
else {
*end = 0;
len -= end - start + 2;
if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
start += 9;
if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
state != phr_init) {
CYASSL_MSG("process_http_response not OK");
return -1;
}
state = phr_http_start;
}
else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
start += 13;
while (*start == ' ' && *start != '\0') start++;
if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
CYASSL_MSG("process_http_response not ocsp-response");
return -1;
}
if (state == phr_http_start) state = phr_have_type;
else if (state == phr_have_length) state = phr_wait_end;
else {
CYASSL_MSG("process_http_response type invalid state");
return -1;
}
}
else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
start += 15;
while (*start == ' ' && *start != '\0') start++;
recvBufSz = atoi(start);
if (state == phr_http_start) state = phr_have_length;
else if (state == phr_have_type) state = phr_wait_end;
else {
CYASSL_MSG("process_http_response length invalid state");
return -1;
}
}
start = end + 2;
}
} while (state != phr_http_end);
recvBuf = XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
if (recvBuf == NULL) {
CYASSL_MSG("process_http_response couldn't create response buffer");
return -1;
}
/* copy the remainder of the httpBuf into the respBuf */
if (len != 0)
XMEMCPY(recvBuf, start, len);
/* receive the OCSP response data */
do {
result = (int)recv(sfd, recvBuf+len, recvBufSz-len, 0);
if (result > 0)
len += result;
else {
CYASSL_MSG("process_http_response recv ocsp from peer failed");
return -1;
}
} while (len != recvBufSz);
*respBuf = recvBuf;
return recvBufSz;
}
#define SCRATCH_BUFFER_SIZE 512
int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
@ -721,6 +775,8 @@ int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
return -1;
}
/* Note, the library uses the EmbedOcspRespFree() callback to
* free this buffer. */
httpBufSz = SCRATCH_BUFFER_SIZE;
httpBuf = (byte*)XMALLOC(httpBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
@ -728,7 +784,6 @@ int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
CYASSL_MSG("Unable to create OCSP response buffer");
return -1;
}
*ocspRespBuf = httpBuf;
httpBufSz = build_http_request(domainName, path, ocspReqSz,
httpBuf, httpBufSz);
@ -739,11 +794,8 @@ int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
if (written == httpBufSz) {
written = (int)send(sfd, ocspReqBuf, ocspReqSz, 0);
if (written == ocspReqSz) {
httpBufSz = (int)recv(sfd, httpBuf, SCRATCH_BUFFER_SIZE, 0);
if (httpBufSz > 0) {
ocspRespSz = decode_http_response(httpBuf, httpBufSz,
ocspRespBuf);
}
ocspRespSz = process_http_response(sfd, ocspRespBuf,
httpBuf, SCRATCH_BUFFER_SIZE);
}
}
close(sfd);

View File

@ -283,7 +283,7 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
else
return OCSP_NEED_URL;
}
else if (cert->extAuthInfoSz == 0 || cert->extAuthInfo == NULL) {
else if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
url = (const char *)cert->extAuthInfo;
urlSz = cert->extAuthInfoSz;
}