diff --git a/Makefile.am b/Makefile.am index 63451fc50..91256b684 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,7 @@ EXTRA_DIST+= cyassl-ntru.sln EXTRA_DIST+= cyassl.sln EXTRA_DIST+= valgrind-error.sh EXTRA_DIST+= gencertbuf.pl +EXTRA_DIST+= IDE include cyassl/include.am include certs/include.am diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c index fd050cfb7..21d3b9c80 100644 --- a/ctaocrypt/src/asn.c +++ b/ctaocrypt/src/asn.c @@ -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; } diff --git a/cyassl/internal.h b/cyassl/internal.h index 411eb4c8b..4a5132c84 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1920,33 +1920,6 @@ enum HandShakeType { }; -/* Valid Alert types from page 16/17 */ -enum AlertDescription { - close_notify = 0, - unexpected_message = 10, - bad_record_mac = 20, - decompression_failure = 30, - handshake_failure = 40, - no_certificate = 41, - bad_certificate = 42, - unsupported_certificate = 43, - certificate_revoked = 44, - certificate_expired = 45, - certificate_unknown = 46, - illegal_parameter = 47, - decrypt_error = 51, - protocol_version = 70, - no_renegotiation = 100, - unrecognized_name = 112 -}; - - -enum AlertLevel { - alert_warning = 1, - alert_fatal = 2 -}; - - static const byte client[SIZEOF_SENDER] = { 0x43, 0x4C, 0x4E, 0x54 }; static const byte server[SIZEOF_SENDER] = { 0x53, 0x52, 0x56, 0x52 }; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 335cd9c6e..8d9352447 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -145,6 +145,33 @@ typedef struct CYASSL_X509_STORE_CTX { } CYASSL_X509_STORE_CTX; +/* Valid Alert types from page 16/17 */ +enum AlertDescription { + close_notify = 0, + unexpected_message = 10, + bad_record_mac = 20, + decompression_failure = 30, + handshake_failure = 40, + no_certificate = 41, + bad_certificate = 42, + unsupported_certificate = 43, + certificate_revoked = 44, + certificate_expired = 45, + certificate_unknown = 46, + illegal_parameter = 47, + decrypt_error = 51, + protocol_version = 70, + no_renegotiation = 100, + unrecognized_name = 112 +}; + + +enum AlertLevel { + alert_warning = 1, + alert_fatal = 2 +}; + + CYASSL_API CYASSL_METHOD *CyaSSLv3_server_method(void); CYASSL_API CYASSL_METHOD *CyaSSLv3_client_method(void); CYASSL_API CYASSL_METHOD *CyaTLSv1_server_method(void); diff --git a/examples/client/client.c b/examples/client/client.c index 200d05f74..632d872f8 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -131,6 +131,10 @@ static void Usage(void) printf("-z Print structure sizes\n"); #endif printf("-S Use Host Name Indication\n"); +#ifdef HAVE_OCSP + printf("-o Perform OCSP lookup on peer certificate\n"); + printf("-O Perform OCSP lookup using 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 diff --git a/examples/server/server.c b/examples/server/server.c index c0eac3e51..032ff7a1e 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -123,6 +123,10 @@ static void Usage(void) printf("-f Fewer packets/group messages\n"); printf("-N Use Non-blocking sockets\n"); printf("-S Use Host Name Indication\n"); +#ifdef HAVE_OCSP + printf("-o Perform OCSP lookup on peer certificate\n"); + printf("-O Perform OCSP lookup using 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); diff --git a/src/io.c b/src/io.c index f3d1c2d8a..4953201f8 100644 --- a/src/io.c +++ b/src/io.c @@ -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); diff --git a/src/ocsp.c b/src/ocsp.c index 64d082216..6933e9748 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -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; }