Skip to content

Commit 8946e3f

Browse files
Merge pull request #7702 from rizlik/ocspv2
ocsp stapling improvements
2 parents 5ca9b2f + 0531706 commit 8946e3f

File tree

12 files changed

+454
-174
lines changed

12 files changed

+454
-174
lines changed

scripts/ocsp-stapling2.test

+23-13
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,19 @@ openssl ocsp -port $port3 -nmin 1 \
334334
"$@" \
335335
&
336336

337+
# NEW: openssl isn't being cleaned up, invoke directly in script for cleanup
338+
# purposes!
339+
openssl ocsp -port $port4 -nmin 1 \
340+
-index certs/ocsp/index-ca-and-intermediate-cas.txt \
341+
-rsigner certs/ocsp/ocsp-responder-cert.pem \
342+
-rkey certs/ocsp/ocsp-responder-key.pem \
343+
-CA certs/ocsp/root-ca-cert.pem \
344+
"$@" \
345+
&
346+
337347
sleep 0.1
338348
# "jobs" is not portable for posix. Must use bash interpreter!
339-
[ $(jobs -r | wc -l) -ne 3 ] && printf '\n\n%s\n' "Setup ocsp responder failed, skipping" && exit 0
349+
[ $(jobs -r | wc -l) -ne 4 ] && printf '\n\n%s\n' "Setup ocsp responder failed, skipping" && exit 0
340350

341351
printf '\n\n%s\n\n' "All OCSP responders started successfully!"
342352
printf '%s\n\n' "------------- TEST CASE 1 SHOULD PASS ------------------------"
@@ -352,18 +362,18 @@ RESULT=$?
352362
[ $RESULT -ne 0 ] && printf '\n\n%s\n' "Client connection 1 failed" && exit 1
353363
printf '%s\n\n' "Test PASSED!"
354364

355-
printf '%s\n\n' "TEST CASE 2 DISABLED PENDING REVIEW"
356-
#printf '%s\n\n' "------------- TEST CASE 2 SHOULD PASS ------------------------"
357-
#remove_single_rF $ready_file5
358-
#./examples/server/server -c certs/ocsp/server3-cert.pem \
359-
# -k certs/ocsp/server3-key.pem -R $ready_file5 \
360-
# -p $port5 &
361-
#wait_for_readyFile $ready_file5 $server_pid5 $port5
362-
#./examples/client/client -C -A certs/ocsp/root-ca-cert.pem -W 3 -v 3 \
363-
# -p $port5
364-
#RESULT=$?
365-
#[ $RESULT -ne 0 ] && printf '\n\n%s\n' "Client connection 2 failed" && exit 1
366-
#printf '%s\n\n' "Test PASSED!"
365+
printf '%s\n\n' "------------- TEST CASE 2 SHOULD PASS ------------------------"
366+
remove_single_rF $ready_file5
367+
./examples/server/server -c certs/ocsp/server3-cert.pem \
368+
-k certs/ocsp/server3-key.pem -R $ready_file5 \
369+
-p $port5 &
370+
server_pid5=$!
371+
wait_for_readyFile $ready_file5 $server_pid5 $port5
372+
./examples/client/client -C -A certs/ocsp/root-ca-cert.pem -W 3 -v 3 \
373+
-p $port5
374+
RESULT=$?
375+
[ $RESULT -ne 0 ] && printf '\n\n%s\n' "Client connection 2 failed" && exit 1
376+
printf '%s\n\n' "Test PASSED!"
367377

368378
printf '%s\n\n' "------------- TEST CASE 3 SHOULD REVOKE ----------------------"
369379
# client test against our own server - REVOKED SERVER CERT

src/internal.c

+136-56
Original file line numberDiff line numberDiff line change
@@ -14035,6 +14035,7 @@ static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args,
1403514035
buffer* cert;
1403614036
byte* subjectHash = NULL;
1403714037
int alreadySigner = 0;
14038+
Signer *extraSigners = NULL;
1403814039
#if defined(HAVE_RPK)
1403914040
int cType;
1404014041
#endif
@@ -14136,9 +14137,13 @@ PRAGMA_GCC_DIAG_POP
1413614137
return ret;
1413714138
#endif
1413814139
}
14139-
14140+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
14141+
if (verify != NO_VERIFY && TLSX_CSR2_IsMulti(ssl->extensions)) {
14142+
extraSigners = TLSX_CSR2_GetPendingSigners(ssl->extensions);
14143+
}
14144+
#endif
1414014145
/* Parse Certificate */
14141-
ret = ParseCertRelative(args->dCert, certType, verify, SSL_CM(ssl));
14146+
ret = ParseCertRelative(args->dCert, certType, verify, SSL_CM(ssl), extraSigners);
1414214147

