diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c | 1105 |
1 files changed, 951 insertions, 154 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c b/FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c index 1794d6317..b5a27197e 100644 --- a/FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c +++ b/FreeRTOS-Plus/Source/WolfSSL/src/ocsp.c @@ -1,8 +1,8 @@ /* ocsp.c * - * Copyright (C) 2006-2015 wolfSSL Inc. + * Copyright (C) 2006-2020 wolfSSL Inc. * - * This file is part of wolfSSL. (formerly known as CyaSSL) + * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,9 +16,10 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ + /* Name change compatibility layer no longer needs to be included here */ #ifdef HAVE_CONFIG_H @@ -27,73 +28,91 @@ #include <wolfssl/wolfcrypt/settings.h> +#ifndef WOLFCRYPT_ONLY #ifdef HAVE_OCSP #include <wolfssl/error-ssl.h> #include <wolfssl/ocsp.h> #include <wolfssl/internal.h> +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif + int InitOCSP(WOLFSSL_OCSP* ocsp, WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("InitOCSP"); - XMEMSET(ocsp, 0, sizeof(*ocsp)); - ocsp->cm = cm; - if (InitMutex(&ocsp->ocspLock) != 0) + + ForceZero(ocsp, sizeof(WOLFSSL_OCSP)); + + if (wc_InitMutex(&ocsp->ocspLock) != 0) return BAD_MUTEX_E; + ocsp->cm = cm; + return 0; } -static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert) +static int InitOcspEntry(OcspEntry* entry, OcspRequest* request) { - WOLFSSL_ENTER("InitOCSP_Entry"); + WOLFSSL_ENTER("InitOcspEntry"); - XMEMSET(ocspe, 0, sizeof(*ocspe)); - XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE); - XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE); + ForceZero(entry, sizeof(OcspEntry)); + + XMEMCPY(entry->issuerHash, request->issuerHash, OCSP_DIGEST_SIZE); + XMEMCPY(entry->issuerKeyHash, request->issuerKeyHash, OCSP_DIGEST_SIZE); return 0; } -static void FreeOCSP_Entry(OCSP_Entry* ocspe) +static void FreeOcspEntry(OcspEntry* entry, void* heap) { - CertStatus* tmp = ocspe->status; + CertStatus *status, *next; + + WOLFSSL_ENTER("FreeOcspEntry"); - WOLFSSL_ENTER("FreeOCSP_Entry"); + for (status = entry->status; status; status = next) { + next = status->next; - while (tmp) { - CertStatus* next = tmp->next; - XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS); - tmp = next; + if (status->rawOcspResponse) + XFREE(status->rawOcspResponse, heap, DYNAMIC_TYPE_OCSP_STATUS); + + XFREE(status, heap, DYNAMIC_TYPE_OCSP_STATUS); } + + (void)heap; } void FreeOCSP(WOLFSSL_OCSP* ocsp, int dynamic) { - OCSP_Entry* tmp = ocsp->ocspList; + OcspEntry *entry, *next; WOLFSSL_ENTER("FreeOCSP"); - while (tmp) { - OCSP_Entry* next = tmp->next; - FreeOCSP_Entry(tmp); - XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY); - tmp = next; + for (entry = ocsp->ocspList; entry; entry = next) { + next = entry->next; + FreeOcspEntry(entry, ocsp->cm->heap); + XFREE(entry, ocsp->cm->heap, DYNAMIC_TYPE_OCSP_ENTRY); } - FreeMutex(&ocsp->ocspLock); + wc_FreeMutex(&ocsp->ocspLock); + if (dynamic) - XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP); + XFREE(ocsp, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); + } -static int xstat2err(int stat) +static int xstat2err(int st) { - switch (stat) { + switch (st) { case CERT_GOOD: return 0; case CERT_REVOKED: @@ -103,86 +122,323 @@ static int xstat2err(int stat) } } - -int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert) +int CheckCertOCSP_ex(WOLFSSL_OCSP* ocsp, DecodedCert* cert, buffer* responseBuffer, WOLFSSL* ssl) { - byte* ocspReqBuf = NULL; - int ocspReqSz = 2048; - byte* ocspRespBuf = NULL; - int result = -1; - OCSP_Entry* ocspe; - CertStatus* certStatus = NULL; - const char *url; - int urlSz; + int ret = OCSP_LOOKUP_FAIL; + #ifdef WOLFSSL_SMALL_STACK - CertStatus* newStatus; OcspRequest* ocspRequest; - OcspResponse* ocspResponse; #else - CertStatus newStatus[1]; OcspRequest ocspRequest[1]; - OcspResponse ocspResponse[1]; #endif WOLFSSL_ENTER("CheckCertOCSP"); - if (LockMutex(&ocsp->ocspLock) != 0) { + +#ifdef WOLFSSL_SMALL_STACK + ocspRequest = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (ocspRequest == NULL) { + WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + return MEMORY_E; + } +#endif + + if (InitOcspRequest(ocspRequest, cert, ocsp->cm->ocspSendNonce, + ocsp->cm->heap) == 0) { + ocspRequest->ssl = ssl; + ret = CheckOcspRequest(ocsp, ocspRequest, responseBuffer); + + FreeOcspRequest(ocspRequest); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(ocspRequest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + WOLFSSL_LEAVE("CheckCertOCSP", ret); + return ret; +} +int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert, buffer* responseBuffer) +{ + return CheckCertOCSP_ex(ocsp, cert, responseBuffer, NULL); +} + +static int GetOcspEntry(WOLFSSL_OCSP* ocsp, OcspRequest* request, + OcspEntry** entry) +{ + WOLFSSL_ENTER("GetOcspEntry"); + + *entry = NULL; + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { WOLFSSL_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) + for (*entry = ocsp->ocspList; *entry; *entry = (*entry)->next) + if (XMEMCMP((*entry)->issuerHash, request->issuerHash, + OCSP_DIGEST_SIZE) == 0 + && XMEMCMP((*entry)->issuerKeyHash, request->issuerKeyHash, + OCSP_DIGEST_SIZE) == 0) break; - else - ocspe = ocspe->next; + + if (*entry == NULL) { + *entry = (OcspEntry*)XMALLOC(sizeof(OcspEntry), + ocsp->cm->heap, DYNAMIC_TYPE_OCSP_ENTRY); + if (*entry) { + InitOcspEntry(*entry, request); + (*entry)->next = ocsp->ocspList; + ocsp->ocspList = *entry; + } } - if (ocspe == NULL) { - 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; + wc_UnLockMutex(&ocsp->ocspLock); + + return *entry ? 0 : MEMORY_ERROR; +} + + +/* Mallocs responseBuffer->buffer and is up to caller to free on success + * + * Returns OCSP status + */ +static int GetOcspStatus(WOLFSSL_OCSP* ocsp, OcspRequest* request, + OcspEntry* entry, CertStatus** status, buffer* responseBuffer) +{ + int ret = OCSP_INVALID_STATUS; + + WOLFSSL_ENTER("GetOcspStatus"); + + *status = NULL; + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { + WOLFSSL_LEAVE("CheckCertOCSP", BAD_MUTEX_E); + return BAD_MUTEX_E; + } + + for (*status = entry->status; *status; *status = (*status)->next) + if ((*status)->serialSz == request->serialSz + && !XMEMCMP((*status)->serial, request->serial, (*status)->serialSz)) + break; + + if (responseBuffer && *status && !(*status)->rawOcspResponse) { + /* force fetching again */ + ret = OCSP_INVALID_STATUS; + } + else if (*status) { +#ifndef NO_ASN_TIME + if (XVALIDATE_DATE((*status)->thisDate, + (*status)->thisDateFormat, BEFORE) + && ((*status)->nextDate[0] != 0) + && XVALIDATE_DATE((*status)->nextDate, + (*status)->nextDateFormat, AFTER)) +#endif + { + 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); + } + } } - else { - UnLockMutex(&ocsp->ocspLock); - WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); - return MEMORY_ERROR; + } + + wc_UnLockMutex(&ocsp->ocspLock); + + return ret; +} + +/* Check that the response for validity. Store result in status. + * + * ocsp Context object for OCSP status. + * response OCSP response message data. + * responseSz Length of OCSP response message data. + * reponseBuffer Buffer object to return the response with. + * status The certificate status object. + * entry The OCSP entry for this certificate. + * returns OCSP_LOOKUP_FAIL when the response is bad and 0 otherwise. + */ +WOLFSSL_LOCAL int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz, + WOLFSSL_BUFFER_INFO *responseBuffer, CertStatus *status, + OcspEntry *entry, OcspRequest *ocspRequest) +{ +#ifdef WOLFSSL_SMALL_STACK + CertStatus* newStatus; + OcspResponse* ocspResponse; +#else + CertStatus newStatus[1]; + OcspResponse ocspResponse[1]; +#endif + int ret; + int validated = 0; /* ocsp validation flag */ + +#ifdef WOLFSSL_SMALL_STACK + newStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ocspResponse = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + + if (newStatus == NULL || ocspResponse == NULL) { + if (newStatus) XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + return MEMORY_E; + } +#endif + XMEMSET(newStatus, 0, sizeof(CertStatus)); + + InitOcspResponse(ocspResponse, newStatus, response, responseSz); + ret = OcspResponseDecode(ocspResponse, ocsp->cm, ocsp->cm->heap, 0); + if (ret != 0) { + ocsp->error = ret; + WOLFSSL_LEAVE("OcspResponseDecode failed", ocsp->error); + goto end; + } + + if (ocspResponse->responseStatus != OCSP_SUCCESSFUL) { + WOLFSSL_MSG("OcspResponse status bad"); + goto end; + } + if (ocspRequest != NULL) { + ret = CompareOcspReqResp(ocspRequest, ocspResponse); + if (ret != 0) { + goto end; } } - else { - certStatus = ocspe->status; - while (certStatus) { - if (certStatus->serialSz == cert->serialSz && - XMEMCMP(certStatus->serial, cert->serial, cert->serialSz) == 0) - break; - else - certStatus = certStatus->next; + + if (responseBuffer) { + responseBuffer->buffer = (byte*)XMALLOC(responseSz, ocsp->cm->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (responseBuffer->buffer) { + responseBuffer->length = responseSz; + XMEMCPY(responseBuffer->buffer, response, responseSz); } } - if (certStatus != NULL) { - if (!ValidateDate(certStatus->thisDate, - certStatus->thisDateFormat, BEFORE) || - (certStatus->nextDate[0] == 0) || - !ValidateDate(certStatus->nextDate, - certStatus->nextDateFormat, AFTER)) { - WOLFSSL_MSG("\tinvalid status date, looking up cert"); + ret = xstat2err(ocspResponse->status->status); + if (ret == 0) { + validated = 1; + } + + if (wc_LockMutex(&ocsp->ocspLock) != 0) { + ret = BAD_MUTEX_E; + goto end; + } + + if (status != NULL) { + if (status->rawOcspResponse) { + XFREE(status->rawOcspResponse, ocsp->cm->heap, + DYNAMIC_TYPE_OCSP_STATUS); } - else { - result = xstat2err(certStatus->status); - UnLockMutex(&ocsp->ocspLock); - WOLFSSL_LEAVE("CheckCertOCSP", result); - return result; + + /* Replace existing certificate entry with updated */ + newStatus->next = status->next; + XMEMCPY(status, newStatus, sizeof(CertStatus)); + } + else { + /* Save new certificate entry */ + status = (CertStatus*)XMALLOC(sizeof(CertStatus), + ocsp->cm->heap, DYNAMIC_TYPE_OCSP_STATUS); + if (status != NULL) { + XMEMCPY(status, newStatus, sizeof(CertStatus)); + status->next = entry->status; + entry->status = status; + entry->totalStatus++; } } - UnLockMutex(&ocsp->ocspLock); + if (status && responseBuffer && responseBuffer->buffer) { + status->rawOcspResponse = (byte*)XMALLOC(responseBuffer->length, + ocsp->cm->heap, + DYNAMIC_TYPE_OCSP_STATUS); + + if (status->rawOcspResponse) { + status->rawOcspResponseSz = responseBuffer->length; + XMEMCPY(status->rawOcspResponse, responseBuffer->buffer, + responseBuffer->length); + } + } + + wc_UnLockMutex(&ocsp->ocspLock); + +end: + if (ret == 0 && validated == 1) { + WOLFSSL_MSG("New OcspResponse validated"); + } else if (ret != OCSP_CERT_REVOKED) { + ret = OCSP_LOOKUP_FAIL; + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; +} + +/* 0 on success */ +int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest, + buffer* responseBuffer) +{ + OcspEntry* entry = NULL; + CertStatus* status = NULL; + byte* request = NULL; + int requestSz = 2048; + int responseSz = 0; + byte* response = NULL; + const char* url = NULL; + int urlSz = 0; + int ret = -1; + WOLFSSL* ssl; + void* ioCtx; + + WOLFSSL_ENTER("CheckOcspRequest"); + + if (ocsp == NULL || ocspRequest == NULL) + return BAD_FUNC_ARG; + + if (responseBuffer) { + responseBuffer->buffer = NULL; + responseBuffer->length = 0; + } + + ret = GetOcspEntry(ocsp, ocspRequest, &entry); + if (ret != 0) + return ret; + + ret = GetOcspStatus(ocsp, ocspRequest, entry, &status, responseBuffer); + if (ret != OCSP_INVALID_STATUS) + return ret; + + /* get SSL and IOCtx */ + ssl = (WOLFSSL*)ocspRequest->ssl; + ioCtx = (ssl && ssl->ocspIOCtx != NULL) ? + ssl->ocspIOCtx : ocsp->cm->ocspIOCtx; + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) + if (ocsp->statusCb != NULL && ssl != NULL) { + ret = ocsp->statusCb(ssl, ioCtx); + if (ret == 0) { + ret = wolfSSL_get_ocsp_response(ssl, &response); + ret = CheckOcspResponse(ocsp, response, ret, responseBuffer, status, + entry, NULL); + if (response != NULL) + XFREE(response, NULL, DYNAMIC_TYPE_OPENSSL); + return ret; + } + WOLFSSL_LEAVE("CheckOcspRequest", ocsp->error); + return OCSP_LOOKUP_FAIL; + } +#endif if (ocsp->cm->ocspUseOverrideURL) { url = ocsp->cm->ocspOverrideURL; @@ -191,104 +447,645 @@ int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert) else return OCSP_NEED_URL; } - else if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) { - url = (const char *)cert->extAuthInfo; - urlSz = cert->extAuthInfoSz; + else if (ocspRequest->urlSz != 0 && ocspRequest->url != NULL) { + url = (const char *)ocspRequest->url; + urlSz = ocspRequest->urlSz; } else { /* cert doesn't have extAuthInfo, assuming CERT_GOOD */ return 0; } - ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER); - if (ocspReqBuf == NULL) { + request = (byte*)XMALLOC(requestSz, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); + if (request == NULL) { WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); + if (responseBuffer) { + XFREE(responseBuffer->buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + responseBuffer->buffer = NULL; + } return MEMORY_ERROR; } -#ifdef WOLFSSL_SMALL_STACK - newStatus = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - ocspRequest = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - ocspResponse = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, - DYNAMIC_TYPE_TMP_BUFFER); + requestSz = EncodeOcspRequest(ocspRequest, request, requestSz); + if (requestSz > 0 && ocsp->cm->ocspIOCb) { + responseSz = ocsp->cm->ocspIOCb(ioCtx, url, urlSz, + request, requestSz, &response); + } + if (responseSz == WOLFSSL_CBIO_ERR_WANT_READ) { + ret = OCSP_WANT_READ; + } - if (newStatus == NULL || ocspRequest == NULL || ocspResponse == NULL) { - if (newStatus) XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (ocspRequest) XFREE(ocspRequest, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (ocspResponse) XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(request, ocsp->cm->heap, DYNAMIC_TYPE_OCSP); - XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (responseSz >= 0 && response) { + ret = CheckOcspResponse(ocsp, response, responseSz, responseBuffer, status, + entry, ocspRequest); + } - WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR); - return MEMORY_E; + if (response != NULL && ocsp->cm->ocspRespFreeCb) + ocsp->cm->ocspRespFreeCb(ioCtx, response); + + /* Keep responseBuffer in the case of getting to response check. Caller + * should free responseBuffer after checking OCSP return value in "ret" */ + WOLFSSL_LEAVE("CheckOcspRequest", ret); + return ret; +} + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_APACHE_HTTPD) + +int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs, + WOLFSSL_OCSP_CERTID* id, int* status, int* reason, + WOLFSSL_ASN1_TIME** revtime, WOLFSSL_ASN1_TIME** thisupd, + WOLFSSL_ASN1_TIME** nextupd) +{ + if (bs == NULL || id == NULL) + return WOLFSSL_FAILURE; + + /* Only supporting one certificate status in asn.c. */ + if (CompareOcspReqResp(id, bs) != 0) + return WOLFSSL_FAILURE; + + if (status != NULL) + *status = bs->status->status; + if (thisupd != NULL) + *thisupd = &bs->status->thisDateParsed; + if (nextupd != NULL) + *nextupd = &bs->status->nextDateParsed; + + /* TODO: Not needed for Nginx. */ + if (reason != NULL) + *reason = 0; + if (revtime != NULL) + *revtime = NULL; + + return WOLFSSL_SUCCESS; +} + +const char *wolfSSL_OCSP_cert_status_str(long s) +{ + switch (s) { + case CERT_GOOD: + return "good"; + case CERT_REVOKED: + return "revoked"; + case CERT_UNKNOWN: + return "unknown"; + default: + return "(UNKNOWN)"; } -#endif +} + +int wolfSSL_OCSP_check_validity(WOLFSSL_ASN1_TIME* thisupd, + WOLFSSL_ASN1_TIME* nextupd, long sec, long maxsec) +{ + (void)thisupd; + (void)nextupd; + (void)sec; + (void)maxsec; + /* Dates validated in DecodeSingleResponse. */ + return WOLFSSL_SUCCESS; +} + +void wolfSSL_OCSP_CERTID_free(WOLFSSL_OCSP_CERTID* certId) +{ + FreeOcspRequest(certId); + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); +} + +WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_cert_to_id( + const WOLFSSL_EVP_MD *dgst, const WOLFSSL_X509 *subject, + const WOLFSSL_X509 *issuer) +{ + WOLFSSL_OCSP_CERTID* certId; + DecodedCert cert; + WOLFSSL_CERT_MANAGER* cm; + int ret; + DerBuffer* derCert = NULL; - InitOcspRequest(ocspRequest, cert, ocsp->cm->ocspSendNonce, - ocspReqBuf, ocspReqSz); - ocspReqSz = EncodeOcspRequest(ocspRequest); - - if (ocsp->cm->ocspIOCb) - result = ocsp->cm->ocspIOCb(ocsp->cm->ocspIOCtx, url, urlSz, - ocspReqBuf, ocspReqSz, &ocspRespBuf); - - if (result >= 0 && ocspRespBuf) { - XMEMSET(newStatus, 0, sizeof(CertStatus)); - - InitOcspResponse(ocspResponse, newStatus, ocspRespBuf, result); - OcspResponseDecode(ocspResponse); - - if (ocspResponse->responseStatus != OCSP_SUCCESSFUL) - result = OCSP_LOOKUP_FAIL; + (void)dgst; + + cm = wolfSSL_CertManagerNew(); + if (cm == NULL) + return NULL; + + ret = AllocDer(&derCert, issuer->derCert->length, + issuer->derCert->type, NULL); + if (ret == 0) { + /* AddCA() frees the buffer. */ + XMEMCPY(derCert->buffer, issuer->derCert->buffer, + issuer->derCert->length); + AddCA(cm, &derCert, WOLFSSL_USER_CA, 1); + } + + certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), NULL, + DYNAMIC_TYPE_OPENSSL); + if (certId != NULL) { + InitDecodedCert(&cert, subject->derCert->buffer, + subject->derCert->length, NULL); + if (ParseCertRelative(&cert, CERT_TYPE, VERIFY_OCSP, cm) != 0) { + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); + certId = NULL; + } else { - if (CompareOcspReqResp(ocspRequest, ocspResponse) == 0) { - 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); - } + ret = InitOcspRequest(certId, &cert, 0, NULL); + if (ret != 0) { + XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); + certId = NULL; } - else - result = OCSP_LOOKUP_FAIL; } + FreeDecodedCert(&cert); } + + wolfSSL_CertManagerFree(cm); + + return certId; +} + +void wolfSSL_OCSP_BASICRESP_free(WOLFSSL_OCSP_BASICRESP* basicResponse) +{ + wolfSSL_OCSP_RESPONSE_free(basicResponse); +} + +/* Signature verified in DecodeBasicOcspResponse. + * But no store available to verify certificate. */ +int wolfSSL_OCSP_basic_verify(WOLFSSL_OCSP_BASICRESP *bs, + WOLF_STACK_OF(WOLFSSL_X509) *certs, WOLFSSL_X509_STORE *st, unsigned long flags) +{ + DecodedCert cert; + int ret = WOLFSSL_SUCCESS; + + (void)certs; + + if (flags & OCSP_NOVERIFY) + return WOLFSSL_SUCCESS; + +#ifdef OPENSSL_EXTRA + if (bs->verifyError != OCSP_VERIFY_ERROR_NONE) + return WOLFSSL_FAILURE; +#endif + + InitDecodedCert(&cert, bs->cert, bs->certSz, NULL); + if (ParseCertRelative(&cert, CERT_TYPE, VERIFY, st->cm) < 0) + ret = WOLFSSL_FAILURE; + FreeDecodedCert(&cert); + + return ret; +} + +void wolfSSL_OCSP_RESPONSE_free(OcspResponse* response) +{ + if (response->status != NULL) + XFREE(response->status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (response->source != NULL) + XFREE(response->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(response, NULL, DYNAMIC_TYPE_OPENSSL); +} + +OcspResponse* wolfSSL_d2i_OCSP_RESPONSE_bio(WOLFSSL_BIO* bio, + OcspResponse** response) +{ + byte* data; + byte* p; + int len; + int dataAlloced = 0; + OcspResponse* ret = NULL; + + if (bio == NULL) + return NULL; + + if (bio->type == WOLFSSL_BIO_MEMORY) { + len = wolfSSL_BIO_get_mem_data(bio, &data); + if (len <= 0 || data == NULL) { + return NULL; + } + } +#ifndef NO_FILESYSTEM + else if (bio->type == WOLFSSL_BIO_FILE) { + long fcur; + long flen; + + if (bio->ptr == NULL) + return NULL; + + fcur = XFTELL((XFILE)bio->ptr); + if (fcur < 0) + return NULL; + if(XFSEEK((XFILE)bio->ptr, 0, SEEK_END) != 0) + return NULL; + flen = XFTELL((XFILE)bio->ptr); + if (flen < 0) + return NULL; + if (XFSEEK((XFILE)bio->ptr, fcur, SEEK_SET) != 0) + return NULL; + + /* check calculated length */ + fcur = flen - fcur; + if (fcur > MAX_WOLFSSL_FILE_SIZE || fcur <= 0) + return NULL; + + data = (byte*)XMALLOC(fcur, 0, DYNAMIC_TYPE_TMP_BUFFER); + if (data == NULL) + return NULL; + dataAlloced = 1; + + len = wolfSSL_BIO_read(bio, (char *)data, (int)flen); + } +#endif else - result = OCSP_LOOKUP_FAIL; + return NULL; + + if (len > 0) { + p = data; + ret = wolfSSL_d2i_OCSP_RESPONSE(response, (const unsigned char **)&p, + len); + } - XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_BUFFER); + if (dataAlloced) + XFREE(data, 0, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(newStatus, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(ocspRequest, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(ocspResponse, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, + const unsigned char** data, int len) +{ + OcspResponse *resp = NULL; + word32 idx = 0; + int length = 0; + + if (data == NULL) + return NULL; + + if (response != NULL) + resp = *response; + if (resp == NULL) { + resp = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL, + DYNAMIC_TYPE_OPENSSL); + if (resp == NULL) + return NULL; + XMEMSET(resp, 0, sizeof(OcspResponse)); + } + + resp->source = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (resp->source == NULL) { + XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + resp->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (resp->status == NULL) { + XFREE(resp->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(resp, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + XMEMCPY(resp->source, *data, len); + resp->maxIdx = len; + + if (OcspResponseDecode(resp, NULL, NULL, 1) != 0) { + wolfSSL_OCSP_RESPONSE_free(resp); + return NULL; + } + + if (GetSequence(*data, &idx, &length, len) >= 0) + (*data) += idx + length; + + return resp; +} + +int wolfSSL_i2d_OCSP_RESPONSE(OcspResponse* response, + unsigned char** data) +{ + if (data == NULL) + return response->maxIdx; + + XMEMCPY(*data, response->source, response->maxIdx); + return response->maxIdx; +} + +int wolfSSL_OCSP_response_status(OcspResponse *response) +{ + return response->responseStatus; +} + +const char *wolfSSL_OCSP_response_status_str(long s) +{ + switch (s) { + case OCSP_SUCCESSFUL: + return "successful"; + case OCSP_MALFORMED_REQUEST: + return "malformedrequest"; + case OCSP_INTERNAL_ERROR: + return "internalerror"; + case OCSP_TRY_LATER: + return "trylater"; + case OCSP_SIG_REQUIRED: + return "sigrequired"; + case OCSP_UNAUTHROIZED: + return "unauthorized"; + default: + return "(UNKNOWN)"; + } +} + +WOLFSSL_OCSP_BASICRESP* wolfSSL_OCSP_response_get1_basic(OcspResponse* response) +{ + WOLFSSL_OCSP_BASICRESP* bs; + + bs = (WOLFSSL_OCSP_BASICRESP*)XMALLOC(sizeof(WOLFSSL_OCSP_BASICRESP), NULL, + DYNAMIC_TYPE_OPENSSL); + if (bs == NULL) + return NULL; + + XMEMCPY(bs, response, sizeof(OcspResponse)); + bs->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + bs->source = (byte*)XMALLOC(bs->maxIdx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (bs->status == NULL || bs->source == NULL) { + if (bs->status) XFREE(bs->status, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (bs->source) XFREE(bs->source, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_OCSP_RESPONSE_free(bs); + bs = NULL; + } + else { + XMEMCPY(bs->status, response->status, sizeof(CertStatus)); + XMEMCPY(bs->source, response->source, response->maxIdx); + } + return bs; +} + +OcspRequest* wolfSSL_OCSP_REQUEST_new(void) +{ + OcspRequest* request; + + request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), NULL, + DYNAMIC_TYPE_OPENSSL); + if (request != NULL) + XMEMSET(request, 0, sizeof(OcspRequest)); + + return request; +} + +void wolfSSL_OCSP_REQUEST_free(OcspRequest* request) +{ + FreeOcspRequest(request); + XFREE(request, NULL, DYNAMIC_TYPE_OPENSSL); +} + +int wolfSSL_i2d_OCSP_REQUEST(OcspRequest* request, unsigned char** data) +{ + int size; + + size = EncodeOcspRequest(request, NULL, 0); + if (size <= 0 || data == NULL) + return size; + + return EncodeOcspRequest(request, *data, size); +} + +WOLFSSL_OCSP_ONEREQ* wolfSSL_OCSP_request_add0_id(OcspRequest *req, + WOLFSSL_OCSP_CERTID *cid) +{ + if (req == NULL || cid == NULL) + return NULL; + + FreeOcspRequest(req); + XMEMCPY(req, cid, sizeof(OcspRequest)); + + if (cid->serial != NULL) { + req->serial = (byte*)XMALLOC(cid->serialSz, NULL, + DYNAMIC_TYPE_OCSP_REQUEST); + req->url = (byte*)XMALLOC(cid->urlSz, NULL, DYNAMIC_TYPE_OCSP_REQUEST); + if (req->serial == NULL || req->url == NULL) { + FreeOcspRequest(req); + return NULL; + } + + XMEMCPY(req->serial, cid->serial, cid->serialSz); + XMEMCPY(req->url, cid->url, cid->urlSz); + } + + wolfSSL_OCSP_REQUEST_free(cid); + + return req; +} + +WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_CERTID_dup(WOLFSSL_OCSP_CERTID* id) +{ + WOLFSSL_OCSP_CERTID* certId; + + if (id == NULL) { + return NULL; + } + + certId = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), + id->heap, DYNAMIC_TYPE_OPENSSL); + if (certId) { + XMEMCPY(certId, id, sizeof(WOLFSSL_OCSP_CERTID)); + } + return certId; +} #endif - if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb) - ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf); +#if defined(OPENSSL_ALL) || defined(APACHE_HTTPD) +int wolfSSL_i2d_OCSP_REQUEST_bio(WOLFSSL_BIO* out, + WOLFSSL_OCSP_REQUEST *req) +{ + int size = -1; + unsigned char* data = NULL; + + WOLFSSL_ENTER("wolfSSL_i2d_OCSP_REQUEST_bio"); + if (out == NULL || req == NULL) + return WOLFSSL_FAILURE; + + size = wolfSSL_i2d_OCSP_REQUEST(req, NULL); + if (size > 0) { + data = (unsigned char*) XMALLOC(size, out->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } + + if (data != NULL) { + size = wolfSSL_i2d_OCSP_REQUEST(req, &data); + } + + if (size <= 0) { + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(out, data, size) == (int)size) { + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } - WOLFSSL_LEAVE("CheckCertOCSP", result); - return result; + XFREE(data, out->heap, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_FAILURE; } +#endif /* OPENSSL_ALL || APACHE_HTTPD */ +#ifdef OPENSSL_EXTRA +#ifndef NO_WOLFSSL_STUB +int wolfSSL_OCSP_REQUEST_add_ext(OcspRequest* req, WOLFSSL_X509_EXTENSION* ext, + int idx) +{ + WOLFSSL_STUB("wolfSSL_OCSP_REQUEST_add_ext"); + (void)req; + (void)ext; + (void)idx; + return WOLFSSL_FATAL_ERROR; +} +#endif + +#ifndef NO_WOLFSSL_STUB +OcspResponse* wolfSSL_OCSP_response_create(int status, + WOLFSSL_OCSP_BASICRESP* bs) +{ + WOLFSSL_STUB("wolfSSL_OCSP_response_create"); + (void)status; + (void)bs; + return NULL; +} +#endif + +#ifndef NO_WOLFSSL_STUB +const char* wolfSSL_OCSP_crl_reason_str(long s) +{ + WOLFSSL_STUB("wolfSSL_OCSP_crl_reason_str"); + (void)s; + return NULL; +} +#endif + +/* Returns elements of an OCSP_CERTID struct. Currently only supports + * returning the serial number, and returns an error if user requests + * any of name, pmd, and/or keyHash. + * Return 1 on success, 0 on failure */ +int wolfSSL_OCSP_id_get0_info(WOLFSSL_ASN1_STRING **name, + WOLFSSL_ASN1_OBJECT **pmd, WOLFSSL_ASN1_STRING **keyHash, + WOLFSSL_ASN1_INTEGER **serial, WOLFSSL_OCSP_CERTID *cid) +{ + int i = 0; + WOLFSSL_ASN1_INTEGER* ser; + + WOLFSSL_ENTER("wolfSSL_OCSP_id_get0_info"); + + if (cid == NULL) + return 0; + + /* build up ASN1_INTEGER for serial */ + if (serial != NULL) { + ser = wolfSSL_ASN1_INTEGER_new(); + if (ser == NULL) + return 0; + + if (cid->serialSz > (WOLFSSL_ASN1_INTEGER_MAX - 2)) { + /* allocate data buffer, +2 for type and length */ + ser->data = (unsigned char*)XMALLOC(cid->serialSz + 2, NULL, + DYNAMIC_TYPE_OPENSSL); + if (ser->data == NULL) { + wolfSSL_ASN1_INTEGER_free(ser); + return 0; + } + ser->dataMax = cid->serialSz + 2; + ser->isDynamic = 1; + } else { + /* Use array instead of dynamic memory */ + ser->data = ser->intData; + ser->dataMax = WOLFSSL_ASN1_INTEGER_MAX; + } + + #ifdef WOLFSSL_QT + /* Serial number starts at 0 index of ser->data */ + XMEMCPY(&ser->data[i], cid->serial, cid->serialSz); + ser->length = cid->serialSz; + #else + ser->data[i++] = ASN_INTEGER; + i += SetLength(cid->serialSz, ser->data + i); + XMEMCPY(&ser->data[i], cid->serial, cid->serialSz); + #endif + + cid->serialInt = ser; + *serial = cid->serialInt; + } + + /* Not needed for Apache, return error if user is requesting */ + if (name != NULL || pmd != NULL || keyHash != NULL) { + if (name != NULL) + *name = NULL; + + if (pmd != NULL) + *pmd = NULL; + + if (keyHash != NULL) + *keyHash = NULL; + return 0; + } + + return 1; +} + +#ifndef NO_WOLFSSL_STUB +int wolfSSL_OCSP_request_add1_nonce(OcspRequest* req, unsigned char* val, + int sz) +{ + WOLFSSL_STUB("wolfSSL_OCSP_request_add1_nonce"); + (void)req; + (void)val; + (void)sz; + return WOLFSSL_FATAL_ERROR; +} +#endif + +/* Returns result of OCSP nonce comparison. Return values: + * 1 - nonces are both present and equal + * 2 - both nonces are absent + * 3 - nonce only present in response + * -1 - nonce only present in request + * 0 - both nonces present and equal + */ +int wolfSSL_OCSP_check_nonce(OcspRequest* req, WOLFSSL_OCSP_BASICRESP* bs) +{ + byte* reqNonce = NULL; + byte* rspNonce = NULL; + int reqNonceSz = 0; + int rspNonceSz = 0; + + WOLFSSL_ENTER("wolfSSL_OCSP_check_nonce"); + + if (req != NULL) { + reqNonce = req->nonce; + reqNonceSz = req->nonceSz; + } + + if (bs != NULL) { + rspNonce = bs->nonce; + rspNonceSz = bs->nonceSz; + } + + /* nonce absent in both req and rsp */ + if (reqNonce == NULL && rspNonce == NULL) + return 2; + + /* nonce present in rsp only */ + if (reqNonce == NULL && rspNonce != NULL) + return 3; + + /* nonce present in req only */ + if (reqNonce != NULL && rspNonce == NULL) + return -1; + + /* nonces are present and equal, return 1. Extra NULL check for fixing + scan-build warning. */ + if (reqNonceSz == rspNonceSz && reqNonce && rspNonce) { + if (XMEMCMP(reqNonce, rspNonce, reqNonceSz) == 0) + return 1; + } + + /* nonces are present but not equal */ + return 0; +} +#endif /* OPENSSL_EXTRA */ #else /* HAVE_OCSP */ @@ -300,4 +1097,4 @@ int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert) #endif /* HAVE_OCSP */ - +#endif /* WOLFCRYPT_ONLY */ |