Browse Source

Merge pull request #1654 from SparkiDev/tls13_stapling

TLS 1.3 OCSP Stapling
toddouska 6 years ago
parent
commit
ae54bae2fa
6 changed files with 472 additions and 376 deletions
  1. 30 0
      scripts/ocsp-stapling.test
  2. 240 292
      src/internal.c
  3. 6 6
      src/ssl.c
  4. 125 52
      src/tls.c
  5. 58 23
      src/tls13.c
  6. 13 3
      wolfssl/internal.h

+ 30 - 0
scripts/ocsp-stapling.test

@@ -8,6 +8,10 @@ server=login.live.com
 ca=certs/external/baltimore-cybertrust-root.pem
 
 [ ! -x ./examples/client/client ] && echo -e "\n\nClient doesn't exist" && exit 1
+./examples/client/client -? 2>&1 | grep -- 'Client not compiled in!'
+if [ $? -eq 0 ]; then
+    exit 0
+fi
 
 # is our desired server there? - login.live.com doesn't answers PING
 #./scripts/ping.test $server 2
@@ -17,6 +21,14 @@ ca=certs/external/baltimore-cybertrust-root.pem
 RESULT=$?
 [ $RESULT -ne 0 ] && echo -e "\n\nClient connection failed" && exit 1
 
+
+# Test with example server
+
+./examples/server/server -? 2>&1 | grep -- 'Server not compiled in!'
+if [ $? -eq 0 ]; then
+    exit 0
+fi
+
 # setup ocsp responder
 ./certs/ocsp/ocspd-intermediate1-ca-issued-certs.sh &
 sleep 1
@@ -36,4 +48,22 @@ sleep 1
 RESULT=$?
 [ $RESULT -ne 1 ] && echo -e "\n\nClient connection suceeded $RESULT" && exit 1
 
+
+./examples/client/client -v 4 2>&1 | grep -- 'Bad SSL version'
+if [ $? -ne 0 ]; then
+    # client test against our own server - GOOD CERT
+    ./examples/server/server -c certs/ocsp/server1-cert.pem -k certs/ocsp/server1-key.pem -v 4 &
+    sleep 1
+    ./examples/client/client -C -A certs/ocsp/root-ca-cert.pem -W 1 -v 4 -F 1
+    RESULT=$?
+    [ $RESULT -ne 0 ] && echo -e "\n\nClient connection failed" && exit 1
+
+    # client test against our own server - REVOKED CERT
+    ./examples/server/server -c certs/ocsp/server2-cert.pem -k certs/ocsp/server2-key.pem -v 4 &
+    sleep 1
+    ./examples/client/client -C -A certs/ocsp/root-ca-cert.pem -W 1 -v 4 -F 1
+    RESULT=$?
+    [ $RESULT -ne 1 ] && echo -e "\n\nClient connection suceeded $RESULT" && exit 1
+fi
+
 exit 0

+ 240 - 292
src/internal.c

@@ -8081,6 +8081,87 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
 
 #endif /* KEEP_PEER_CERT || SESSION_CERTS */
 
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+     (defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) && !defined(WOLFSSL_NO_TLS12))
+static int ProcessCSR(WOLFSSL* ssl, byte* input, word32* inOutIdx,
+                      word32 status_length)
+{
+    int ret = 0;
+    OcspRequest* request;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        CertStatus* status;
+        OcspResponse* response;
+    #else
+        CertStatus status[1];
+        OcspResponse response[1];
+    #endif
+
+    do {
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+            if (ssl->status_request) {
+                request = (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
+                ssl->status_request = 0;
+                break;
+            }
+        #endif
+
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+            if (ssl->status_request_v2) {
+                request = (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions,
+                                                          WOLFSSL_CSR2_OCSP, 0);
+                ssl->status_request_v2 = 0;
+                break;
+            }
+        #endif
+
+        return BUFFER_ERROR;
+    } while(0);
+
+    if (request == NULL)
+        return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */
+
+    #ifdef WOLFSSL_SMALL_STACK
+        status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
+                                                      DYNAMIC_TYPE_OCSP_STATUS);
+        response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+
+        if (status == NULL || response == NULL) {
+            if (status)
+                XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
+            if (response)
+                XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
+
+            return MEMORY_ERROR;
+        }
+    #endif
+
+    InitOcspResponse(response, status, input +*inOutIdx, status_length);
+
+    if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (CompareOcspReqResp(request, response) != 0)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (response->responseStatus != OCSP_SUCCESSFUL)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+    else if (response->status->status == CERT_REVOKED)
+        ret = OCSP_CERT_REVOKED;
+    else if (response->status->status != CERT_GOOD)
+        ret = BAD_CERTIFICATE_STATUS_ERROR;
+
+    *inOutIdx += status_length;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(status,   ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
+        XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+    #endif
+
+    return ret;
+}
+#endif
+
+
 typedef struct ProcPeerCertArgs {
     buffer*      certs;
 #ifdef WOLFSSL_TLS13
@@ -8353,6 +8434,10 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
                     args->exts[args->totalCerts].buffer = input + args->idx;
                     args->idx += extSz;
                     listSz -= extSz + OPAQUE16_LEN;
+                    ret = TLSX_Parse(ssl, args->exts[args->totalCerts].buffer,
+                        args->exts[args->totalCerts].length, certificate, NULL);
+                    if (ret < 0)
+                        return ret;
                 }
             #endif
 
@@ -9028,6 +9113,21 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
                             args->fatal = TLSX_CSR_InitRequest(ssl->extensions,
                                                     args->dCert, ssl->heap);
                             doLookup = 0;
+                        #ifdef WOLFSSL_TLS13
+                            if (ssl->options.tls1_3) {
+                                TLSX* ext = TLSX_Find(ssl->extensions,
+                                                           TLSX_STATUS_REQUEST);
+                                if (ext != NULL) {
+                                    word32 idx = 0;
+                                    CertificateStatusRequest* csr =
+                                           (CertificateStatusRequest*)ext->data;
+                                    ret = ProcessCSR(ssl, csr->response.buffer,
+                                                    &idx, csr->response.length);
+                                    if (ret < 0)
+                                        goto exit_ppc;
+                                }
+                            }
+                        #endif
                         }
                 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
                 #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