1414314148
#if defined(HAVE_RPK)
1414414149
/* if cert type has negotiated with peer, confirm the cert received has
@@ -14371,6 +14376,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1437114376
byte* subjectHash = NULL;
1437214377
int alreadySigner = 0;
1437314378

14379+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
14380+
int addToPendingCAs = 0;
14381+
#endif
1437414382
WOLFSSL_ENTER("ProcessPeerCerts");
1437514383

1437614384
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
@@ -14796,9 +14804,11 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1479614804
if (ret == 0) {
1479714805
#ifdef HAVE_OCSP
1479814806
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
14799-
if (ssl->status_request_v2) {
14807+
addToPendingCAs = 0;
14808+
if (ssl->status_request_v2 && TLSX_CSR2_IsMulti(ssl->extensions)) {
1480014809
ret = TLSX_CSR2_InitRequests(ssl->extensions,
1480114810
args->dCert, 0, ssl->heap);
14811+
addToPendingCAs = 1;
1480214812
}
1480314813
else /* skips OCSP and force CRL check */
1480414814
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
@@ -14943,6 +14953,46 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1494314953
skipAddCA = 1;
1494414954
}
1494514955
#endif
14956+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
14957+
if (ret == 0 && addToPendingCAs && !alreadySigner) {
14958+
DecodedCert dCertAdd;
14959+
DerBuffer *derBuffer;
14960+
buffer* cert = &args->certs[args->certIdx];
14961+
Signer *s;
14962+
InitDecodedCert(&dCertAdd, cert->buffer, cert->length, ssl->heap);
14963+
ret = ParseCert(&dCertAdd, CA_TYPE, NO_VERIFY, SSL_CM(ssl));
14964+
if (ret != 0) {
14965+
FreeDecodedCert(&dCertAdd);
14966+
goto exit_ppc;
14967+
}
14968+
ret = AllocDer(&derBuffer, cert->length, CA_TYPE, ssl->heap);
14969+
if (ret != 0 || derBuffer == NULL) {
14970+
FreeDecodedCert(&dCertAdd);
14971+
goto exit_ppc;
14972+
}
14973+
XMEMCPY(derBuffer->buffer, cert->buffer, cert->length);
14974+
s = MakeSigner(SSL_CM(ssl)->heap);
14975+
if (s == NULL) {
14976+
FreeDecodedCert(&dCertAdd);
14977+
FreeDer(&derBuffer);
14978+
ret = MEMORY_E;
14979+
goto exit_ppc;
14980+
}
14981+
ret = FillSigner(s, &dCertAdd, CA_TYPE, derBuffer);
14982+
FreeDecodedCert(&dCertAdd);
14983+
FreeDer(&derBuffer);
14984+
if (ret != 0) {
14985+
FreeSigner(s, SSL_CM(ssl)->heap);
14986+
goto exit_ppc;
14987+
}
14988+
skipAddCA = 1;
14989+
ret = TLSX_CSR2_AddPendingSigner(ssl->extensions, s);
14990+
if (ret != 0) {
14991+
FreeSigner(s, ssl->heap);
14992+
goto exit_ppc;
14993+
}
14994+
}
14995+
#endif
1494614996

