Merge pull request #1654 from SparkiDev/tls13_stapling

TLS 1.3 OCSP Stapling
This commit is contained in:
toddouska 2018-07-03 12:56:28 -07:00 committed by GitHub
commit ae54bae2fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 472 additions and 376 deletions

View File

@ -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

View File

@ -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));
ret = CreateOcspResponse(ssl, &request, &response);
if (ret == 0 && response.buffer) {
ret = BuildCertificateStatus(ssl, status_type, &response, 1);
/* 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
XFREE(response.buffer, ssl->heap, DYNAMIC_TYPE_OCSP_REQUEST);
response.buffer = NULL;
}
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;
}
}
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;

View File

@ -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(

177
src/tls.c
View File

@ -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,51 +9502,70 @@ 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
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
#endif
break;
#ifndef NO_CERTS
#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));
@ -9492,16 +9573,8 @@ int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset
* TLSX_SERVER_CERTIFICATE_TYPE
*/
break;
#endif
#endif
#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
}
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,

View File

@ -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;

View File

@ -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*);