@@ -9644,80 +9744,9 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
      || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
 
         /* WOLFSSL_CSR_OCSP overlaps with WOLFSSL_CSR2_OCSP */
-        case WOLFSSL_CSR2_OCSP: {
-            OcspRequest* request;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                CertStatus* status;
-                OcspResponse* response;
-            #else
-                CertStatus status[1];
-                OcspResponse response[1];
-            #endif
-
-            do {
-                #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
-                    if (ssl->status_request) {
-                        request = (OcspRequest*)TLSX_CSR_GetRequest(
-                                                               ssl->extensions);
-                        ssl->status_request = 0;
-                        break;
-                    }
-                #endif
-
-                #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
-                    if (ssl->status_request_v2) {
-                        request = (OcspRequest*)TLSX_CSR2_GetRequest(
-                                               ssl->extensions, status_type, 0);
-                        ssl->status_request_v2 = 0;
-                        break;
-                    }
-                #endif
-
-                return BUFFER_ERROR;
-            } while(0);
-
-            if (request == NULL)
-                return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */
-
-            #ifdef WOLFSSL_SMALL_STACK
-                status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_STATUS);
-                response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_REQUEST);
-
-                if (status == NULL || response == NULL) {
-                    if (status)
-                        XFREE(status, NULL, DYNAMIC_TYPE_OCSP_STATUS);
-                    if (response)
-                        XFREE(response, NULL, DYNAMIC_TYPE_OCSP_REQUEST);
-
-                    return MEMORY_ERROR;
-                }
-            #endif
-
-            InitOcspResponse(response, status, input +*inOutIdx, status_length);
-
-            if (OcspResponseDecode(response, ssl->ctx->cm, ssl->heap, 0) != 0)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (CompareOcspReqResp(request, response) != 0)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (response->responseStatus != OCSP_SUCCESSFUL)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-            else if (response->status->status == CERT_REVOKED)
-                ret = OCSP_CERT_REVOKED;
-            else if (response->status->status != CERT_GOOD)
-                ret = BAD_CERTIFICATE_STATUS_ERROR;
-
-            *inOutIdx += status_length;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                XFREE(status,   ssl->heap, DYNAMIC_TYPE_OCSP_STATUS);
-                XFREE(response, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-            #endif
-
-        }
-        break;
+        case WOLFSSL_CSR2_OCSP:
+            ret = ProcessCSR(ssl, input, inOutIdx, status_length);
+            break;
 
     #endif
 
@@ -13724,7 +13753,116 @@ int SendFinished(WOLFSSL* ssl)
 
     return ret;
 }