1494714997
/* If valid CA then add to Certificate Manager */
1494814998
if (ret == 0 && args->dCert->isCA &&
@@ -16062,6 +16112,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1606216112
int ret = 0;
1606316113
byte status_type;
1606416114
word32 status_length;
16115+
int endCertificateOK = 0;
1606516116

1606616117
WOLFSSL_START(WC_FUNC_CERTIFICATE_STATUS_DO);
1606716118
WOLFSSL_ENTER("DoCertificateStatus");
@@ -16085,6 +16136,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1608516136
/* WOLFSSL_CSR_OCSP overlaps with WOLFSSL_CSR2_OCSP */
1608616137
case WOLFSSL_CSR2_OCSP:
1608716138
ret = ProcessCSR(ssl, input, inOutIdx, status_length);
16139+
endCertificateOK = (ret == 0);
1608816140
break;
1608916141

1609016142
#endif
@@ -16095,6 +16147,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1609516147
OcspRequest* request;
1609616148
word32 list_length = status_length;
1609716149
byte idx = 0;
16150+
Signer *pendingCAs = NULL;
1609816151

1609916152
#ifdef WOLFSSL_SMALL_STACK
1610016153
CertStatus* status;
@@ -16106,14 +16159,12 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1610616159
OcspResponse response[1];
1610716160
#endif
1610816161

16109-
do {
16110-
if (ssl->status_request_v2) {
16111-
ssl->status_request_v2 = 0;
16112-
break;
16113-
}
16114-
16162+
if (!ssl->status_request_v2)
1611516163
return BUFFER_ERROR;
16116-
} while(0);
16164+
16165+
ssl->status_request_v2 = 0;
16166+
16167+
pendingCAs = TLSX_CSR2_GetPendingSigners(ssl->extensions);
1611716168

1611816169
#ifdef WOLFSSL_SMALL_STACK
1611916170
status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
@@ -16153,23 +16204,27 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1615316204
if (status_length) {
1615416205
InitOcspResponse(response, single, status, input +*inOutIdx,
1615516206
status_length, ssl->heap);
16156-
16207+
response->pendingCAs = pendingCAs;
1615716208
if ((OcspResponseDecode(response, SSL_CM(ssl), ssl->heap,
1615816209
0) != 0)
1615916210
|| (response->responseStatus != OCSP_SUCCESSFUL)
1616016211
|| (response->single->status->status != CERT_GOOD))
1616116212
ret = BAD_CERTIFICATE_STATUS_ERROR;
1616216213

16163-
while (ret == 0) {
16214+
if (ret == 0) {
1616416215
request = (OcspRequest*)TLSX_CSR2_GetRequest(
16165-
ssl->extensions, status_type, idx++);
16216+
ssl->extensions, status_type, idx);
1616616217

16167-
if (request == NULL)
16218+
if (request == NULL) {
1616816219
ret = BAD_CERTIFICATE_STATUS_ERROR;
16169-
else if (CompareOcspReqResp(request, response) == 0)
16170-
break;
16171-
else if (idx == 1) /* server cert must be OK */
16220+
}
16221+
else if (CompareOcspReqResp(request, response) != 0) {
1617216222
ret = BAD_CERTIFICATE_STATUS_ERROR;
16223+
}
16224+
else {
16225+
if (idx == 0) /* server cert must be OK */
16226+
endCertificateOK = 1;
16227+
}
1617316228
}
1617416229

1617516230
/* only frees 'single' if single->isDynamic is set */
@@ -16178,6 +16233,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1617816233
*inOutIdx += status_length;
1617916234
list_length -= status_length;
1618016235
}
16236+
idx++;
1618116237
}
1618216238

1618316239
ssl->status_request_v2 = 0;
@@ -16197,6 +16253,20 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1619716253
ret = BUFFER_ERROR;
1619816254
}
1619916255

