From 346dcb0fd9af585bb055e9b8a315b0beb838269a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 30 Nov 2015 21:26:00 -0300 Subject: [PATCH] adds WOLFSSL_CSR2_OCSP_MULTI support; --- src/internal.c | 268 +++++++++++++++++++++++++++++++++++++++------ src/tls.c | 59 ++++++---- wolfssl/internal.h | 7 +- 3 files changed, 274 insertions(+), 60 deletions(-) diff --git a/src/internal.c b/src/internal.c index b7fc15bdc..6b2d44459 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4393,7 +4393,13 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, #if defined(HAVE_OCSP) || defined(HAVE_CRL) if (ret == 0) { int doCrlLookup = 1; + #ifdef HAVE_OCSP + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + if (ssl->status_request_v2) + ret = TLSX_CSR2_InitRequests(ssl->extensions, dCert); + else /* skips OCSP and force CRL check */ + #endif if (ssl->ctx->cm->ocspEnabled && ssl->ctx->cm->ocspCheckAll) { WOLFSSL_MSG("Doing Non Leaf OCSP check"); ret = CheckCertOCSP(ssl->ctx->cm->ocsp, dCert, NULL); @@ -4406,7 +4412,7 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, #endif /* HAVE_OCSP */ #ifdef HAVE_CRL - if (doCrlLookup && ssl->ctx->cm->crlEnabled + if (ret == 0 && doCrlLookup && ssl->ctx->cm->crlEnabled && ssl->ctx->cm->crlCheckAll) { WOLFSSL_MSG("Doing Non Leaf CRL check"); ret = CheckCertCRL(ssl->ctx->cm->crl, dCert); @@ -4858,13 +4864,13 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, case WOLFSSL_CSR2_OCSP: { OcspRequest* request; - #ifdef WOLFSSL_SMALL_STACK - CertStatus* status; - OcspResponse* response; - #else - CertStatus status[1]; - OcspResponse response[1]; - #endif + #ifdef WOLFSSL_SMALL_STACK + CertStatus* status; + OcspResponse* response; + #else + CertStatus status[1]; + OcspResponse response[1]; + #endif do { #ifdef HAVE_CERTIFICATE_STATUS_REQUEST @@ -4878,7 +4884,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 if (ssl->status_request_v2) { request = TLSX_CSR2_GetRequest(ssl->extensions, - WOLFSSL_CSR2_OCSP); + status_type, 0); ssl->status_request_v2 = 0; break; } @@ -4890,19 +4896,21 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (request == NULL) return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */ - #ifdef WOLFSSL_SMALL_STACK - status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + #ifdef WOLFSSL_SMALL_STACK + status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, DYNAMIC_TYPE_TMP_BUFFER); - response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (status == NULL || response == NULL) { - if (status) XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (response) XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (status == NULL || response == NULL) { + if (status) + XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (response) + XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_ERROR; - } - #endif + return MEMORY_ERROR; + } + #endif InitOcspResponse(response, status, input +*inOutIdx, status_length); @@ -4914,13 +4922,109 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, *inOutIdx += status_length; - #ifdef WOLFSSL_SMALL_STACK - XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif + #ifdef WOLFSSL_SMALL_STACK + XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif } break; + + #endif + + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + + case WOLFSSL_CSR2_OCSP_MULTI: { + OcspRequest* request; + word32 list_length = status_length; + byte index = 0; + + #ifdef WOLFSSL_SMALL_STACK + CertStatus* status; + OcspResponse* response; + #else + CertStatus status[1]; + OcspResponse response[1]; + #endif + + do { + if (ssl->status_request_v2) { + ssl->status_request_v2 = 0; + break; + } + + return BUFFER_ERROR; + } while(0); + + #ifdef WOLFSSL_SMALL_STACK + status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (status == NULL || response == NULL) { + if (status) + XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (response) + XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return MEMORY_ERROR; + } + #endif + + while (list_length && ret == 0) { + if (OPAQUE24_LEN > list_length) { + ret = BUFFER_ERROR; + break; + } + + c24to32(input + *inOutIdx, &status_length); + *inOutIdx += OPAQUE24_LEN; + list_length -= OPAQUE24_LEN; + + if (status_length > list_length) { + ret = BUFFER_ERROR; + break; + } + + if (status_length) { + InitOcspResponse(response, status, input +*inOutIdx, + status_length); + + if ((OcspResponseDecode(response, ssl->ctx->cm) != 0) + || (response->responseStatus != OCSP_SUCCESSFUL) + || (response->status->status != CERT_GOOD)) + ret = BAD_CERTIFICATE_STATUS_ERROR; + + while (ret == 0) { + request = TLSX_CSR2_GetRequest(ssl->extensions, + status_type, index++); + + if (request == NULL) + ret = BAD_CERTIFICATE_STATUS_ERROR; + else if (CompareOcspReqResp(request, response) == 0) + break; + else if (index == 1) + ret = BAD_CERTIFICATE_STATUS_ERROR; + } + + *inOutIdx += status_length; + list_length -= status_length; + } + } + + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + ssl->status_request_v2 = 0; + #endif + + #ifdef WOLFSSL_SMALL_STACK + XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + + } + break; + #endif default: @@ -8417,7 +8521,10 @@ int SendCertificateStatus(WOLFSSL* ssl) #if defined HAVE_CERTIFICATE_STATUS_REQUEST_V2 case WOLFSSL_CSR2_OCSP_MULTI: { OcspRequest* request = ssl->ctx->certOcspRequest; - buffer response = {NULL, 0}; + buffer responses[1 + MAX_CHAIN_DEPTH]; + int i = 0; + + ForceZero(responses, sizeof(responses)); /* unable to fetch status. skip. */ if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0) @@ -8483,26 +8590,121 @@ int SendCertificateStatus(WOLFSSL* ssl) if (ret == 0) { ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request, - &response); + &responses[0]); /* Suppressing, not critical */ if (ret == OCSP_CERT_REVOKED || ret == OCSP_CERT_UNKNOWN || ret == OCSP_LOOKUP_FAIL) ret = 0; - - if (response.buffer) { - if (ret == 0) - ret = BuildCertificateStatus(ssl, status_type, - &response, 1); - - XFREE(response.buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - } if (request != ssl->ctx->certOcspRequest) XFREE(request, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + + if (ret == 0 && (!ssl->ctx->chainOcspRequest[0] + || ssl->buffers.weOwnCertChain)) { + buffer der = {NULL, 0}; + word32 idx = 0; + #ifdef WOLFSSL_SMALL_STACK + DecodedCert* cert = NULL; + #else + DecodedCert cert[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (cert == NULL) + return MEMORY_E; + #endif + + while (idx + OPAQUE24_LEN < ssl->buffers.certChain.length) { + c24to32(ssl->buffers.certChain.buffer + idx, &der.length); + idx += OPAQUE24_LEN; + + der.buffer = ssl->buffers.certChain.buffer + idx; + idx += der.length; + + if (idx > ssl->buffers.certChain.length) + break; + + InitDecodedCert(cert, der.buffer, der.length, NULL); + + if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, + ssl->ctx->cm)) != 0) { + WOLFSSL_MSG("ParseCert failed"); + break; + } + else { + request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), + NULL, DYNAMIC_TYPE_OCSP_REQUEST); + if (request == NULL) { + ret = MEMORY_E; + break; + } + + ret = InitOcspRequest(request, cert, 0); + if (ret != 0) { + XFREE(request, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + break; + } + else if (!ssl->buffers.weOwnCertChain && 0 == + LockMutex( + &ssl->ctx->cm->ocsp_stapling->ocspLock)) { + if (!ssl->ctx->chainOcspRequest[i]) + ssl->ctx->chainOcspRequest[i] = request; + + UnLockMutex( + &ssl->ctx->cm->ocsp_stapling->ocspLock); + } + + ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, + request, &responses[i + 1]); + + /* Suppressing, not critical */ + if (ret == OCSP_CERT_REVOKED + || ret == OCSP_CERT_UNKNOWN + || ret == OCSP_LOOKUP_FAIL) + ret = 0; + + if (request != ssl->ctx->chainOcspRequest[i]) + XFREE(request, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + + i++; + } + + FreeDecodedCert(cert); + } + + #ifdef WOLFSSL_SMALL_STACK + XFREE(cert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } + else { + while (ret == 0 && + NULL != (request = ssl->ctx->chainOcspRequest[i])) { + ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, + request, &responses[++i]); + + /* Suppressing, not critical */ + if (ret == OCSP_CERT_REVOKED + || ret == OCSP_CERT_UNKNOWN + || ret == OCSP_LOOKUP_FAIL) + ret = 0; + } + } + + if (responses[0].buffer) { + if (ret == 0) + ret = BuildCertificateStatus(ssl, status_type, + responses, i + 1); + + for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++) + if (responses[i].buffer) + XFREE(responses[i].buffer, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + } } break; diff --git a/src/tls.c b/src/tls.c index 177cb73f5..49bb8c4f9 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2211,7 +2211,8 @@ static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2) switch (csr2->status_type) { case WOLFSSL_CSR2_OCSP: case WOLFSSL_CSR2_OCSP_MULTI: - FreeOcspRequest(&csr2->request.ocsp); + while(csr2->requests--) + FreeOcspRequest(&csr2->request.ocsp[csr2->requests]); break; } @@ -2239,7 +2240,7 @@ static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2, case WOLFSSL_CSR2_OCSP_MULTI: size += ENUM_LEN + 3 * OPAQUE16_LEN; - if (csr2->request.ocsp.nonceSz) + if (csr2->request.ocsp[0].nonceSz) size += OCSP_NONCE_EXT_SZ; break; } @@ -2272,7 +2273,7 @@ static word16 TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2, /* request_length */ length = 2 * OPAQUE16_LEN; - if (csr2->request.ocsp.nonceSz) + if (csr2->request.ocsp[0].nonceSz) length += OCSP_NONCE_EXT_SZ; c16toa(length, output + offset); @@ -2285,9 +2286,9 @@ static word16 TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2, /* request extensions */ length = 0; - if (csr2->request.ocsp.nonceSz) + if (csr2->request.ocsp[0].nonceSz) length = EncodeOcspRequestExtensions( - &csr2->request.ocsp, + &csr2->request.ocsp[0], output + offset + OPAQUE16_LEN, OCSP_NONCE_EXT_SZ); @@ -2342,17 +2343,18 @@ static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length, /* followed by */ case WOLFSSL_CSR2_OCSP_MULTI: /* propagate nonce */ - if (csr2->request.ocsp.nonceSz) { + if (csr2->request.ocsp[0].nonceSz) { OcspRequest* request = TLSX_CSR2_GetRequest(ssl->extensions, - csr2->status_type); + csr2->status_type, 0); if (request) { XMEMCPY(request->nonce, - csr2->request.ocsp.nonce, - csr2->request.ocsp.nonceSz); + csr2->request.ocsp[0].nonce, + csr2->request.ocsp[0].nonceSz); - request->nonceSz = csr2->request.ocsp.nonceSz; + request->nonceSz = + csr2->request.ocsp[0].nonceSz; } } break; @@ -2456,21 +2458,29 @@ int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert) for (; csr2; csr2 = csr2->next) { switch (csr2->status_type) { case WOLFSSL_CSR2_OCSP: + if (csr2->requests != 0) + break; + /* followed by */ case WOLFSSL_CSR2_OCSP_MULTI: { - byte nonce[MAX_OCSP_NONCE_SZ]; - int nonceSz = csr2->request.ocsp.nonceSz; + if (csr2->requests < 1 + MAX_CHAIN_DEPTH) { + byte nonce[MAX_OCSP_NONCE_SZ]; + int nonceSz = csr2->request.ocsp[0].nonceSz; - /* preserve nonce */ - XMEMCPY(nonce, csr2->request.ocsp.nonce, nonceSz); + /* preserve nonce, replicating nonce of ocsp[0] */ + XMEMCPY(nonce, csr2->request.ocsp[0].nonce, nonceSz); - if ((ret = InitOcspRequest(&csr2->request.ocsp, cert, 0)) != 0) - return ret; + if ((ret = InitOcspRequest( + &csr2->request.ocsp[csr2->requests], cert, 0)) != 0) + return ret; - /* restore nonce */ - XMEMCPY(csr2->request.ocsp.nonce, nonce, nonceSz); - csr2->request.ocsp.nonceSz = nonceSz; + /* restore nonce */ + XMEMCPY(csr2->request.ocsp[csr2->requests].nonce, + nonce, nonceSz); + csr2->request.ocsp[csr2->requests].nonceSz = nonceSz; + csr2->requests++; + } } break; } @@ -2479,7 +2489,7 @@ int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert) return ret; } -void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type) +void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type, byte index) { TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2); CertificateStatusRequestItemV2* csr2 = extension ? extension->data : NULL; @@ -2491,7 +2501,8 @@ void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type) /* followed by */ case WOLFSSL_CSR2_OCSP_MULTI: - return &csr2->request.ocsp; + return index < csr2->requests ? &csr2->request.ocsp[index] + : NULL; break; } } @@ -2514,7 +2525,7 @@ int TLSX_CSR2_ForceRequest(WOLFSSL* ssl) case WOLFSSL_CSR2_OCSP_MULTI: if (ssl->ctx->cm->ocspEnabled) return CheckOcspRequest(ssl->ctx->cm->ocsp, - &csr2->request.ocsp, NULL); + &csr2->request.ocsp[0], NULL); else return OCSP_LOOKUP_FAIL; } @@ -2555,9 +2566,9 @@ int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type, WC_RNG rng; if (wc_InitRng(&rng) == 0) { - if (wc_RNG_GenerateBlock(&rng, csr2->request.ocsp.nonce, + if (wc_RNG_GenerateBlock(&rng, csr2->request.ocsp[0].nonce, MAX_OCSP_NONCE_SZ) == 0) - csr2->request.ocsp.nonceSz = MAX_OCSP_NONCE_SZ; + csr2->request.ocsp[0].nonceSz = MAX_OCSP_NONCE_SZ; wc_FreeRng(&rng); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9e592fb26..87d5247bc 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1603,9 +1603,9 @@ WOLFSSL_LOCAL int TLSX_CSR_ForceRequest(WOLFSSL* ssl); typedef struct CSRIv2 { byte status_type; byte options; - word16 request_length; + word16 requests; union { - OcspRequest ocsp; + OcspRequest ocsp[1 + MAX_CHAIN_DEPTH]; } request; struct CSRIv2* next; } CertificateStatusRequestItemV2; @@ -1613,7 +1613,8 @@ typedef struct CSRIv2 { WOLFSSL_LOCAL int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type, byte options); WOLFSSL_LOCAL int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert); -WOLFSSL_LOCAL void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type); +WOLFSSL_LOCAL void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type, + byte index); WOLFSSL_LOCAL int TLSX_CSR2_ForceRequest(WOLFSSL* ssl); #endif