+#endif /* WOLFSSL_NO_TLS12 */
+
+#ifndef NO_WOLFSSL_SERVER
+#if (!defined(WOLFSSL_NO_TLS12) && \
+        (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+         defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2))) || \
+    (defined(WOLFSSL_TLS13) && defined(HAVE_CERTIFICATE_STATUS_REQUEST))
+static int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request,
+                             DecodedCert* cert, byte* certData, word32 length)
+{
+    int ret;
+
+    InitDecodedCert(cert, certData, length, ssl->heap);
+    /* TODO: Setup async support here */
+    ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, ssl->ctx->cm);
+    if (ret != 0) {
+        WOLFSSL_MSG("ParseCert failed");
+    }
+    if (ret == 0)
+        ret = InitOcspRequest(request, cert, 0, ssl->heap);
+    if (ret == 0) {
+        /* make sure ctx OCSP request is updated */
+        if (!ssl->buffers.weOwnCert) {
+            wolfSSL_Mutex* ocspLock = &ssl->ctx->cm->ocsp_stapling->ocspLock;
+            if (wc_LockMutex(ocspLock) == 0) {
+                if (ssl->ctx->certOcspRequest == NULL)
+                    ssl->ctx->certOcspRequest = request;
+                wc_UnLockMutex(ocspLock);
+            }
+        }
+    }
+
+    FreeDecodedCert(cert);
+
+    return ret;
+}
+
+
+int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
+                       buffer* response)
+{
+    int          ret = 0;
+    OcspRequest* request;
+
+    if (ssl == NULL || ocspRequest == NULL || response == NULL)
+        return BAD_FUNC_ARG;
+
+    request = *ocspRequest;
+
+    XMEMSET(response, 0, sizeof(*response));
+
+    /* unable to fetch status. skip. */
+    if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
+        return 0;
+
+    if (request == NULL || ssl->buffers.weOwnCert) {
+        DerBuffer* der = ssl->buffers.certificate;
+        #ifdef WOLFSSL_SMALL_STACK
+            DecodedCert* cert = NULL;
+        #else
+            DecodedCert  cert[1];
+        #endif
+
+        /* unable to fetch status. skip. */
+        if (der->buffer == NULL || der->length == 0)
+            return 0;
+
+    #ifdef WOLFSSL_SMALL_STACK
+        cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
+                                        DYNAMIC_TYPE_DCERT);
+        if (cert == NULL)
+            return MEMORY_E;
+    #endif
+        request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+        if (request == NULL)
+            ret = MEMORY_E;
+
+        if (ret == 0) {
+            ret = CreateOcspRequest(ssl, request, cert, der->buffer,
+                                                                   der->length);
+        }
+
+        if (request != NULL)
+            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+    #ifdef WOLFSSL_SMALL_STACK
+        XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+    #endif
+    }
+
+    if (ret == 0) {
+        request->ssl = ssl;
+        ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request, response);
+
+        /* Suppressing, not critical */
+        if (ret == OCSP_CERT_REVOKED ||
+            ret == OCSP_CERT_UNKNOWN ||
+            ret == OCSP_LOOKUP_FAIL) {
+            ret = 0;
+        }
+    }
+
+    *ocspRequest = request;
+
+    return ret;
+}
+#endif
+#endif /* !NO_WOLFSSL_SERVER */
 
+#ifndef WOLFSSL_NO_TLS12
 
 #ifndef NO_CERTS
 #if !defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH)
@@ -14228,7 +14366,6 @@ static int BuildCertificateStatus(WOLFSSL* ssl, byte type, buffer* status,
 #endif
 #endif /* NO_WOLFSSL_SERVER */
 
-
 /* handle generation of certificate_status (22) */
 int SendCertificateStatus(WOLFSSL* ssl)
 {
@@ -14259,97 +14396,14 @@ int SendCertificateStatus(WOLFSSL* ssl)
             OcspRequest* request = ssl->ctx->certOcspRequest;
             buffer response;
 
-            XMEMSET(&response, 0, sizeof(response));
-
-            /* unable to fetch status. skip. */
-            if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
-                return 0;
-
-            if (request == NULL || ssl->buffers.weOwnCert) {
-                DerBuffer* der = ssl->buffers.certificate;
-                #ifdef WOLFSSL_SMALL_STACK
-                    DecodedCert* cert = NULL;
-                #else
-                    DecodedCert  cert[1];
-                #endif
-
-                /* unable to fetch status. skip. */
-                if (der->buffer == NULL || der->length == 0)
-                    return 0;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
-                                             DYNAMIC_TYPE_DCERT);
-                if (cert == NULL)
-                    return MEMORY_E;
-            #endif
-
-                InitDecodedCert(cert, der->buffer, der->length, ssl->heap);
-                /* TODO: Setup async support here */
-                if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                          ssl->ctx->cm)) != 0) {
-                    WOLFSSL_MSG("ParseCert failed");
-                }
-                else {
-                    request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    if (request) {
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
-                        if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCert) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->certOcspRequest == NULL)
-                                        ssl->ctx->certOcspRequest = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                        }
-                    }
-                    else {
-                        ret = MEMORY_E;
-                    }
-                }
-
-                FreeDecodedCert(cert);
-
-            #ifdef WOLFSSL_SMALL_STACK
-                XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
-            #endif
-            }
-
-            if (ret == 0) {
-                request->ssl = ssl;
-                ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request,
-                                                                     &response);
-
-                /* 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, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    response.buffer = NULL;
-                }
+            ret = CreateOcspResponse(ssl, &request, &response);
+            if (ret == 0 && response.buffer) {
+                ret = BuildCertificateStatus(ssl, status_type, &response, 1);
 
+                XFREE(response.buffer, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
+                response.buffer = NULL;
             }
 
-            if (request != ssl->ctx->certOcspRequest)
-                XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-
             break;
         }
 
@@ -14365,85 +14419,7 @@ int SendCertificateStatus(WOLFSSL* ssl)
 
             XMEMSET(responses, 0, sizeof(responses));
 
-            /* unable to fetch status. skip. */
-            if (ssl->ctx->cm == NULL || ssl->ctx->cm->ocspStaplingEnabled == 0)
-                return 0;
-
-            if (!request || ssl->buffers.weOwnCert) {
-                DerBuffer* der = ssl->buffers.certificate;
-            #ifdef WOLFSSL_SMALL_STACK
-                DecodedCert* cert = NULL;
-            #else
-                DecodedCert  cert[1];
-            #endif
-
-                /* unable to fetch status. skip. */
-                if (der->buffer == NULL || der->length == 0)
-                    return 0;
-
-            #ifdef WOLFSSL_SMALL_STACK
-                cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
-                                             DYNAMIC_TYPE_DCERT);
-                if (cert == NULL)
-                    return MEMORY_E;
-            #endif
-
-                InitDecodedCert(cert, der->buffer, der->length, ssl->heap);
-                /* TODO: Setup async support here */
-                if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                          ssl->ctx->cm)) != 0) {
-                    WOLFSSL_MSG("ParseCert failed");
-                }
-                else {
-                    request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                    if (request) {
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
-                        if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCert) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->certOcspRequest == NULL)
-                                        ssl->ctx->certOcspRequest = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                        }
-                    }
-                    else {
-                        ret = MEMORY_E;
-                    }
-                }
-
-                FreeDecodedCert(cert);
-
-            #ifdef WOLFSSL_SMALL_STACK
-                XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
-            #endif
-            }
-
-            if (ret == 0) {
-                request->ssl = ssl;
-                ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling, request,
-                                                                 &responses[0]);
-
-                /* Suppressing, not critical */
-                if (ret == OCSP_CERT_REVOKED ||
-                    ret == OCSP_CERT_UNKNOWN ||
-                    ret == OCSP_LOOKUP_FAIL) {
-                    ret = 0;
-                }
-            }
-
-            if (request != ssl->ctx->certOcspRequest)
-                XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-
+            ret = CreateOcspResponse(ssl, &request, &responses[0]);
             if (ret == 0 && (!ssl->ctx->chainOcspRequest[0]
                                               || ssl->buffers.weOwnCertChain)) {
                 buffer der;
@@ -14454,14 +14430,20 @@ int SendCertificateStatus(WOLFSSL* ssl)
                 DecodedCert  cert[1];
             #endif
 
-                XMEMSET(&der, 0, sizeof(buffer));
-
             #ifdef WOLFSSL_SMALL_STACK
                 cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap,
-                                             DYNAMIC_TYPE_DCERT);
+                                                            DYNAMIC_TYPE_DCERT);
                 if (cert == NULL)
                     return MEMORY_E;
             #endif
