Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16239,12 +16239,23 @@ static int ProcessPeerCertsChainOCSPStatusCheck(WOLFSSL* ssl)
} else
return 0;

/* error when leaf cert doesn't have certificate status */
if (csr->requests < 1 || csr->responses[0].length == 0) {
/* RFC 8446 4.4.2.1: when a server includes the status_request extension
* in its CertificateRequest, the client MAY return an OCSP response with
* its Certificate, but is not required to. Treat a missing or empty
* stapled response as a non-fatal condition by default and fall back to
* standard certificate validation.
*
* RFC 7633: a certificate carrying the TLS Feature extension with the
* status_request feature ("must-staple") asserts that a stapled OCSP
* response is required. The wolfSSL ocspMustStaple flag mirrors that
* policy at the verifier side. Only in those cases should the absence
* of a stapled response be reported as BAD_CERTIFICATE_STATUS_ERROR. */
if (csr->requests < 1 || csr->responses[0].length == 0) {
WOLFSSL_MSG("Leaf cert doesn't have certificate status.");
return BAD_CERTIFICATE_STATUS_ERROR;
if (SSL_CM(ssl)->ocspMustStaple)
return BAD_CERTIFICATE_STATUS_ERROR;
return 0;
}

for (i = 0; i < csr->requests; i++) {
if (csr->responses[i].length != 0) {
ssl->status_request = 1;
Expand Down Expand Up @@ -16450,7 +16461,12 @@ static int ProcessPeerCertLeafRevocation(WOLFSSL* ssl, ProcPeerCertArgs* args,

WOLFSSL_MSG("Checking if ocsp needed");

if (ssl->options.side == WOLFSSL_CLIENT_END) {
if (ssl->options.side == WOLFSSL_CLIENT_END
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|| (ssl->options.side == WOLFSSL_SERVER_END
&& ssl->options.handShakeDone)
#endif
) {
#ifndef NO_TLS
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
if (ssl->status_request) {
Expand Down
26 changes: 26 additions & 0 deletions src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,7 @@ void FreeWriteDup(WOLFSSL* ssl)
#endif
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
Free_HS_Hashes(ssl->dupWrite->postHandshakeHashState, ssl->heap);
Free_HS_Hashes(ssl->dupWrite->postHandshakeSyncedHashState, ssl->heap);
{
CertReqCtx* ctx = ssl->dupWrite->postHandshakeCertReqCtx;
while (ctx != NULL) {
Expand Down Expand Up @@ -1763,6 +1764,31 @@ static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz)
}
return WOLFSSL_FATAL_ERROR;
}
/* PHA response fully sent: publish the write side's updated
* transcript to the read side for the next PHA round. */
if (ssl->hsHashes != NULL && ssl->dupWrite != NULL) {
int syncRet;
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0)
return BAD_MUTEX_E;
syncRet = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->dupWrite->postHandshakeSyncedHashState);
if (syncRet != 0) {
/* On failure the copy may have left a partially
* initialized transcript. The read side only checks
* for non-NULL before consuming it, so drop it here to
* avoid hashing onto a corrupt transcript, and surface
* the error to the caller. */
Free_HS_Hashes(
ssl->dupWrite->postHandshakeSyncedHashState,
ssl->heap);
ssl->dupWrite->postHandshakeSyncedHashState = NULL;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
if (syncRet != 0) {
ssl->error = syncRet;
return WOLFSSL_FATAL_ERROR;
}
}
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */
#ifdef WOLFSSL_DTLS13
Expand Down
37 changes: 22 additions & 15 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -3486,7 +3486,7 @@ word16 TLSX_CSR_GetSize_ex(CertificateStatusRequest* csr, byte isRequest,
}
#endif
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
if (!isRequest && IsAtLeastTLSv1_3(csr->ssl->version)) {
if (!isRequest && csr->ssl != NULL && IsAtLeastTLSv1_3(csr->ssl->version)) {
if (csr->ssl != NULL && SSL_CM(csr->ssl) != NULL &&
SSL_CM(csr->ssl)->ocsp_stapling != NULL &&
SSL_CM(csr->ssl)->ocsp_stapling->statusCb != NULL) {
Expand Down Expand Up @@ -3626,7 +3626,7 @@ int TLSX_CSR_Write_ex(CertificateStatusRequest* csr, byte* output,
}
#endif
#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
if (!isRequest && IsAtLeastTLSv1_3(csr->ssl->version)) {
if (!isRequest && csr->ssl != NULL && IsAtLeastTLSv1_3(csr->ssl->version)) {
word16 offset = 0;
if (csr->ssl != NULL && SSL_CM(csr->ssl) != NULL &&
SSL_CM(csr->ssl)->ocsp_stapling != NULL &&
Expand Down Expand Up @@ -15404,8 +15404,9 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
break;

case TLSX_STATUS_REQUEST:
length += CSR_GET_SIZE(
(CertificateStatusRequest*)extension->data, isRequest);
if (msgType != certificate_request)
length += CSR_GET_SIZE(
(CertificateStatusRequest*)extension->data, isRequest);
break;

case TLSX_STATUS_REQUEST_V2:
Expand Down Expand Up @@ -15682,11 +15683,15 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,

case TLSX_STATUS_REQUEST:
WOLFSSL_MSG("Certificate Status Request extension to write");
ret = CSR_WRITE((CertificateStatusRequest*)extension->data,
output + offset, isRequest);
if (ret > 0) {
offset += (word16)ret;
if (msgType == certificate_request) {
ret = 0;
} else {
ret = CSR_WRITE((CertificateStatusRequest*)extension->data,
output + offset, isRequest);
if (ret > 0) {
offset += (word16)ret;
ret = 0;
}
}
break;

Expand Down Expand Up @@ -17122,9 +17127,10 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength)
TLSX_ToSemaphore(TLSX_CERTIFICATE_AUTHORITIES));
}
#endif
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, OID_FILTERS
* TLSX_STATUS_REQUEST
*/
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, OID_FILTERS */
/* TLSX_STATUS_REQUEST is enabled: the server may request the client
* to staple an OCSP response with its CertificateRequest. */
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
}
#endif
#if defined(HAVE_ECH)
Expand Down Expand Up @@ -17345,11 +17351,12 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset)
TLSX_ToSemaphore(TLSX_CERTIFICATE_AUTHORITIES));
}
#endif
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, TLSX_OID_FILTERS
* TLSX_STATUS_REQUEST
*/
/* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP, TLSX_OID_FILTERS */
/* TLSX_STATUS_REQUEST is enabled: the server may request the client
* to staple an OCSP response with its CertificateRequest. */
TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
}
#endif
#endif
#endif
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
if (!ssl->options.disableECH && msgType == client_hello) {
Expand Down
74 changes: 69 additions & 5 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -9550,6 +9550,24 @@ static int SetupOcspResp(WOLFSSL* ssl)
OcspRequest* request = NULL;

extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* During post-handshake client authentication the client must staple
* its own OCSP response, but the status_request extension it offered in
* the initial ClientHello is no longer present on ssl->extensions.
* Recreate it here (the request extension still lives on
* ctx->extensions). Pass ssl so csr->ssl is set, which the response
* size/write path requires. */
if (extension == NULL &&
ssl->options.side == WOLFSSL_CLIENT_END &&
ssl->options.handShakeDone &&
TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST) != NULL) {
ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
WOLFSSL_CSR_OCSP, 0, ssl, ssl->heap, ssl->devId);
if (ret != WOLFSSL_SUCCESS)
return ret;
extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
}
#endif
if (extension == NULL)
return 0; /* peer didn't signal ocsp support */
csr = (CertificateStatusRequest*)extension->data;
Expand Down Expand Up @@ -9579,12 +9597,33 @@ static int SetupOcspResp(WOLFSSL* ssl)
XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
return ret;
}
ret = TLSX_CSR_InitRequest(ssl->extensions, cert, ssl->heap);
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* On client PHA the same certificate is re-stapled every round; reuse
* request slot 0 instead of appending, else csr->requests grows until
* MAX_CERT_EXTENSIONS_ERR. */
if (ssl->options.side == WOLFSSL_CLIENT_END && ssl->options.handShakeDone) {
ret = TLSX_CSR_InitRequest_ex(ssl->extensions, cert, ssl->heap, 0);
}
else
#endif
{
ret = TLSX_CSR_InitRequest(ssl->extensions, cert, ssl->heap);
}
FreeDecodedCert(cert);
XFREE(cert, ssl->heap, DYNAMIC_TYPE_DCERT);
if (ret != 0 )
return ret;

/* Free previous OCSP response buffers to avoid leak on PHA reuse */
{
int j;
for (j = 0; j < MAX_CERT_EXTENSIONS; j++) {
XFREE(csr->responses[j].buffer, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
csr->responses[j].buffer = NULL;
csr->responses[j].length = 0;
}
}
request = &csr->request.ocsp[0];
ret = CreateOcspResponse(ssl, &request, &csr->responses[0]);
if (request != &csr->request.ocsp[0] &&
Expand Down Expand Up @@ -9697,10 +9736,16 @@ static int SendTls13Certificate(WOLFSSL* ssl)
extSz[extIdx] = OPAQUE16_LEN;

#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && !defined(NO_WOLFSSL_SERVER)
/* We only send CSR on the server side. On client side, the CSR data
* is populated with the server response. We would be sending the server
* its own stapling data. */
if (ssl->options.side == WOLFSSL_SERVER_END) {
/* Staple our own OCSP response with the Certificate. Normally only the
* server staples; the client's CSR holds the server's response, so
* echoing it back is wrong. The exception is post-handshake auth (PHA),
* where the client sends its own Certificate and staples for it. */
if (ssl->options.side == WOLFSSL_SERVER_END
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|| (ssl->options.side == WOLFSSL_CLIENT_END
&& ssl->options.handShakeDone)
#endif
) {
ret = SetupOcspResp(ssl);
if (ret != 0)
return ret;
Expand Down Expand Up @@ -14053,6 +14098,25 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ssl->error = 0;
}
#endif
#if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
/* Read side: a fresh PHA CertificateRequest. Resume from the transcript
* the write side published after the previous PHA response, so this CR is
* hashed onto the same base the server has. */
if (ret == 0 && type == certificate_request &&
ssl->options.side == WOLFSSL_CLIENT_END &&
ssl->dupSide == READ_DUP_SIDE &&
ssl->options.handShakeState == HANDSHAKE_DONE &&
ssl->dupWrite != NULL) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0)
return BAD_MUTEX_E;
if (ssl->dupWrite->postHandshakeSyncedHashState != NULL) {
FreeHandshakeHashes(ssl);
ssl->hsHashes = ssl->dupWrite->postHandshakeSyncedHashState;
ssl->dupWrite->postHandshakeSyncedHashState = NULL;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
#endif /* HAVE_WRITE_DUP && WOLFSSL_POST_HANDSHAKE_AUTH */
if (ret == 0 && type != client_hello && type != session_ticket &&
type != key_update
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
Expand Down
Loading
Loading