wolfSSL SSL/TLS library, support up to TLS1.3

Dependents:   CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more

Revision:
0:d92f9d21154c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ocsp.c	Fri Jun 26 00:39:20 2015 +0000
@@ -0,0 +1,304 @@
+/* ocsp.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+  /* Name change compatibility layer no longer needs to be included here */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef HAVE_OCSP
+
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/ocsp.h>
+#include <wolfssl/internal.h>
+
+
+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)
+        return BAD_MUTEX_E;
+
+    return 0;
+}
+
+
+static int InitOCSP_Entry(OCSP_Entry* ocspe, DecodedCert* cert)
+{
+    WOLFSSL_ENTER("InitOCSP_Entry");
+
+    XMEMSET(ocspe, 0, sizeof(*ocspe));
+    XMEMCPY(ocspe->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE);
+    XMEMCPY(ocspe->issuerKeyHash, cert->issuerKeyHash, SHA_DIGEST_SIZE);
+
+    return 0;
+}
+
+
+static void FreeOCSP_Entry(OCSP_Entry* ocspe)
+{
+    CertStatus* tmp = ocspe->status;
+
+    WOLFSSL_ENTER("FreeOCSP_Entry");
+
+    while (tmp) {
+        CertStatus* next = tmp->next;
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+        tmp = next;
+    }
+}
+
+
+void FreeOCSP(WOLFSSL_OCSP* ocsp, int dynamic)
+{
+    OCSP_Entry* tmp = ocsp->ocspList;
+
+    WOLFSSL_ENTER("FreeOCSP");
+
+    while (tmp) {
+        OCSP_Entry* next = tmp->next;
+        FreeOCSP_Entry(tmp);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_OCSP_ENTRY);
+        tmp = next;
+    }
+
+    FreeMutex(&ocsp->ocspLock);
+    if (dynamic)
+        XFREE(ocsp, NULL, DYNAMIC_TYPE_OCSP);
+}
+
+
+static int xstat2err(int stat)
+{
+    switch (stat) {
+        case CERT_GOOD:
+            return 0;
+        case CERT_REVOKED:
+            return OCSP_CERT_REVOKED;
+        default:
+            return OCSP_CERT_UNKNOWN;
+    }
+}
+
+
+int CheckCertOCSP(WOLFSSL_OCSP* ocsp, DecodedCert* cert)
+{
+    byte* ocspReqBuf = NULL;
+    int ocspReqSz = 2048;
+    byte* ocspRespBuf = NULL;
+    int result = -1;
+    OCSP_Entry* ocspe;
+    CertStatus* certStatus = NULL;
+    const char *url;
+    int urlSz;
+#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) {
+        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)
+            break;
+        else
+            ocspe = ocspe->next;
+    }
+
+    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;
+        }
+        else {
+            UnLockMutex(&ocsp->ocspLock);
+            WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+            return MEMORY_ERROR;
+        }
+    }
+    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 (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");
+        }
+        else {
+            result = xstat2err(certStatus->status);
+            UnLockMutex(&ocsp->ocspLock);
+            WOLFSSL_LEAVE("CheckCertOCSP", result);
+            return result;
+        }
+    }
+
+    UnLockMutex(&ocsp->ocspLock);
+
+    if (ocsp->cm->ocspUseOverrideURL) {
+        url = ocsp->cm->ocspOverrideURL;
+        if (url != NULL && url[0] != '\0')
+            urlSz = (int)XSTRLEN(url);
+        else
+            return OCSP_NEED_URL;
+    }
+    else if (cert->extAuthInfoSz != 0 && cert->extAuthInfo != NULL) {
+        url = (const char *)cert->extAuthInfo;
+        urlSz = cert->extAuthInfoSz;
+    }
+    else {
+        /* cert doesn't have extAuthInfo, assuming CERT_GOOD */
+        return 0;
+    }
+
+    ocspReqBuf = (byte*)XMALLOC(ocspReqSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
+    if (ocspReqBuf == NULL) {
+        WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+        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);
+
+    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(ocspReqBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+        WOLFSSL_LEAVE("CheckCertOCSP", MEMORY_ERROR);
+        return MEMORY_E;
+    }
+#endif
+
+    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;
+        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);
+                }
+            }
+            else
+                result = OCSP_LOOKUP_FAIL;
+        }
+    }
+    else
+        result = OCSP_LOOKUP_FAIL;
+
+    XFREE(ocspReqBuf, NULL, DYNAMIC_TYPE_IN_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);
+#endif
+
+    if (ocspRespBuf != NULL && ocsp->cm->ocspRespFreeCb)
+        ocsp->cm->ocspRespFreeCb(ocsp->cm->ocspIOCtx, ocspRespBuf);
+
+    WOLFSSL_LEAVE("CheckCertOCSP", result);
+    return result;
+}
+
+
+#else /* HAVE_OCSP */
+
+
+#ifdef _MSC_VER
+    /* 4206 warning for blank file */
+    #pragma warning(disable: 4206)
+#endif
+
+
+#endif /* HAVE_OCSP */
+
+