+                request = (OcspRequest*)XMALLOC(sizeof(OcspRequest), ssl->heap,
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+                if (request == NULL) {
+            #ifdef WOLFSSL_SMALL_STACK
+                    XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
+            #endif
+                    return MEMORY_E;
+                }
 
                 while (idx + OPAQUE24_LEN < ssl->buffers.certChain->length) {
                     c24to32(ssl->buffers.certChain->buffer + idx, &der.length);
@@ -14473,43 +14455,9 @@ int SendCertificateStatus(WOLFSSL* ssl)
                     if (idx > ssl->buffers.certChain->length)
                         break;
 
-                    InitDecodedCert(cert, der.buffer, der.length, ssl->heap);
-                    /* TODO: Setup async support here */
-                    if ((ret = ParseCertRelative(cert, CERT_TYPE, VERIFY,
-                                                      ssl->ctx->cm)) != 0) {
-                        WOLFSSL_MSG("ParseCert failed");
-                        break;
-                    }
-                    else {
-                        request = (OcspRequest*)XMALLOC(sizeof(OcspRequest),
-                                          ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                        if (request == NULL) {
-                            FreeDecodedCert(cert);
-
-                            ret = MEMORY_E;
-                            break;
-                        }
-
-                        ret = InitOcspRequest(request, cert, 0, ssl->heap);
-                        if (ret == 0) {
-                            /* make sure ctx OCSP request is updated */
-                            if (!ssl->buffers.weOwnCertChain) {
-                                wolfSSL_Mutex* ocspLock =
-                                    &ssl->ctx->cm->ocsp_stapling->ocspLock;
-                                if (wc_LockMutex(ocspLock) == 0) {
-                                    if (ssl->ctx->chainOcspRequest[i] == NULL)
-                                        ssl->ctx->chainOcspRequest[i] = request;
-                                    wc_UnLockMutex(ocspLock);
-                                }
-                            }
-                        }
-                        else {
-                            FreeDecodedCert(cert);
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
-                            request = NULL;
-                            break;
-                        }
-
+                    ret = CreateOcspRequest(ssl, request, cert, der.buffer,
+                                                                    der.length);
+                    if (ret == 0) {
                         request->ssl = ssl;
                         ret = CheckOcspRequest(ssl->ctx->cm->ocsp_stapling,
                                                     request, &responses[i + 1]);
@@ -14521,15 +14469,12 @@ int SendCertificateStatus(WOLFSSL* ssl)
                             ret = 0;
                         }
 
-                        if (request != ssl->ctx->chainOcspRequest[i])
-                            XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
 
                         i++;
                     }
-
-                    FreeDecodedCert(cert);
                 }
 
+                XFREE(request, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
             #ifdef WOLFSSL_SMALL_STACK
                 XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
             #endif
@@ -14551,14 +14496,17 @@ int SendCertificateStatus(WOLFSSL* ssl)
             }
 
             if (responses[0].buffer) {
-                if (ret == 0)
-                    ret = BuildCertificateStatus(ssl, status_type,
-                                                        responses, (byte)i + 1);
+                if (ret == 0) {
+                    ret = BuildCertificateStatus(ssl, status_type, responses,
+                                                                   (byte)i + 1);
+                }
 
-                for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++)
-                    if (responses[i].buffer)
+                for (i = 0; i < 1 + MAX_CHAIN_DEPTH; i++) {
+                    if (responses[i].buffer) {
                         XFREE(responses[i].buffer, ssl->heap,
-                                                       DYNAMIC_TYPE_OCSP_REQUEST);
+                                                     DYNAMIC_TYPE_OCSP_REQUEST);
+                    }
+                }
             }
 
             break;

