adds server side Certificate Status Request extension;

missing: Finish SendCertificateStatus();
This commit is contained in:
Moisés Guimarães
2015-11-12 23:29:27 -03:00
parent cc684f8593
commit 8ae6bf1641
10 changed files with 304 additions and 57 deletions

View File

@@ -725,6 +725,9 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args)
CyaSSL_CTX_EnableOCSP(ctx, CYASSL_OCSP_NO_NONCE);
}
#endif
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
wolfSSL_CTX_EnableOCSPStapling(ctx);
#endif
#ifdef HAVE_PK_CALLBACKS
if (pkCallbacks)
SetupPkCallbacks(ctx, ssl);

View File

@@ -4368,7 +4368,7 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_OCSP
if (ssl->ctx->cm->ocspEnabled && ssl->ctx->cm->ocspCheckAll) {
WOLFSSL_MSG("Doing Non Leaf OCSP check");
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert, NULL);
doCrlLookup = (ret == OCSP_CERT_UNKNOWN);
if (ret != 0) {
doCrlLookup = 0;
@@ -4469,7 +4469,7 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#ifdef HAVE_OCSP
if (doLookup && ssl->ctx->cm->ocspEnabled) {
WOLFSSL_MSG("Doing Leaf OCSP check");
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert);
ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert, NULL);
doLookup = (ret == OCSP_CERT_UNKNOWN);
if (ret != 0) {
WOLFSSL_MSG("\tOCSP Lookup not ok");
@@ -8141,6 +8141,86 @@ int SendCertificateRequest(WOLFSSL* ssl)
else
return SendBuffered(ssl);
}
int SendCertificateStatus(WOLFSSL* ssl)
{
int ret = 0;
byte status_type = 0;
WOLFSSL_ENTER("SendCertificateStatus");
(void) ssl;
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
status_type = ssl->status_request;
#endif
switch (status_type) {
#if defined HAVE_CERTIFICATE_STATUS_REQUEST
case WOLFSSL_CSR_OCSP: {
buffer response = {NULL, 0};
buffer der = ssl->buffers.certificate;
#ifdef WOLFSSL_SMALL_STACK
DecodedCert* cert = NULL;
#else
DecodedCert cert[1];
#endif
/* unable to fetch status. skip. */
if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
return 0;
if (der.buffer == NULL || der.length == 0)
return 0;
#ifdef WOLFSSL_SMALL_STACK
cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (cert == NULL)
return MEMORY_E;
#endif
InitDecodedCert(cert, der.buffer, der.length, NULL);
if ((ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY,
ssl->ctx->cm)) != 0) {
WOLFSSL_MSG("ParseCert failed");
}
else {
ret = CheckCertOCSP(ssl->ctx->cm->ocsp_stapling, cert,
&response);
if (response.buffer) {
if (ret == OCSP_CERT_REVOKED || ret == OCSP_CERT_UNKNOWN) {
ret = 0; /* Forward status to client */
}
if (ret == 0) {
}
XFREE(response.buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (ret == OCSP_LOOKUP_FAIL)
ret = 0; /* Suppressing, not critical */
}
FreeDecodedCert(cert);
#ifdef WOLFSSL_SMALL_STACK
XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
break;
#endif
default:
break;
}
return ret;
}
#endif /* !NO_CERTS */

View File

@@ -77,6 +77,10 @@ static void FreeOcspEntry(OcspEntry* entry)
for (status = entry->status; status; status = next) {
next = status->next;
if (status->rawOcspResponse)
XFREE(status->rawOcspResponse, NULL, DYNAMIC_TYPE_OCSP_STATUS);
XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
}
}
@@ -114,7 +118,7 @@ static int xstat2err(int stat)
}
int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert)
int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert, void* encodedResponse)
{
int ret = OCSP_LOOKUP_FAIL;
@@ -137,7 +141,7 @@ int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert)
#endif
if (InitOcspRequest(ocspRequest, cert, ocsp->cm->ocspSendNonce) == 0) {
ret = CheckOcspRequest(ocsp, ocspRequest);
ret = CheckOcspRequest(ocsp, ocspRequest, encodedResponse);
FreeOcspRequest(ocspRequest);
}
@@ -186,7 +190,7 @@ static int GetOcspEntry(WOLFSSL_OCSP* ocsp, OcspRequest* request,
static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request,
OcspEntry* entry, CertStatus** status)
OcspEntry* entry, CertStatus** status, buffer* responseBuffer)
{
int ret = OCSP_INVALID_STATUS;
@@ -204,11 +208,27 @@ static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request,
&& !XMEMCMP((*status)->serial, request->serial, (*status)->serialSz))
break;
if (*status) {
if (responseBuffer && *status && !(*status)->rawOcspResponse) {
/* force fetching again */
ret = OCSP_INVALID_STATUS;
}
else if (*status) {
if (ValidateDate((*status)->thisDate, (*status)->thisDateFormat, BEFORE)
&& ((*status)->nextDate[0] != 0)
&& ValidateDate((*status)->nextDate, (*status)->nextDateFormat, AFTER))
ret = xstat2err((*status)->status);
if (responseBuffer) {
responseBuffer->buffer = (byte*)XMALLOC(
(*status)->rawOcspResponseSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (responseBuffer->buffer) {
responseBuffer->length = (*status)->rawOcspResponseSz;
XMEMCPY(responseBuffer->buffer,
(*status)->rawOcspResponse,
(*status)->rawOcspResponseSz);
}
}
}
UnLockMutex(&ocsp->ocspLock);
@@ -216,16 +236,18 @@ static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request,
return ret;
}
int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest)
int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest,
void* encodedResponse)
{
OcspEntry* entry = NULL;
CertStatus* status = NULL;
byte* request = NULL;
int requestSz = 2048;
byte* response = NULL;
const char* url;
int urlSz;
int ret = -1;
OcspEntry* entry = NULL;
CertStatus* status = NULL;
byte* request = NULL;
int requestSz = 2048;
byte* response = NULL;
buffer* responseBuffer = (buffer*) encodedResponse;
const char* url = NULL;
int urlSz = 0;
int ret = -1;
#ifdef WOLFSSL_SMALL_STACK
CertStatus* newStatus;
@@ -237,11 +259,16 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest)
WOLFSSL_ENTER("CheckOcspRequest");
if (responseBuffer) {
responseBuffer->buffer = NULL;
responseBuffer->length = 0;
}
ret = GetOcspEntry(ocsp, ocspRequest, &entry);
if (ret != 0)
return ret;
ret = GetOcspStatus(ocsp, ocspRequest, entry, &status);
ret = GetOcspStatus(ocsp, ocspRequest, entry, &status, responseBuffer);
if (ret != OCSP_INVALID_STATUS)
return ret;
@@ -300,14 +327,29 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest)
ret = OCSP_LOOKUP_FAIL;
else {
if (CompareOcspReqResp(ocspRequest, ocspResponse) == 0) {
if (responseBuffer) {
responseBuffer->buffer = (byte*)XMALLOC(ret, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (responseBuffer->buffer) {
responseBuffer->length = ret;
XMEMCPY(responseBuffer->buffer, response, ret);
}
}
ret = xstat2err(ocspResponse->status->status);
if (LockMutex(&ocsp->ocspLock) != 0)
ret = BAD_MUTEX_E;
else {
if (status != NULL)
if (status != NULL) {
if (status->rawOcspResponse)
XFREE(status->rawOcspResponse, NULL,
DYNAMIC_TYPE_OCSP_STATUS);
/* Replace existing certificate entry with updated */
XMEMCPY(status, newStatus, sizeof(CertStatus));
}
else {
/* Save new certificate entry */
status = (CertStatus*)XMALLOC(sizeof(CertStatus),
@@ -320,6 +362,19 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest)
}
}
if (responseBuffer && responseBuffer->buffer) {
status->rawOcspResponse = (byte*)XMALLOC(
responseBuffer->length, NULL,
DYNAMIC_TYPE_OCSP_STATUS);
if (status->rawOcspResponse) {
status->rawOcspResponseSz = responseBuffer->length;
XMEMCPY(status->rawOcspResponse,
responseBuffer->buffer,
responseBuffer->length);
}
}
UnLockMutex(&ocsp->ocspLock);
}
}

View File

@@ -1643,6 +1643,10 @@ void wolfSSL_CertManagerFree(WOLFSSL_CERT_MANAGER* cm)
#ifdef HAVE_OCSP
if (cm->ocsp)
FreeOCSP(cm->ocsp, 1);
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
if (cm->ocsp_stapling)
FreeOCSP(cm->ocsp_stapling, 1);
#endif
#endif
FreeSignerTable(cm->caTable, CA_TABLE_SIZE, NULL);
FreeMutex(&cm->caLock);
@@ -3460,6 +3464,42 @@ int wolfSSL_CertManagerDisableOCSP(WOLFSSL_CERT_MANAGER* cm)
return SSL_SUCCESS;
}
/* turn on OCSP Stapling if off and compiled in, set options */
int wolfSSL_CertManagerEnableOCSPStapling(WOLFSSL_CERT_MANAGER* cm)
{
int ret = SSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_CertManagerEnableOCSPStapling");
if (cm == NULL)
return BAD_FUNC_ARG;
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
if (cm->ocsp_stapling == NULL) {
cm->ocsp_stapling = (WOLFSSL_OCSP*)XMALLOC(sizeof(WOLFSSL_OCSP),
cm->heap, DYNAMIC_TYPE_OCSP);
if (cm->ocsp_stapling == NULL)
return MEMORY_E;
if (InitOCSP(cm->ocsp_stapling, cm) != 0) {
WOLFSSL_MSG("Init OCSP failed");
FreeOCSP(cm->ocsp_stapling, 1);
cm->ocsp_stapling = NULL;
return SSL_FAILURE;
}
}
cm->ocspStaplingEnabled = 1;
#ifndef WOLFSSL_USER_IO
cm->ocspIOCb = EmbedOcspLookup;
cm->ocspRespFreeCb = EmbedOcspRespFree;
#endif /* WOLFSSL_USER_IO */
#else
ret = NOT_COMPILED_IN;
#endif
return ret;
}
#ifdef HAVE_OCSP
@@ -3494,7 +3534,7 @@ int wolfSSL_CertManagerCheckOCSP(WOLFSSL_CERT_MANAGER* cm, byte* der, int sz)
if ((ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, cm)) != 0) {
WOLFSSL_MSG("ParseCert failed");
}
else if ((ret = CheckCertOCSP(cm->ocsp, cert)) != 0) {
else if ((ret = CheckCertOCSP(cm->ocsp, cert, NULL)) != 0) {
WOLFSSL_MSG("CheckCertOCSP failed");
}
@@ -3629,6 +3669,16 @@ int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb,
return BAD_FUNC_ARG;
}
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx)
{
WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling");
if (ctx)
return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm);
else
return BAD_FUNC_ARG;
}
#endif
#endif /* HAVE_OCSP */
@@ -6132,6 +6182,15 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
WOLFSSL_MSG("accept state CERT_SENT");
case CERT_SENT :
if (!ssl->options.resuming)
if ( (ssl->error = SendCertificateStatus(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
ssl->options.acceptState = CERT_STATUS_SENT;
WOLFSSL_MSG("accept state CERT_STATUS_SENT");
case CERT_STATUS_SENT :
if (!ssl->options.resuming)
if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);

View File

@@ -1891,11 +1891,6 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
#ifndef HAVE_OCSP
#error Status Request Extension requires OCSP. \
Use --enable-ocsp in the configure script or define HAVE_OCSP.
#endif
static void TLSX_CSR_Free(CertificateStatusRequest* csr)
{
switch (csr->status_type) {
@@ -1972,7 +1967,7 @@ static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output,
static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
int ret = 0;
int ret;
/* shut up compiler warnings */
(void) ssl; (void) input;
@@ -2019,8 +2014,56 @@ static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
#endif
}
else {
#ifndef NO_WOLFSSL_SERVER
byte status_type;
word16 offset = 0;
word16 size = 0;
return ret;
if (length < ENUM_LEN)
return BUFFER_ERROR;
status_type = input[offset++];
switch (status_type) {
case WOLFSSL_CSR_OCSP: {
/* skip responder_id_list */
if (length - offset < OPAQUE16_LEN)
return BUFFER_ERROR;
ato16(input + offset, &size);
offset += OPAQUE16_LEN + size;
/* skip request_extensions */
if (length - offset < OPAQUE16_LEN)
return BUFFER_ERROR;
ato16(input + offset, &size);
offset += OPAQUE16_LEN + size;
if (offset > length)
return BUFFER_ERROR;
/* is able to send OCSP response? */
if (ssl->ctx->cm == NULL || !ssl->ctx->cm->ocspStaplingEnabled)
return 0;
}
break;
}
ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
0);
if (ret != SSL_SUCCESS)
return ret; /* throw error */
TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
ssl->status_request = status_type;
#endif
}
return 0;
}
int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert)
@@ -2078,7 +2121,7 @@ int TLSX_CSR_ForceRequest(WOLFSSL* ssl)
case WOLFSSL_CSR_OCSP:
if (ssl->ctx->cm->ocspEnabled)
return CheckOcspRequest(ssl->ctx->cm->ocsp,
&csr->request.ocsp);
&csr->request.ocsp, NULL);
else
return OCSP_LOOKUP_FAIL;
}

