Thread safe OCSP.

This commit is contained in:
John Safranek
2014-01-31 16:59:13 -08:00
parent 12e9309618
commit 909b9258d6
2 changed files with 98 additions and 117 deletions

View File

@@ -999,6 +999,7 @@ struct OCSP_Entry {
struct CYASSL_OCSP { struct CYASSL_OCSP {
CYASSL_CERT_MANAGER* cm; /* pointer back to cert manager */ CYASSL_CERT_MANAGER* cm; /* pointer back to cert manager */
OCSP_Entry* ocspList; /* OCSP response list */ OCSP_Entry* ocspList; /* OCSP response list */
CyaSSL_Mutex ocspLock; /* OCSP list lock */
}; };
#ifndef MAX_DATE_SIZE #ifndef MAX_DATE_SIZE

View File

@@ -37,6 +37,8 @@ int InitOCSP(CYASSL_OCSP* ocsp, CYASSL_CERT_MANAGER* cm)
CYASSL_ENTER("InitOCSP"); CYASSL_ENTER("InitOCSP");
XMEMSET(ocsp, 0, sizeof(*ocsp)); XMEMSET(ocsp, 0, sizeof(*ocsp));
ocsp->cm = cm; ocsp->cm = cm;
if (InitMutex(&ocsp->ocspLock) != 0)
return BAD_MUTEX_E;
return 0; return 0;
} }
@@ -46,11 +48,9 @@ static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
{ {
CYASSL_ENTER("InitOCSP_Entry"); CYASSL_ENTER("InitOCSP_Entry");
ocspe->next = NULL; XMEMSET(ocspe, 0, sizeof(*ocspe));
XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE); XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE); XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
ocspe->status = NULL;
ocspe->totalStatus = 0;
return 0; return 0;
} }
@@ -83,84 +83,12 @@ void FreeOCSP(CYASSL_OCSP* ocsp, int dynamic)
tmp = next; tmp = next;
} }
FreeMutex(&ocsp->ocspLock);
if (dynamic) if (dynamic)
XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP); XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP);
} }
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;
stat->nextDate[0] = 0;
ocspe->totalStatus++;
stat->next = ocspe->status;
ocspe->status = stat;
}
}
return stat;
}
static int xstat2err(int stat) static int xstat2err(int stat)
{ {
switch (stat) { switch (stat) {
@@ -184,46 +112,73 @@ int CheckCertOCSP(CYASSL_OCSP* ocsp, DecodedCert* cert)
byte* ocspRespBuf = NULL; byte* ocspRespBuf = NULL;
OcspRequest ocspRequest; OcspRequest ocspRequest;
OcspResponse ocspResponse; OcspResponse ocspResponse;
int result = 0; int result = -1;
OCSP_Entry* ocspe; OCSP_Entry* ocspe;
CertStatus* certStatus; CertStatus* certStatus = NULL;
CertStatus newStatus;
const char *url; const char *url;
int urlSz; int urlSz;
CYASSL_ENTER("CheckCertOCSP"); CYASSL_ENTER("CheckCertOCSP");
ocspe = find_ocsp_entry(ocsp, cert); if (LockMutex(&ocsp->ocspLock) != 0) {
CYASSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E);
return BAD_MUTEX_E;
}
ocspe = ocsp->ocspList;
while (ocspe) {
if (XMEMCMP(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0
&& XMEMCMP(ocspe->issuerKeyHash, cert->issuerKeyHash,
SHA_DIGEST_SIZE) == 0)
break;
else
ocspe = ocspe->next;
}
if (ocspe == NULL) { if (ocspe == NULL) {
CYASSL_MSG("alloc OCSP entry failed"); ocspe = (OCSP_Entry*)XMALLOC(sizeof(OCSP_Entry),
NULL, DYNAMIC_TYPE_OCSP_ENTRY);
if (ocspe != NULL) {
InitOCSP_Entry(ocspe, cert);
ocspe->next = ocsp->ocspList;
ocsp->ocspList = ocspe;
}
else {
UnLockMutex(&ocsp->ocspLock);
CYASSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
return MEMORY_ERROR; return MEMORY_ERROR;
} }
}
certStatus = find_cert_status(ocspe, cert); else {
if (certStatus == NULL) certStatus = ocspe->status;
{ while (certStatus) {
CYASSL_MSG("alloc OCSP cert status failed"); if (certStatus->serialSz == cert->serialSz &&
return MEMORY_ERROR; XMEMCMP(certStatus->serial, cert->serial, cert->serialSz) == 0)
break;
else
certStatus = certStatus->next;
}
} }
if (certStatus->status != -1) if (certStatus != NULL) {
{
if (!ValidateDate(certStatus->thisDate, if (!ValidateDate(certStatus->thisDate,
certStatus->thisDateFormat, BEFORE) || certStatus->thisDateFormat, BEFORE) ||
(certStatus->nextDate[0] == 0) || (certStatus->nextDate[0] == 0) ||
!ValidateDate(certStatus->nextDate, !ValidateDate(certStatus->nextDate,
certStatus->nextDateFormat, AFTER)) certStatus->nextDateFormat, AFTER)) {
{
CYASSL_MSG("\tinvalid status date, looking up cert"); CYASSL_MSG("\tinvalid status date, looking up cert");
certStatus->status = -1;
} }
else else {
{
CYASSL_MSG("\tusing cached status");
result = xstat2err(certStatus->status); result = xstat2err(certStatus->status);
UnLockMutex(&ocsp->ocspLock);
CYASSL_LEAVE("CheckCertOCSP", result);
return result; return result;
} }
} }
UnLockMutex(&ocsp->ocspLock);
if (ocsp->cm->ocspUseOverrideURL) { if (ocsp->cm->ocspUseOverrideURL) {
url = ocsp->cm->ocspOverrideURL; url = ocsp->cm->ocspOverrideURL;
if (url != NULL && url[0] != '\0') if (url != NULL && url[0] != '\0')
@@ -236,57 +191,82 @@ int CheckCertOCSP(CYASSL_OCSP* ocsp, DecodedCert* cert)
urlSz = cert->extAuthInfoSz; urlSz = cert->extAuthInfoSz;
} }
else { else {
CYASSL_MSG("\tcert doesn't have extAuthInfo, assuming CERT_GOOD"); /* cert doesn't have extAuthInfo, assuming CERT_GOOD */
return 0; return 0;
} }
ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER); ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
if (ocspReqBuf == NULL) { if (ocspReqBuf == NULL) {
CYASSL_MSG("\talloc OCSP request buffer failed"); CYASSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
return MEMORY_ERROR; return MEMORY_ERROR;
} }
InitOcspRequest(&ocspRequest, cert, ocsp->cm->ocspSendNonce, InitOcspRequest(&ocspRequest, cert, ocsp->cm->ocspSendNonce,
ocspReqBuf, ocspReqSz); ocspReqBuf, ocspReqSz);
ocspReqSz = EncodeOcspRequest(&ocspRequest); ocspReqSz = EncodeOcspRequest(&ocspRequest);
if (ocsp->cm->ocspIOCb) { if (ocsp->cm->ocspIOCb)
result = ocsp->cm->ocspIOCb(ocsp->cm->ocspIOCtx, url, urlSz, result = ocsp->cm->ocspIOCb(ocsp->cm->ocspIOCtx, url, urlSz,
ocspReqBuf, ocspReqSz, &ocspRespBuf); ocspReqBuf, ocspReqSz, &ocspRespBuf);
}
if (result >= 0 && ocspRespBuf) { if (result >= 0 && ocspRespBuf) {
InitOcspResponse(&ocspResponse, certStatus, ocspRespBuf, result); XMEMSET(&newStatus, 0, sizeof(CertStatus));
InitOcspResponse(&ocspResponse, &newStatus, ocspRespBuf, result);
OcspResponseDecode(&ocspResponse); OcspResponseDecode(&ocspResponse);
if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) { if (ocspResponse.responseStatus != OCSP_SUCCESSFUL)
CYASSL_MSG("OCSP Responder failure");
result = OCSP_LOOKUP_FAIL; result = OCSP_LOOKUP_FAIL;
} else { else {
if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0) if (CompareOcspReqResp(&ocspRequest, &ocspResponse) == 0) {
{
result = xstat2err(ocspResponse.status->status); result = xstat2err(ocspResponse.status->status);
if (LockMutex(&ocsp->ocspLock) != 0)
result = BAD_MUTEX_E;
else {
if (certStatus != NULL)
/* Replace existing certificate entry with updated */
XMEMCPY(certStatus, &newStatus, sizeof(CertStatus));
else {
/* Save new certificate entry */
certStatus = (CertStatus*)XMALLOC(sizeof(CertStatus),
NULL, DYNAMIC_TYPE_OCSP_STATUS);
if (certStatus != NULL) {
XMEMCPY(certStatus, &newStatus, sizeof(CertStatus));
certStatus->next = ocspe->status;
ocspe->status = certStatus;
ocspe->totalStatus++;
}
}
UnLockMutex(&ocsp->ocspLock);
}
} }
else else
{
CYASSL_MSG("OCSP Response incorrect for Request");
result = OCSP_LOOKUP_FAIL; result = OCSP_LOOKUP_FAIL;
} }
} }
} else
else {
result = OCSP_LOOKUP_FAIL; result = OCSP_LOOKUP_FAIL;
}
if (ocspReqBuf != NULL) { if (ocspReqBuf != NULL)
XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER); XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
}
if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb) {
ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf);
}
if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb)
ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf);
CYASSL_LEAVE("CheckCertOCSP", result);
return result; return result;
} }
#else /* HAVE_OCSP */
#ifdef _MSC_VER
/* 4206 warning for blank file */
#pragma warning(disable: 4206)
#endif
#endif /* HAVE_OCSP */ #endif /* HAVE_OCSP */