+ 6 - 6
src/ssl.c

@@ -1913,7 +1913,7 @@ int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options)
         return BAD_FUNC_ARG;
 
     return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
-                                                options, ssl->heap, ssl->devId);
+                                          options, NULL, ssl->heap, ssl->devId);
 }
 
 
@@ -1924,7 +1924,7 @@ int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type,
         return BAD_FUNC_ARG;
 
     return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type,
-                                                options, ctx->heap, ctx->devId);
+                                          options, NULL, ctx->heap, ctx->devId);
 }
 
 #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
@@ -1941,8 +1941,8 @@ int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options)
 }
 
 
-int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx,
-                                                 byte status_type, byte options)
+int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type,
+                                                                   byte options)
 {
     if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END)
         return BAD_FUNC_ARG;
@@ -19659,8 +19659,8 @@ long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type)
 
     if (type == TLSEXT_STATUSTYPE_ocsp){
         int r = 0;
-        r = TLSX_UseCertificateStatusRequest(&s->extensions, type,
-                                                     0, s->heap, s->devId);
+        r = TLSX_UseCertificateStatusRequest(&s->extensions, type, 0, s,
+                                                             s->heap, s->devId);
         return (long)r;
     } else {
         WOLFSSL_MSG(

+ 125 - 52
src/tls.c

@@ -2651,6 +2651,17 @@ static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest)
         }
     }
 #endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        if (csr->response.buffer == NULL) {
+            OcspRequest* request = &csr->request.ocsp;
+            int ret = CreateOcspResponse(csr->ssl, &request, &csr->response);
+            if (ret < 0)
+                return ret;
+        }
+        return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length;
+    }
+#endif
 
     return size;
 }
@@ -2691,6 +2702,17 @@ static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output,
         return offset;
     }
 #endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    if (!isRequest && csr->ssl->options.tls1_3) {
+        word16 offset = 0;
+        output[offset++] = csr->status_type;
+        c32to24(csr->response.length, output + offset);
+        offset += OPAQUE24_LEN;
+        XMEMCPY(output + offset, csr->response.buffer, csr->response.length);
+        offset += csr->response.length;
+        return offset;
+    }
+#endif
 
     return 0;
 }
@@ -2719,8 +2741,8 @@ static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
 
             /* enable extension at ssl level */
             ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
-                                     csr->status_type, csr->options, ssl->heap,
-                                     ssl->devId);
+                                     csr->status_type, csr->options, ssl,
+                                     ssl->heap, ssl->devId);
             if (ret != WOLFSSL_SUCCESS)
                 return ret;
 
@@ -2743,7 +2765,34 @@ static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
 
         ssl->status_request = 1;
 
-        return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
+    #ifdef WOLFSSL_TLS13
+        if (ssl->options.tls1_3) {
+            word32       resp_length;
+            word32       offset = 0;
+            ret = 0;
+            if (OPAQUE8_LEN + OPAQUE24_LEN > length)
+                ret = BUFFER_ERROR;
+            if (ret == 0 && input[offset++] != WOLFSSL_CSR_OCSP)
+                ret = BAD_CERTIFICATE_STATUS_ERROR;
+            if (ret == 0) {
+                c24to32(input + offset, &resp_length);
+                offset += OPAQUE24_LEN;
+                if (offset + resp_length != length)
+                    ret = BUFFER_ERROR;
+            }
+            if (ret == 0) {
+                csr->response.buffer = input + offset;
+                csr->response.length = resp_length;
+            }
+
+            return ret;
+        }
+        else
+    #endif
+        {
+            /* extension_data MUST be empty. */
+            return length ? BUFFER_ERROR : 0;
+        }
 #endif
     }
     else {
@@ -2796,13 +2845,12 @@ static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
 
         /* accept the first good status_type and return */
         ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
-                                                      0, ssl->heap, ssl->devId);
+                                                 0, ssl, ssl->heap, ssl->devId);
         if (ret != WOLFSSL_SUCCESS)
             return ret; /* throw error */
 
         TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
         ssl->status_request = status_type;
-
 #endif
     }
 
@@ -2880,7 +2928,8 @@ int TLSX_CSR_ForceRequest(WOLFSSL* ssl)
 }
 
 int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