View File

@@ -8776,20 +8776,13 @@ void InitOcspResponse(OcspResponse* resp, CertStatus* status,
{
WOLFSSL_ENTER("InitOcspResponse");
XMEMSET(status, 0, sizeof(CertStatus));
XMEMSET(resp, 0, sizeof(OcspResponse));
resp->responseStatus = -1;
resp->response = NULL;
resp->responseSz = 0;
resp->producedDateFormat = 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->status = status;
resp->source = source;
resp->maxIdx = inSz;
}

View File

@@ -1361,22 +1361,26 @@ struct WOLFSSL_CRL {
/* wolfSSL Certificate Manager */
struct WOLFSSL_CERT_MANAGER {
Signer* caTable[CA_TABLE_SIZE]; /* the CA signer table */
void* heap; /* heap helper */
WOLFSSL_CRL* crl; /* CRL checker */
WOLFSSL_OCSP* ocsp; /* OCSP checker */
char* ocspOverrideURL; /* use this responder */
void* ocspIOCtx; /* I/O callback CTX */
CallbackCACache caCacheCallback; /* CA cache addition callback */
CbMissingCRL cbMissingCRL; /* notify through cb of missing crl */
CbOCSPIO ocspIOCb; /* I/O callback for OCSP lookup */
CbOCSPRespFree ocspRespFreeCb; /* Frees OCSP Response from IO Cb */
wolfSSL_Mutex caLock; /* CA list lock */
byte crlEnabled; /* is CRL on ? */
byte crlCheckAll; /* always leaf, but all ? */
byte ocspEnabled; /* is OCSP on ? */
byte ocspCheckAll; /* always leaf, but all ? */
byte ocspSendNonce; /* send the OCSP nonce ? */
byte ocspUseOverrideURL; /* ignore cert's responder, override */
void* heap; /* heap helper */
WOLFSSL_CRL* crl; /* CRL checker */
WOLFSSL_OCSP* ocsp; /* OCSP checker */
#if !defined(NO_WOLFSSL_SEVER) && defined(HAVE_CERTIFICATE_STATUS_REQUEST)
WOLFSSL_OCSP* ocsp_stapling; /* OCSP checker for OCSP stapling */
#endif
char* ocspOverrideURL; /* use this responder */
void* ocspIOCtx; /* I/O callback CTX */
CallbackCACache caCacheCallback; /* CA cache addition callback */
CbMissingCRL cbMissingCRL; /* notify through cb of missing crl */
CbOCSPIO ocspIOCb; /* I/O callback for OCSP lookup */
CbOCSPRespFree ocspRespFreeCb; /* Frees OCSP Response from IO Cb */
wolfSSL_Mutex caLock; /* CA list lock */
byte crlEnabled; /* is CRL on ? */
byte crlCheckAll; /* always leaf, but all ? */
byte ocspEnabled; /* is OCSP on ? */
byte ocspCheckAll; /* always leaf, but all ? */
byte ocspSendNonce; /* send the OCSP nonce ? */
byte ocspUseOverrideURL; /* ignore cert's responder, override */
byte ocspStaplingEnabled; /* is OCSP Stapling on ? */
};
WOLFSSL_LOCAL int CM_SaveCertCache(WOLFSSL_CERT_MANAGER*, const char*);
@@ -2033,6 +2037,7 @@ enum AcceptState {
ACCEPT_FIRST_REPLY_DONE,
SERVER_HELLO_SENT,
CERT_SENT,
CERT_STATUS_SENT,
KEY_EXCHANGE_SENT,
CERT_REQ_SENT,
SERVER_HELLO_DONE,
@@ -2640,6 +2645,7 @@ WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32);
WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int);
WOLFSSL_LOCAL int SendCertificate(WOLFSSL*);
WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*);
WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*);
WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*);
WOLFSSL_LOCAL int SendBuffered(WOLFSSL*);
WOLFSSL_LOCAL int ReceiveData(WOLFSSL*, byte*, int, int);