16256+
/* end certificate MUST be present */
16257+
if (endCertificateOK == 0)
16258+
ret = BAD_CERTIFICATE_STATUS_ERROR;
16259+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
16260+
if (ret == 0) {
16261+
if (TLSX_CSR2_MergePendingCA(ssl) < 0) {
16262+
WOLFSSL_MSG("Failed to merge pending CAs");
16263+
}
16264+
}
16265+
else {
16266+
TLSX_CSR2_ClearPendingCA(ssl);
16267+
}
16268+
#endif
16269+
1620016270
if (ret != 0) {
1620116271
WOLFSSL_ERROR_VERBOSE(ret);
1620216272
SendAlert(ssl, alert_fatal, bad_certificate_status_response);
@@ -16600,44 +16670,6 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
1660016670
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
1660116671
return OUT_OF_ORDER_E;
1660216672
}
16603-
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
16604-
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
16605-
if (ssl->msgsReceived.got_certificate_status == 0) {
16606-
int csrRet = 0;
16607-
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
16608-
if (csrRet == 0 && ssl->status_request) {
16609-
WOLFSSL_MSG("No CertificateStatus before ServerKeyExchange");
16610-
csrRet = TLSX_CSR_ForceRequest(ssl);
16611-
}
16612-
#endif
16613-
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
16614-
if (csrRet == 0 && ssl->status_request_v2) {
16615-
WOLFSSL_MSG("No CertificateStatus before ServerKeyExchange");
16616-
csrRet = TLSX_CSR2_ForceRequest(ssl);
16617-
}
16618-
#endif
16619-
if (csrRet != 0) {
16620-
/* Error out if OCSP lookups are enabled and failed or if
16621-
* the user requires stapling. */
16622-
if (SSL_CM(ssl)->ocspEnabled || SSL_CM(ssl)->ocspMustStaple)
16623-
return csrRet;
16624-
}
16625-
/* Check that a status request extension was seen as the
16626-
* CertificateStatus wasn't when an OCSP staple is required.
16627-
*/
16628-
if (
16629-
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
16630-
!ssl->status_request &&
16631-
#endif
16632-
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
16633-
!ssl->status_request_v2 &&
16634-
#endif
16635-
SSL_CM(ssl)->ocspMustStaple) {
16636-
WOLFSSL_ERROR_VERBOSE(OCSP_CERT_UNKNOWN);
16637-
return OCSP_CERT_UNKNOWN;
16638-
}
16639-
}
16640-
#endif
1664116673

1664216674
break;
1664316675
#endif
@@ -16710,6 +16742,54 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
1671016742
return OUT_OF_ORDER_E;
1671116743
}
1671216744
}
16745+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
16746+
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
16747+
if (ssl->msgsReceived.got_certificate_status == 0) {
16748+
int csrRet = 0;
16749+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
16750+
if (csrRet == 0 && ssl->status_request) {
16751+
WOLFSSL_MSG("No CertificateStatus before ServerHelloDone");
16752+
csrRet = TLSX_CSR_ForceRequest(ssl);
16753+
}
16754+
#endif
16755+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
16756+
if (csrRet == 0 && ssl->status_request_v2) {
16757+
WOLFSSL_MSG("No CertificateStatus before ServerHelloDone");
16758+
csrRet = TLSX_CSR2_ForceRequest(ssl);
16759+
}
16760+
if (ssl->status_request_v2) {
16761+
if (csrRet == 0) {
16762+
if (TLSX_CSR2_MergePendingCA(ssl) < 0) {
16763+
WOLFSSL_MSG("Failed to merge pending CAs");
16764+
}
16765+
}
16766+
else {
16767+
TLSX_CSR2_ClearPendingCA(ssl);
16768+
}
16769+
}
16770+
#endif
16771+
if (csrRet != 0) {
16772+
/* Error out if OCSP lookups are enabled and failed or if
16773+
* the user requires stapling. */
16774+
if (SSL_CM(ssl)->ocspEnabled || SSL_CM(ssl)->ocspMustStaple)
16775+
return csrRet;
16776+
}
16777+
/* Check that a status request extension was seen as the
16778+
* CertificateStatus wasn't when an OCSP staple is required.
16779+
*/
16780+
if (
16781+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
16782+
!ssl->status_request &&
16783+
#endif
16784+
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
16785+
!ssl->status_request_v2 &&
16786+
#endif
16787+
SSL_CM(ssl)->ocspMustStaple) {
16788+
WOLFSSL_ERROR_VERBOSE(OCSP_CERT_UNKNOWN);
16789+
return OCSP_CERT_UNKNOWN;
16790+
}
16791+
}
16792+
#endif
1671316793
break;
1671416794
#endif
1671516795

@@ -23187,7 +23267,7 @@ static int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request,
2318723267

2318823268
InitDecodedCert(cert, certData, length, ssl->heap);
2318923269
/* TODO: Setup async support here */
23190-
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, SSL_CM(ssl));
23270+
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, SSL_CM(ssl), NULL);
2319123271
if (ret != 0) {
2319223272
WOLFSSL_MSG("ParseCert failed");
2319323273
}

0 commit comments

Comments
 (0)