-                                           byte options, void* heap, int devId)
+                                         byte options, WOLFSSL* ssl, void* heap,
+                                                                      int devId)
 {
     CertificateStatusRequest* csr = NULL;
     int ret = 0;
@@ -2897,6 +2946,7 @@ int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
 
     csr->status_type = status_type;
     csr->options     = options;
+    csr->ssl         = ssl;
 
     switch (csr->status_type) {
         case WOLFSSL_CSR_OCSP:
@@ -3082,7 +3132,8 @@ static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length,
             /* enable extension at ssl level */
             for (; csr2; csr2 = csr2->next) {
                 ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
-                       csr2->status_type, csr2->options, ssl->heap, ssl->devId);
+                                    csr2->status_type, csr2->options, ssl->heap,
+                                                                    ssl->devId);
                 if (ret != WOLFSSL_SUCCESS)
                     return ret;
 
@@ -9184,9 +9235,9 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength)
     else if (msgType == certificate_request) {
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
     #endif
@@ -9281,9 +9332,9 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
     else if (msgType == certificate_request) {
         XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
-        TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
         /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
          *       TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
+         *       TLSX_STATUS_REQUEST
          */
     }
     #endif
@@ -9329,7 +9380,7 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
 
 #endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
 
-#ifndef NO_WOLFSSL_SERVER
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
 
 /** Tells the buffered size of extensions to be sent into the server hello. */
 int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
@@ -9339,58 +9390,69 @@ int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
     byte semaphore[SEMAPHORE_SIZE] = {0};
 
     switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
         case server_hello:
             PF_VALIDATE_RESPONSE(ssl, semaphore);
-#ifdef WOLFSSL_TLS13
+    #ifdef WOLFSSL_TLS13
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#ifndef WOLFSSL_TLS13_DRAFT_18
+        #ifndef WOLFSSL_TLS13_DRAFT_18
                     TURN_OFF(semaphore,
                                      TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-#endif
+        #endif
                     if (!ssl->options.noPskDheKe)
                         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
+        #endif
                 }
                 else {
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
+        #endif
                 }
-#endif
+    #endif
             break;
-#ifdef WOLFSSL_TLS13
+
+    #ifdef WOLFSSL_TLS13
         case hello_retry_request:
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#ifndef WOLFSSL_TLS13_DRAFT_18
+        #ifndef WOLFSSL_TLS13_DRAFT_18
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-#endif
+        #endif
             if (!ssl->options.noPskDheKe)
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
             TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
             break;
-#endif
-#ifdef WOLFSSL_TLS13
+    #endif
+
+    #ifdef WOLFSSL_TLS13
         case encrypted_extensions:
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
             TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
+        #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+            TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
             break;
-    #ifdef WOLFSSL_EARLY_DATA
+
+        #ifdef WOLFSSL_EARLY_DATA
         case session_ticket:
             if (ssl->options.tls1_3) {
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
             }
             break;
+        #endif
     #endif
+#endif
+
+#ifdef WOLFSSL_TLS13
     #ifndef NO_CERT
         case certificate:
             XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
@@ -9440,68 +9502,79 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
         byte semaphore[SEMAPHORE_SIZE] = {0};
 
         switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
             case server_hello:
                 PF_VALIDATE_RESPONSE(ssl, semaphore);
-#ifdef WOLFSSL_TLS13
+    #ifdef WOLFSSL_TLS13
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#ifndef WOLFSSL_TLS13_DRAFT_18
+        #ifndef WOLFSSL_TLS13_DRAFT_18
                     TURN_OFF(semaphore,
                                      TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-#endif
+        #endif
                     if (!ssl->options.noPskDheKe)
                         TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
+        #endif
                 }
                 else {
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                     TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
+        #endif
                 }
-#endif
+    #endif
                 break;
-#ifdef WOLFSSL_TLS13
+
+    #ifdef WOLFSSL_TLS13
             case hello_retry_request:
                 XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-#ifndef WOLFSSL_TLS13_DRAFT_18
+        #ifndef WOLFSSL_TLS13_DRAFT_18
                 TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
-#endif
+        #endif
                 if (!ssl->options.noPskDheKe)
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
                 /* Cookie is written below as last extension. */
                 break;
-#endif
-#ifdef WOLFSSL_TLS13
+    #endif
+
+    #ifdef WOLFSSL_TLS13
             case encrypted_extensions:
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
-    #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+        #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
                 TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
-    #endif
-                break;
-    #ifndef NO_CERTS
-            case certificate:
-                XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
-                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
-                /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
-                 *       TLSX_SERVER_CERTIFICATE_TYPE
-                 */
+        #endif
+        #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+                TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+        #endif
                 break;
-    #endif
-    #ifdef WOLFSSL_EARLY_DATA
+
+        #ifdef WOLFSSL_EARLY_DATA
             case session_ticket:
                 if (ssl->options.tls1_3) {
                     XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
                     TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
                 }
                 break;
+        #endif
     #endif
 #endif
+
+    #ifdef WOLFSSL_TLS13
+        #ifndef NO_CERTS
+            case certificate:
+                XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+                TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+                /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+                 *       TLSX_SERVER_CERTIFICATE_TYPE
+                 */
+                break;
+        #endif
+    #endif
         }
 
         offset += OPAQUE16_LEN; /* extensions length */
