dynamic allocation of OCSP responses, response signature check

This commit is contained in:
John Safranek
2012-05-31 17:29:32 -07:00
parent 4b8bb6cdfe
commit 6d76b2f247
4 changed files with 470 additions and 227 deletions

View File

@@ -1916,7 +1916,7 @@ word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID)
return encDigSz + algoSz + seqSz;
}
#include <stdio.h>
/* return true (1) for Confirmation */
static int ConfirmSignature(const byte* buf, word32 bufSz,
const byte* key, word32 keySz, word32 keyOID,
@@ -2029,7 +2029,7 @@ static int ConfirmSignature(const byte* buf, word32 bufSz,
{
int x;
printf("cyassl encodedSig:\n");
for (x = 0; x < sigSz; x++) {
for (x = 0; x < encodedSigSz; x++) {
printf("%02x ", encodedSig[x]);
if ( (x % 16) == 15)
printf("\n");
@@ -4122,6 +4122,8 @@ static int GetEnumerated(const byte* input, word32* inOutIdx, int *value)
word32 idx = *inOutIdx;
word32 len;
CYASSL_ENTER("GetEnumerated");
*value = 0;
if (input[idx++] != ASN_ENUMERATED)
@@ -4145,22 +4147,19 @@ static int DecodeSingleResponse(byte* source,
word32* ioIndex, OcspResponse* resp, word32 size)
{
word32 index = *ioIndex, prevIndex, oid;
int length;
CertStatus* cs = NULL;
int length, wrapperSz;
CertStatus* cs = resp->status;
CYASSL_ENTER("DecodeSingleResponse");
/* Outer wrapper of the SEQUENCE OF Single Responses. */
if (GetSequence(source, &index, &length, size) < 0)
if (GetSequence(source, &index, &wrapperSz, size) < 0)
return ASN_PARSE_E;
prevIndex = index;
/* When making a request, we only request one status on one certificate
* at a time. There should only be one SingleResponse */
cs = resp->status;/*XMALLOC(sizeof(CertStatus), NULL, DYNAMIC_TYPE_CERT_STATUS);
if (cs == NULL)
{
CYASSL_MSG("\tAlloc Cert Status failed");
return MEMORY_E;
}
cs->next = NULL; */
/* Wrapper around the Single Response */
if (GetSequence(source, &index, &length, size) < 0)
@@ -4172,17 +4171,19 @@ static int DecodeSingleResponse(byte* source,
/* Skip the hash algorithm */
if (GetAlgoId(source, &index, &oid, size) < 0)
return ASN_PARSE_E;
/* Skip the hash of CN */
/* Save reference to the hash of CN */
if (source[index++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
resp->issuerHash = source + index;
index += length;
/* Skip the hash of the issuer public key */
/* Save reference to the hash of the issuer public key */
if (source[index++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
if (GetLength(source, &index, &length, size) < 0)
return ASN_PARSE_E;
resp->issuerKeyHash = source + index;
index += length;
/* Read the serial number, it is handled as a string, not as a
@@ -4231,8 +4232,12 @@ static int DecodeSingleResponse(byte* source,
if (GetBasicDate(source, &index, cs->thisDate,
&cs->thisDateFormat, size) < 0)
return ASN_PARSE_E;
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
/* The following items are optional. Only check for them if there is more
* unprocessed data in the singleResponse wrapper. */
if ((index - prevIndex < wrapperSz) &&
(source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)))
{
index++;
if (GetLength(source, &index, &length, size) < 0)
@@ -4241,7 +4246,8 @@ static int DecodeSingleResponse(byte* source,
&cs->nextDateFormat, size) < 0)
return ASN_PARSE_E;
}
if (source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
if ((index - prevIndex < wrapperSz) &&
(source[index] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)))
{
index++;
if (GetLength(source, &index, &length, size) < 0)
@@ -4318,15 +4324,18 @@ static int DecodeOcspRespExtensions(byte* source,
static int DecodeResponseData(byte* source,
word32* ioIndex, OcspResponse* resp, word32 size)
{
word32 idx = *ioIndex;
word32 idx = *ioIndex, prev_idx;
int length;
int version;
word32 responderId = 0;
CYASSL_ENTER("DecodeResponseData");
resp->response = source + idx;
prev_idx = idx;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
resp->respBegin = idx;
resp->respLength = length;
resp->responseSz = length + idx - prev_idx;
/* Get version. It is an EXPLICIT[0] DEFAULT(0) value. If this
* item isn't an EXPLICIT[0], then set version to zero and move
@@ -4375,7 +4384,7 @@ static int DecodeCerts(byte* source,
{
word32 idx = *ioIndex;
(void)resp;
CYASSL_ENTER("DecodeCerts");
if (source[idx++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
{
@@ -4383,6 +4392,13 @@ static int DecodeCerts(byte* source,
if (GetLength(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
resp->cert = source + idx;
resp->certSz = length;
idx += length;
}
*ioIndex = idx;
@@ -4396,6 +4412,8 @@ static int DecodeBasicOcspResponse(byte* source,
word32 idx = *ioIndex;
word32 end_index;
CYASSL_ENTER("DecodeBasicOcspResponse");
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
@@ -4416,8 +4434,8 @@ static int DecodeBasicOcspResponse(byte* source,
int sigLength = 0;
if (GetLength(source, &idx, &sigLength, size) < 0)
return ASN_PARSE_E;
resp->sigLength = sigLength;
resp->sigIndex = idx;
resp->sigSz = sigLength;
resp->sig = source + idx;
idx += sigLength;
}
@@ -4426,25 +4444,55 @@ static int DecodeBasicOcspResponse(byte* source,
* see if there are certificates, they are optional.
*/
if (idx < end_index)
return DecodeCerts(source, &idx, resp, size);
{
DecodedCert cert;
int ret;
if (DecodeCerts(source, &idx, resp, size) < 0)
return ASN_PARSE_E;
InitDecodedCert(&cert, resp->cert, resp->certSz, 0);
ret = ParseCertRelative(&cert, CA_TYPE, NO_VERIFY, 0);
if (ret < 0)
return ret;
ret = ConfirmSignature(resp->response, resp->responseSz,
cert.publicKey, cert.pubKeySize, cert.keyOID,
resp->sig, resp->sigSz, resp->sigOID, NULL);
FreeDecodedCert(&cert);
if (ret == 0)
{
CYASSL_MSG("\tConfirm signature failed");
return ASN_SIG_CONFIRM_E;
}
}
*ioIndex = idx;
return 0;
}
void InitOcspResponse(OcspResponse* resp, byte* source, word32 inSz, void* heap)
void InitOcspResponse(OcspResponse* resp, CertStatus* status,
byte* source, word32 inSz)
{
XMEMSET(resp, 0, sizeof(*resp));
CYASSL_ENTER("InitOcspResponse");
resp->responseStatus = -1;
resp->response = NULL;
resp->responseSz = 0;
resp->producedAt = NULL;
resp->producedAtFormat = 0;
resp->issuerHash = NULL;
resp->issuerKeyHash = NULL;
resp->sig = NULL;
resp->sigSz = 0;
resp->sigOID = 0;
resp->status = status;
resp->nonce = NULL;
resp->nonceSz = 0;
resp->source = source;
resp->maxIdx = inSz;
resp->heap = heap;
}
void FreeOcspResponse(OcspResponse* resp)
{
(void)resp;
}
@@ -4456,6 +4504,8 @@ int OcspResponseDecode(OcspResponse* resp)
word32 size = resp->maxIdx;
word32 oid;
CYASSL_ENTER("OcspResponseDecode");
/* peel the outer SEQUENCE wrapper */
if (GetSequence(source, &idx, &length, size) < 0)
return ASN_PARSE_E;
@@ -4501,6 +4551,8 @@ static int SetSerialNumber(const byte* sn, word32 snSz, byte* output)
{
int result = 0;
CYASSL_ENTER("SetSerialNumber");
if (snSz <= EXTERNAL_SERIAL_SIZE) {
output[0] = ASN_INTEGER;
output[1] = snSz + 1;
@@ -4520,6 +4572,8 @@ static word32 SetOcspReqExtensions(word32 extSz, byte* output,
byte seqArray[5][MAX_SEQ_SZ];
word32 seqSz[5], totalSz;
CYASSL_ENTER("SetOcspReqExtensions");
if (nonce == NULL || nonceSz == 0) return 0;
seqArray[0][0] = ASN_OCTET_STRING;
@@ -4563,7 +4617,7 @@ static word32 SetOcspReqExtensions(word32 extSz, byte* output,
}
int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
int EncodeOcspRequest(OcspRequest* req)
{
byte seqArray[5][MAX_SEQ_SZ];
/* The ASN.1 of the OCSP Request is an onion of sequences */
@@ -4572,29 +4626,34 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
byte issuerKeyArray[MAX_ENCODED_DIG_SZ];
byte snArray[MAX_SN_SZ];
byte extArray[MAX_OCSP_EXT_SZ];
byte nonceArray[MAX_OCSP_NONCE_SZ];
byte* output = req->dest;
word32 outputSz = req->destSz;
RNG rng;
word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, nonceSz,
extSz, totalSz;
word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz;
int i;
(void)outputSz;
CYASSL_ENTER("EncodeOcspRequest");
algoSz = SetAlgoID(SHAh, algoArray, hashType);
issuerSz = SetDigest(cert->issuerHash, SHA_SIZE, issuerArray);
issuerKeySz = SetDigest(cert->issuerKeyHash, SHA_SIZE, issuerKeyArray);
snSz = SetSerialNumber(cert->serial, cert->serialSz, snArray);
req->issuerHash = req->cert->issuerHash;
issuerSz = SetDigest(req->cert->issuerHash, SHA_SIZE, issuerArray);
req->issuerKeyHash = req->cert->issuerKeyHash;
issuerKeySz = SetDigest(req->cert->issuerKeyHash, SHA_SIZE, issuerKeyArray);
req->serial = req->cert->serial;
req->serialSz = req->cert->serialSz;
snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray);
if (InitRng(&rng) != 0) {
CYASSL_MSG("\tCannot initialize RNG. Skipping the OSCP Nonce.");
nonceSz = 0;
extSz = 0;
} else {
nonceSz = MAX_OCSP_NONCE_SZ;
RNG_GenerateBlock(&rng, nonceArray, nonceSz);
req->nonceSz = MAX_OCSP_NONCE_SZ;
RNG_GenerateBlock(&rng, req->nonce, req->nonceSz);
extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray,
nonceArray, nonceSz);
req->nonce, req->nonceSz);
}
totalSz = algoSz + issuerSz + issuerKeySz + snSz;
@@ -4626,12 +4685,18 @@ int EncodeOcspRequest(DecodedCert* cert, byte* output, word32 outputSz)
}
void InitOcspRequest(OcspRequest* req, byte* dest, word32 destSz, void* heap)
void InitOcspRequest(OcspRequest* req, DecodedCert* cert,
byte* dest, word32 destSz)
{
XMEMSET(req, 0, sizeof(*req));
CYASSL_ENTER("InitOcspRequest");
req->cert = cert;
req->nonceSz = 0;
req->issuerHash = NULL;
req->issuerKeyHash = NULL;
req->serial = NULL;
req->dest = dest;
req->destSz = destSz;
req->heap = heap;
}
@@ -4639,14 +4704,61 @@ int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp)
{
int cmp;
if (req == NULL) return -1;
if (resp == NULL) return 1;
CYASSL_ENTER("CompareOcspReqResp");
if (req == NULL)
{
CYASSL_MSG("\tReq missing");
return -1;
}
if (resp == NULL)
{
CYASSL_MSG("\tResp missing");
return 1;
}
cmp = req->nonceSz - resp->nonceSz;
if (cmp != 0) return cmp;
if (cmp != 0)
{
CYASSL_MSG("\tnonceSz mismatch");
return cmp;
}
cmp = XMEMCMP(req->nonce, resp->nonce, req->nonceSz);
if (cmp != 0) return cmp;
if (cmp != 0)
{
CYASSL_MSG("\tnonce mismatch");
return cmp;
}
cmp = XMEMCMP(req->issuerHash, resp->issuerHash, SHA_DIGEST_SIZE);
if (cmp != 0)
{
CYASSL_MSG("\tissuerHash mismatch");
return cmp;
}
cmp = XMEMCMP(req->issuerKeyHash, resp->issuerKeyHash, SHA_DIGEST_SIZE);
if (cmp != 0)
{
CYASSL_MSG("\tissuerKeyHash mismatch");
return cmp;
}
cmp = req->serialSz - resp->status->serialSz;
if (cmp != 0)
{
CYASSL_MSG("\tserialSz mismatch");
return cmp;
}
cmp = XMEMCMP(req->serial, resp->status->serial, req->serialSz);
if (cmp != 0)
{
CYASSL_MSG("\tserial mismatch");
return cmp;
}
return 0;
}

View File

@@ -358,68 +358,69 @@ typedef struct OcspResponse OcspResponse;
struct CertStatus {
CertStatus* next;
CertStatus* next;
byte serial[EXTERNAL_SERIAL_SIZE];
int serialSz;
byte serial[EXTERNAL_SERIAL_SIZE];
int serialSz;
int status;
byte thisDate[MAX_DATE_SIZE];
byte nextDate[MAX_DATE_SIZE];
byte thisDateFormat;
byte nextDateFormat;
byte thisDate[MAX_DATE_SIZE];
byte nextDate[MAX_DATE_SIZE];
byte thisDateFormat;
byte nextDateFormat;
};
struct OcspResponse {
int responseStatus; /* return code from Responder */
word32 respBegin; /* index to beginning of OCSP Response */
word32 respLength; /* length of the OCSP Response */
int version; /* Response version number */
byte* response; /* Pointer to beginning of OCSP Response */
word32 responseSz; /* length of the OCSP Response */
byte* producedAt; /* Time at which this response was signed */
byte producedAtFormat;/* format of the producedAt date */
byte producedAtFormat;/* format of the producedAt date */
byte* issuerHash;
byte* issuerKeyHash;
word32 sigIndex; /* Index into source for start of sig */
word32 sigLength; /* Length in octets for the sig */
byte* cert;
word32 certSz;
byte* sig; /* Pointer to sig in source */
word32 sigSz; /* Length in octets for the sig */
word32 sigOID; /* OID for hash used for sig */
CertStatus status[1]; /* list of certificate status */
CertStatus* status; /* certificate status to fill out */
byte* nonce; /* pointer to nonce inside ASN.1 response */
int nonceSz; /* length of the nonce string */
byte* source; /* pointer to source buffer, not owned */
word32 maxIdx; /* max offset based on init size */
void* heap; /* for user memory overrides */
};
struct OcspRequest {
byte* nonce;
DecodedCert* cert;
byte nonce[MAX_OCSP_NONCE_SZ];
int nonceSz;
byte* issuerHash; /* pointer to issuerHash in source cert */
byte* issuerKeyHash; /* pointer to issuerKeyHash in source cert */
byte* serial; /* pointer to serial number in source cert */
int serialSz; /* length of the serial number */
byte* issuerHash; /* pointer to issuerHash in source cert */
byte* issuerKeyHash; /* pointer to issuerKeyHash in source cert */
byte* serial; /* pointer to serial number in source cert */
int serialSz; /* length of the serial number */
byte* dest; /* pointer to the destination ASN.1 buffer */
word32 destSz; /* length of the destination buffer */
void* heap;
};
CYASSL_LOCAL void InitOcspResponse(OcspResponse*, byte*, word32, void*);
CYASSL_LOCAL void FreeOcspResponse(OcspResponse*);
CYASSL_LOCAL void InitOcspResponse(OcspResponse*, CertStatus*, byte*, word32);
CYASSL_LOCAL int OcspResponseDecode(OcspResponse*);
CYASSL_LOCAL void InitOcspRequest(OcspRequest*, byte*, word32, void*);
CYASSL_LOCAL void FreeOcspRequest(OcspRequest*);
CYASSL_LOCAL int EncodeOcspRequest(DecodedCert*, byte*, word32);
CYASSL_LOCAL void InitOcspRequest(OcspRequest*, DecodedCert*, byte*, word32);
CYASSL_LOCAL int EncodeOcspRequest(OcspRequest*);
CYASSL_LOCAL int CompareOcspReqResp(OcspRequest*, OcspResponse*);

View File

@@ -630,7 +630,7 @@ struct OCSP_Entry {
OCSP_Entry* next; /* next entry */
byte issuerHash[SHA_DIGEST_SIZE]; /* issuer hash */
byte issuerKeyHash[SHA_DIGEST_SIZE]; /* issuer public key hash */
CertStatus status[1]; /* OCSP response list */
CertStatus* status; /* OCSP response list */
int totalStatus; /* number on list */
};
@@ -642,7 +642,7 @@ struct CYASSL_OCSP {
char overrideName[80];
char overridePath[80];
int overridePort;
OCSP_Entry ocspList[1];
OCSP_Entry* ocspList;
};

View File

@@ -51,29 +51,6 @@ typedef struct sockaddr_in SOCKADDR_IN_T;
#define SOCKET_T unsigned int
int ocsp_test(unsigned char* buf, int sz)
{
CYASSL_OCSP ocsp;
OcspResponse resp;
int result;
CyaSSL_OCSP_Init(&ocsp);
InitOcspResponse(&resp, buf, sz, NULL);
ocsp.enabled = 1;
ocsp.useOverrideUrl = 1;
CyaSSL_OCSP_set_override_url(&ocsp, "http://ocsp.example.com:8080/bob");
CyaSSL_OCSP_Lookup_Cert(&ocsp, NULL);
result = OcspResponseDecode(&resp);
FreeOcspResponse(&resp);
CyaSSL_OCSP_Cleanup(&ocsp);
return result;
}
int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
{
if (ocsp != NULL) {
@@ -85,83 +62,105 @@ int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
}
static void FreeOCSP_Entry(OCSP_Entry* ocspe)
{
CertStatus* tmp = ocspe->status;
CYASSL_ENTER("FreeOCSP_Entry");
while (tmp) {
CertStatus* next = tmp->next;
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
tmp = next;
}
}
void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
{
OCSP_Entry* tmp = ocsp->ocspList;
ocsp->enabled = 0;
while (tmp) {
OCSP_Entry* next = tmp->next;
FreeOCSP_Entry(tmp);
XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
tmp = next;
}
}
static int decode_url(const char* url, int urlSz,
char* outName, char* outPath, int* outPort)
char* outName, char* outPath, int* outPort)
{
if (outName != NULL && outPath != NULL && outPort != NULL)
{
if (url == NULL || urlSz == 0)
{
*outName = 0;
*outPath = 0;
*outPort = 0;
}
else
{
int i, cur;
/* need to break the url down into scheme, address, and port */
/* "http://example.com:8080/" */
if (XSTRNCMP(url, "http://", 7) == 0) {
cur = 7;
} else cur = 0;
i = 0;
while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
outName[i++] = url[cur++];
}
outName[i] = 0;
/* Need to pick out the path after the domain name */
if (cur < urlSz && url[cur] == ':') {
char port[6];
int j;
i = 0;
cur++;
while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
i < 6) {
port[i++] = url[cur++];
}
*outPort = 0;
for (j = 0; j < i; j++) {
if (port[j] < '0' || port[j] > '9') return -1;
*outPort = (*outPort * 10) + (port[j] - '0');
}
}
else
*outPort = 80;
if (cur < urlSz && url[cur] == '/') {
i = 0;
while (cur < urlSz && url[cur] != 0 && i < 80) {
outPath[i++] = url[cur++];
}
outPath[i] = 0;
}
else {
outPath[0] = '/';
outPath[1] = 0;
}
}
}
if (outName != NULL && outPath != NULL && outPort != NULL)
{
if (url == NULL || urlSz == 0)
{
*outName = 0;
*outPath = 0;
*outPort = 0;
}
else
{
int i, cur;
/* need to break the url down into scheme, address, and port */
/* "http://example.com:8080/" */
if (XSTRNCMP(url, "http://", 7) == 0) {
cur = 7;
} else cur = 0;
i = 0;
while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
outName[i++] = url[cur++];
}
outName[i] = 0;
/* Need to pick out the path after the domain name */
if (cur < urlSz && url[cur] == ':') {
char port[6];
int j;
i = 0;
cur++;
while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
i < 6) {
port[i++] = url[cur++];
}
*outPort = 0;
for (j = 0; j < i; j++) {
if (port[j] < '0' || port[j] > '9') return -1;
*outPort = (*outPort * 10) + (port[j] - '0');
}
}
else
*outPort = 80;
if (cur < urlSz && url[cur] == '/') {
i = 0;
while (cur < urlSz && url[cur] != 0 && i < 80) {
outPath[i++] = url[cur++];
}
outPath[i] = 0;
}
else {
outPath[0] = '/';
outPath[1] = 0;
}
}
}
return 0;
return 0;
}
int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
{
if (ocsp != NULL) {
int urlSz = strlen(url);
decode_url(url, urlSz,
ocsp->overrideName, ocsp->overridePath, &ocsp->overridePort);
int urlSz = strlen(url);
decode_url(url, urlSz,
ocsp->overrideName, ocsp->overridePath, &ocsp->overridePort);
return 1;
}
@@ -214,7 +213,7 @@ static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
static int build_http_request(const char* domainName, const char* path,
int ocspReqSz, byte* buf, int bufSize)
int ocspReqSz, byte* buf, int bufSize)
{
return snprintf((char*)buf, bufSize,
"POST %s HTTP/1.1\r\n"
@@ -226,22 +225,23 @@ static int build_http_request(const char* domainName, const char* path,
}
static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
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 (strncasecmp(buf, "HTTP/1", 6) != 0)
return NULL;
return 0;
idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
* HTTP result code */
if (strncasecmp(&buf[idx], "200 OK", 6) != 0)
return NULL;
return 0;
idx += 8;
@@ -256,18 +256,16 @@ static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
idx += 13;
if (buf[idx] == ' ') idx++;
if (strncasecmp(&buf[idx], "application/ocsp-response", 25) != 0)
return NULL;
return 0;
idx += 27;
} else if (contentLength == NULL &&
strncasecmp(&buf[idx], "Content-Length:", 15) == 0) {
int len = 0;
idx += 15;
if (buf[idx] == ' ') idx++;
while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
len = (len * 10) + (buf[idx] - '0');
idx++;
}
*ocspRespSz = len;
idx += 2; /* skip the crlf */
} else {
/* Advance idx past the next \r\n */
@@ -277,52 +275,128 @@ static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
}
}
}
return &httpBuf[idx];
if (len > 0) {
*dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
XMEMCPY(*dst, httpBuf + idx, len);
}
return len;
}
static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
{
CYASSL_ENTER("InitOCSP_Entry");
ocspe->next = NULL;
XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
ocspe->status = NULL;
ocspe->totalStatus = 0;
return 0;
}
static OCSP_Entry* find_ocsp_entry(CYASSL_OCSP* ocsp, DecodedCert* cert)
{
OCSP_Entry* entry = ocsp->ocspList;
while (entry)
{
if (XMEMCMP(entry->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
&& XMEMCMP(entry->issuerKeyHash, cert->issuerKeyHash,
SHA_DIGEST_SIZE) == 0)
{
CYASSL_MSG("Found OCSP responder");
break;
}
else
{
entry = entry->next;
}
}
if (entry == NULL)
{
CYASSL_MSG("Add a new OCSP entry");
entry = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
NULL, DYNAMIC_TYPE_OCSP_ENTRY);
if (entry != NULL)
{
InitOCSP_Entry(entry, cert);
entry->next = ocsp->ocspList;
ocsp->ocspList = entry;
}
}
return entry;
}
static CertStatus* find_cert_status(OCSP_Entry* ocspe, DecodedCert* cert)
{
CertStatus* stat = ocspe->status;
while (stat)
{
if(stat->serialSz == cert->serialSz &&
(XMEMCMP(stat->serial, cert->serial, cert->serialSz) == 0))
{
break;
}
else
{
stat = stat->next;
}
}
if (stat == NULL)
{
stat = (CertStatus*)XMALLOC(sizeof(CertStatus),
NULL, DYNAMIC_TYPE_OCSP_STATUS);
if (stat != NULL)
{
XMEMCPY(stat->serial, cert->serial, cert->serialSz);
stat->serialSz = cert->serialSz;
stat->status = -1;
ocspe->totalStatus++;
stat->next = ocspe->status;
ocspe->status = stat;
}
}
return stat;
}
#define SCRATCH_BUFFER_SIZE 2048
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
static int http_ocsp_transaction(CYASSL_OCSP* ocsp, DecodedCert* cert,
byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
{
SOCKET_T sfd = -1;
byte buf[SCRATCH_BUFFER_SIZE];
byte* httpBuf = &buf[0];
int httpBufSz = SCRATCH_BUFFER_SIZE/4;
byte* ocspReqBuf = &buf[httpBufSz];
int ocspReqSz = SCRATCH_BUFFER_SIZE - httpBufSz;
OcspResponse ocspResponse;
int result = 0;
char domainName[80], path[80];
int port;
/* If OCSP lookups are disabled, return success. */
if (!ocsp->enabled) {
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
return 0;
}
byte httpBuf[SCRATCH_BUFFER_SIZE];
int httpBufSz = SCRATCH_BUFFER_SIZE;
char domainName[80], path[80];
int port, ocspRespSz;
if (ocsp->useOverrideUrl || cert->extAuthInfo == NULL) {
if (ocsp->overrideName != NULL) {
XMEMCPY(domainName, ocsp->overrideName, 80);
XMEMCPY(path, ocsp->overridePath, 80);
port = ocsp->overridePort;
} else
return OCSP_NEED_URL;
} else {
if (!decode_url((const char*)cert->extAuthInfo, cert->extAuthInfoSz,
domainName, path, &port))
return OCSP_NEED_URL;
}
if (ocsp->overrideName != NULL) {
XMEMCPY(domainName, ocsp->overrideName, 80);
XMEMCPY(path, ocsp->overridePath, 80);
port = ocsp->overridePort;
} else
return OCSP_NEED_URL;
} else {
if (!decode_url((const char*)cert->extAuthInfo, cert->extAuthInfoSz,
domainName, path, &port))
return OCSP_NEED_URL;
}
XMEMCPY(ocsp->ocspList->issuerHash, cert->issuerHash, SHA_SIZE);
XMEMCPY(ocsp->ocspList->issuerKeyHash, cert->issuerKeyHash, SHA_SIZE);
XMEMCPY(ocsp->ocspList->status->serial, cert->serial, cert->serialSz);
ocsp->ocspList->status->serialSz = cert->serialSz;
ocspReqSz = EncodeOcspRequest(cert, ocspReqBuf, ocspReqSz);
httpBufSz = build_http_request(domainName, path, ocspReqSz,
httpBuf, httpBufSz);
httpBuf, httpBufSz);
tcp_connect(&sfd, domainName, port);
if (sfd > 0) {
@@ -331,15 +405,15 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
if (written == httpBufSz) {
written = write(sfd, ocspReqBuf, ocspReqSz);
if (written == ocspReqSz) {
httpBufSz = read(sfd, buf, SCRATCH_BUFFER_SIZE);
httpBufSz = read(sfd, httpBuf, SCRATCH_BUFFER_SIZE);
if (httpBufSz > 0) {
ocspReqBuf = decode_http_response(buf, httpBufSz,
&ocspReqSz);
ocspRespSz = decode_http_response(httpBuf, httpBufSz,
ocspRespBuf);
}
}
}
close(sfd);
if (ocspReqBuf == NULL) {
if (ocspRespSz == 0) {
CYASSL_MSG("HTTP response was not OK, no OCSP response");
return OCSP_LOOKUP_FAIL;
}
@@ -348,26 +422,82 @@ int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
return OCSP_LOOKUP_FAIL;
}
InitOcspResponse(&ocspResponse, ocspReqBuf, ocspReqSz, NULL);
return ocspRespSz;
}
int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
{
byte ocspReqBuf[SCRATCH_BUFFER_SIZE];
int ocspReqSz = SCRATCH_BUFFER_SIZE;
byte* ocspRespBuf = NULL;
int ocspRespSz;
OcspRequest ocspRequest;
OcspResponse ocspResponse;
int result = 0;
OCSP_Entry* ocspe;
CertStatus* certStatus;
/* If OCSP lookups are disabled, return success. */
if (!ocsp->enabled) {
CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
return 0;
}
ocspe = find_ocsp_entry(ocsp, cert);
if (ocspe == NULL) {
CYASSL_MSG("alloc OCSP entry failed");
return MEMORY_ERROR;
}
certStatus = find_cert_status(ocspe, cert);
if (certStatus == NULL)
{
CYASSL_MSG("alloc OCSP cert status failed");
return MEMORY_ERROR;
}
if (certStatus->status != -1)
{
}
InitOcspRequest(&ocspRequest, cert, ocspReqBuf, ocspReqSz);
ocspReqSz = EncodeOcspRequest(&ocspRequest);
result = http_ocsp_transaction(ocsp, cert,
ocspReqBuf, ocspReqSz, &ocspRespBuf);
if (result < 0) return result;
/* If the transaction failed, return that result. */
InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, ocspRespSz);
OcspResponseDecode(&ocspResponse);
if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
CYASSL_MSG("OCSP Responder failure");
result = OCSP_LOOKUP_FAIL;
result = OCSP_LOOKUP_FAIL;
} else {
switch (ocspResponse.status[0].status) {
case CERT_GOOD:
result = 0;
break;
case CERT_REVOKED:
result = OCSP_CERT_REVOKED;
break;
default:
result = OCSP_CERT_UNKNOWN;
break;
}
if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0)
{
switch (ocspResponse.status[0].status) {
case CERT_GOOD:
result = 0;
break;
case CERT_REVOKED:
result = OCSP_CERT_REVOKED;
break;
default:
result = OCSP_CERT_UNKNOWN;
break;
}
}
else
{
CYASSL_MSG("OCSP Response incorrect for Request");
result = OCSP_LOOKUP_FAIL;
}
}
if (ocspReqBuf != NULL) {
XFREE(ocspRespBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
}
FreeOcspResponse(&ocspResponse);
return result;
}