View File

@@ -39,9 +39,9 @@ typedef struct WOLFSSL_OCSP WOLFSSL_OCSP;
WOLFSSL_LOCAL int InitOCSP(WOLFSSL_OCSP*, WOLFSSL_CERT_MANAGER*);
WOLFSSL_LOCAL void FreeOCSP(WOLFSSL_OCSP*, int dynamic);
WOLFSSL_LOCAL int CheckCertOCSP(WOLFSSL_OCSP*, DecodedCert*);
WOLFSSL_LOCAL int CheckCertOCSP(WOLFSSL_OCSP*, DecodedCert*, void*);
WOLFSSL_LOCAL int CheckOcspRequest(WOLFSSL_OCSP* ocsp,
OcspRequest* ocspRequest);
OcspRequest* ocspRequest, void*);
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -1269,6 +1269,9 @@ WOLFSSL_API void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER*,
CbOCSPIO, CbOCSPRespFree, void*);
WOLFSSL_API int wolfSSL_CertManagerEnableOCSPStapling(
WOLFSSL_CERT_MANAGER* cm);
WOLFSSL_API int wolfSSL_EnableCRL(WOLFSSL* ssl, int options);
WOLFSSL_API int wolfSSL_DisableCRL(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_LoadCRL(WOLFSSL*, const char*, int, int);
@@ -1287,6 +1290,8 @@ WOLFSSL_API void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX*, const char*);
WOLFSSL_API int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX*,
CbOCSPIO, CbOCSPRespFree, void*);
WOLFSSL_API int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX*);
#endif /* !NO_CERTS */
/* end of handshake frees temporary arrays, if user needs for get_keys or

View File

@@ -675,6 +675,9 @@ struct CertStatus {
byte nextDate[MAX_DATE_SIZE];
byte thisDateFormat;
byte nextDateFormat;
byte* rawOcspResponse;
word32 rawOcspResponseSz;
};