@@ -9537,7 +9610,7 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
     return ret;
 }
 
-#endif /* NO_WOLFSSL_SERVER */
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */
 
 /** Parses a buffer of TLS extensions. */
 int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType,

+ 58 - 23
src/tls13.c

@@ -4837,15 +4837,17 @@ static word32 NextCert(byte* data, word32 length, word32* idx)
 
 /* Add certificate data and empty extension to output up to the fragment size.
  *
+ * ssl     SSL/TLS object.
  * cert    The certificate data to write out.
  * len     The length of the certificate data.
+ * extSz   Length of the extension data with the certificate.
  * idx     The start of the certificate data to write out.
  * fragSz  The maximum size of this fragment.
  * output  The buffer to write to.
  * returns the number of bytes written.
  */
-static word32 AddCertExt(byte* cert, word32 len, word32 idx, word32 fragSz,
-                         byte* output)
+static word32 AddCertExt(WOLFSSL* ssl, byte* cert, word32 len, word16 extSz,
+                         word32 idx, word32 fragSz, byte* output)
 {
     word32 i = 0;
     word32 copySz = min(len - idx, fragSz);
@@ -4853,12 +4855,25 @@ static word32 AddCertExt(byte* cert, word32 len, word32 idx, word32 fragSz,
     if (idx < len) {
         XMEMCPY(output, cert + idx, copySz);
         i = copySz;
+        if (copySz == fragSz)
+            return i;
     }
+    copySz = len + extSz - idx - i;
 
-    if (copySz + OPAQUE16_LEN <= fragSz) {
-        /* Empty extension */
-        output[i++] = 0;
-        output[i++] = 0;
+    if (extSz == OPAQUE16_LEN) {
+        if (copySz <= fragSz) {
+            /* Empty extension */
+            output[i++] = 0;
+            output[i++] = 0;
+        }
+    }
+    else {
+        byte* certExts = ssl->buffers.certExts->buffer + idx + i - len;
+        /* Put out as much of the extensions' data as will fit in fragment. */
+        if (copySz > fragSz - i)
+            copySz = fragSz - i;
+        XMEMCPY(output + i, certExts, copySz);
+        i += copySz;
     }
 
     return i;
@@ -4875,6 +4890,7 @@ static int SendTls13Certificate(WOLFSSL* ssl)
 {
     int    ret = 0;
     word32 certSz, certChainSz, headerSz, listSz, payloadSz;
+    word16 extSz = 0;
     word32 length, maxFragment;
     word32 len = 0;
     word32 idx = 0;
@@ -4910,14 +4926,30 @@ static int SendTls13Certificate(WOLFSSL* ssl)
         /* Cert Req Ctx Len | Cert Req Ctx | Cert List Len | Cert Data Len */
         headerSz = OPAQUE8_LEN + certReqCtxLen + CERT_HEADER_SZ +
                    CERT_HEADER_SZ;
-        /* Length of message data with one certificate and empty extensions. */
-        length = headerSz + certSz + OPAQUE16_LEN;
-        /* Length of list data with one certificate and empty extensions. */
-        listSz = CERT_HEADER_SZ + certSz + OPAQUE16_LEN;
+
+        ret = TLSX_GetResponseSize(ssl, certificate, &extSz);
+        if (ret < 0)
+            return ret;
+
+        /* Create extensions' data if none already present. */
+        if (extSz > OPAQUE16_LEN && ssl->buffers.certExts == NULL) {
+            ret = AllocDer(&ssl->buffers.certExts, extSz, CERT_TYPE, ssl->heap);
+            if (ret < 0)
+                return ret;
+
+            ret = TLSX_WriteResponse(ssl, ssl->buffers.certExts->buffer,
+                                                           certificate, &extSz);
+            if (ret < 0)
+                return ret;
+        }
+
+        /* Length of message data with one certificate and extensions. */
+        length = headerSz + certSz + extSz;
+        /* Length of list data with one certificate and extensions. */
+        listSz = CERT_HEADER_SZ + certSz + extSz;
 
         /* Send rest of chain if sending cert (chain has leading size/s). */
         if (certSz > 0 && ssl->buffers.certChainCnt > 0) {
-            /* The pointer to the current spot in the cert chain buffer. */
             p = ssl->buffers.certChain->buffer;
             /* Chain length including extensions. */
             certChainSz = ssl->buffers.certChain->length +
@@ -4943,14 +4975,13 @@ static int SendTls13Certificate(WOLFSSL* ssl)
         int    sendSz = RECORD_HEADER_SZ;
 
         if (ssl->fragOffset == 0)  {
-            if (headerSz + certSz + OPAQUE16_LEN + certChainSz <=
-                maxFragment - HANDSHAKE_HEADER_SZ) {
-
-                fragSz = headerSz + certSz + OPAQUE16_LEN + certChainSz;
+            if (headerSz + certSz + extSz + certChainSz <=
+                                            maxFragment - HANDSHAKE_HEADER_SZ) {
+                fragSz = headerSz + certSz + extSz + certChainSz;
             }
-            else {
+            else
                 fragSz = maxFragment - HANDSHAKE_HEADER_SZ;
-            }
+
             sendSz += fragSz + HANDSHAKE_HEADER_SZ;
             i += HANDSHAKE_HEADER_SZ;
         }
@@ -4996,15 +5027,16 @@ static int SendTls13Certificate(WOLFSSL* ssl)
         else
             AddTls13RecordHeader(output, fragSz, handshake, ssl);
 
-        if (certSz > 0 && ssl->fragOffset < certSz + OPAQUE16_LEN) {
-            /* Put in the leaf certificate and empty extension. */
-            word32 copySz = AddCertExt(ssl->buffers.certificate->buffer, certSz,
-                                       ssl->fragOffset, fragSz, output + i);
-
+        if (certSz > 0 && ssl->fragOffset < certSz + extSz) {
+            /* Put in the leaf certificate with extensions. */
+            word32 copySz = AddCertExt(ssl, ssl->buffers.certificate->buffer,
+                            certSz, extSz, ssl->fragOffset, fragSz, output + i);
             i += copySz;
             ssl->fragOffset += copySz;
             length -= copySz;
             fragSz -= copySz;
+            if (ssl->fragOffset == certSz + extSz)
+                FreeDer(&ssl->buffers.certExts);
         }
         if (certChainSz > 0 && fragSz > 0) {
             /* Put in the CA certificates with empty extensions. */
@@ -5014,6 +5046,8 @@ static int SendTls13Certificate(WOLFSSL* ssl)
                 if (offset == len + OPAQUE16_LEN) {
                     /* Find next CA certificate to write out. */
                     offset = 0;
+                    /* Point to the start of current cert in chain buffer. */
+                    p = ssl->buffers.certChain->buffer + idx;
                     len = NextCert(ssl->buffers.certChain->buffer,
                                    ssl->buffers.certChain->length, &idx);
                     if (len == 0)
@@ -5021,7 +5055,8 @@ static int SendTls13Certificate(WOLFSSL* ssl)
                 }
 
                 /* Write out certificate and empty extension. */
-                l = AddCertExt(p, len, offset, fragSz, output + i);
+                l = AddCertExt(ssl, p, len, OPAQUE16_LEN, offset, fragSz,
+                                                                    output + i);
                 i += l;
                 ssl->fragOffset += l;
                 length -= l;

+ 13 - 3
wolfssl/internal.h

@@ -1991,7 +1991,8 @@ WOLFSSL_LOCAL int   TLSX_WriteRequest(WOLFSSL* ssl, byte* output,
                                        byte msgType, word16* pOffset);
 #endif
 
-#ifndef NO_WOLFSSL_SERVER
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
+/* TLS 1.3 Certificate messages have extensions. */
 WOLFSSL_LOCAL int   TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, 
                                           word16* pLength);
 WOLFSSL_LOCAL int   TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, 
@@ -2084,13 +2085,17 @@ WOLFSSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions, void* heap);
 typedef struct {
     byte status_type;
     byte options;
+    WOLFSSL* ssl;
     union {
         OcspRequest ocsp;
     } request;
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+    buffer response;
+#endif
 } CertificateStatusRequest;
 
 WOLFSSL_LOCAL int   TLSX_UseCertificateStatusRequest(TLSX** extensions,
-                                    byte status_type, byte options, void* heap, int devId);
+           byte status_type, byte options, WOLFSSL* ssl, void* heap, int devId);
 #ifndef NO_CERTS
 WOLFSSL_LOCAL int   TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert,
                                                                     void* heap);
@@ -2114,7 +2119,7 @@ typedef struct CSRIv2 {
 } CertificateStatusRequestItemV2;
 
 WOLFSSL_LOCAL int   TLSX_UseCertificateStatusRequestV2(TLSX** extensions,
-                                    byte status_type, byte options, void* heap, int devId);
+                         byte status_type, byte options, void* heap, int devId);
 #ifndef NO_CERTS
 WOLFSSL_LOCAL int   TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert,
                                                        byte isPeer, void* heap);
@@ -2957,6 +2962,7 @@ typedef struct Buffers {
                  /* chain after self, in DER, with leading size for each cert */
 #ifdef WOLFSSL_TLS13
     int             certChainCnt;
+    DerBuffer*      certExts;
 #endif
 #endif
 #ifdef WOLFSSL_SEND_HRR_COOKIE
@@ -3870,6 +3876,10 @@ WOLFSSL_LOCAL int SendTls13ServerHello(WOLFSSL*, byte);
 #endif
 WOLFSSL_LOCAL int SendCertificate(WOLFSSL*);
 WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*);
+#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+WOLFSSL_LOCAL int CreateOcspResponse(WOLFSSL*, OcspRequest**, buffer*);
+#endif
 WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL*);
 WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL*);
 WOLFSSL_LOCAL int SendBuffered(WOLFSSL*);