Skip to content

Commit 610da2a

Browse files
julek-wolfsslrizlik
andcommitted
tls ocsp: support lazy cert loading with ocsp stapling
- Expose dynamic TLS certificate loading via WOLFSSL_CERT_SETUP_CB - Expose OCSP Status Cb to load responses directly. This bypasses internal checks on the OCSP response which is desirable if the CA is not loaded on the server. - OCSP csr: Allow the user to provide OCSP responses to staple for the entire cert chain. - Add `wc_InitOCSP`, `wc_FreeOCSP`, and `wc_CheckCertOcspResponse` as wrapper functions around existing OCSP functionality - Add `wolfSSL_GetOcspStaple` to retrieve OCSP staple data in TLS 1.3 - Add test for OCSP cert callback - Expose store_ctx functions - Add cert-setup-cb to os-check Co-Authored-By: Marco Oliverio <marco@wolfssl.com>
1 parent d4f8c9c commit 610da2a

File tree

20 files changed

+1396
-347
lines changed

20 files changed

+1396
-347
lines changed

.github/workflows/os-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ jobs:
6060
'--disable-sys-ca-certs',
6161
'--enable-all CPPFLAGS=-DWOLFSSL_DEBUG_CERTS ',
6262
'--enable-all CFLAGS="-DWOLFSSL_CHECK_MEM_ZERO"',
63+
'--enable-dtls --enable-dtls13 --enable-ocspstapling --enable-cert-setup-cb',
6364
]
6465
name: make check
6566
if: github.repository_owner == 'wolfssl'

configure.ac

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9796,6 +9796,13 @@ AC_ARG_ENABLE([rpk],
97969796
[ ENABLED_RPK=no ]
97979797
)
97989798
9799+
# Allows dynamically loading the certificate
9800+
AC_ARG_ENABLE([cert-setup-cb],
9801+
[AS_HELP_STRING([--enable-cert-setup-cb],[Enable support for dynamically loading TLS certificates (default: disabled)])],
9802+
[ ENABLED_CERT_SETUP_CB=$enableval ],
9803+
[ ENABLED_CERT_SETUP_CB=no ]
9804+
)
9805+
97999806
# check if should run the trusted peer certs test
98009807
# (for now checking both C_FLAGS and C_EXTRA_FLAGS)
98019808
AS_CASE(["$CFLAGS $CPPFLAGS"],[*'WOLFSSL_TRUST_PEER_CERT'*],[ENABLED_TRUSTED_PEER_CERT=yes])
@@ -10217,6 +10224,9 @@ AS_IF([test "x$ENABLED_DUAL_ALG_CERTS" = "xyes"],
1021710224
AS_IF([test "x$ENABLED_RPK" = "xyes"],
1021810225
[AM_CFLAGS="$AM_CFLAGS -DHAVE_RPK"])
1021910226
10227+
AS_IF([test "x$ENABLED_CERT_SETUP_CB" = "xyes"],
10228+
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_SETUP_CB"])
10229+
1022010230
AS_IF([test "x$ENABLED_ALTNAMES" = "xyes"],
1022110231
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALT_NAMES"])
1022210232

src/internal.c

Lines changed: 113 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6721,13 +6721,21 @@ int InitSSL_Suites(WOLFSSL* ssl)
67216721
!havePSK && !haveAnon && !haveMcast) {
67226722

67236723
/* server certificate must be loaded */
6724-
if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) {
6724+
if ((!ssl->buffers.certificate || !ssl->buffers.certificate->buffer)
6725+
#ifdef WOLFSSL_CERT_SETUP_CB
6726+
&& ssl->ctx->certSetupCb == NULL
6727+
#endif
6728+
) {
67256729
WOLFSSL_MSG("Server missing certificate");
67266730
WOLFSSL_ERROR_VERBOSE(NO_PRIVATE_KEY);
67276731
return NO_PRIVATE_KEY;
67286732
}
67296733

6730-
if (!ssl->buffers.key || !ssl->buffers.key->buffer) {
6734+
if ((!ssl->buffers.key || !ssl->buffers.key->buffer)
6735+
#ifdef WOLFSSL_CERT_SETUP_CB
6736+
&& ssl->ctx->certSetupCb == NULL
6737+
#endif
6738+
) {
67316739
/* allow no private key if using existing key */
67326740
#ifdef WOLF_PRIVATE_KEY_ID
67336741
if (ssl->devId != INVALID_DEVID
@@ -7037,9 +7045,7 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
70377045
ssl->buffers.certificate = ctx->certificate;
70387046
ssl->buffers.certChain = ctx->certChain;
70397047
#endif
7040-
#ifdef WOLFSSL_TLS13
70417048
ssl->buffers.certChainCnt = ctx->certChainCnt;
7042-
#endif
70437049
#ifndef WOLFSSL_BLIND_PRIVATE_KEY
70447050
#ifdef WOLFSSL_COPY_KEY
70457051
if (ctx->privateKey != NULL) {
@@ -8702,11 +8708,12 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
87028708
#ifdef OPENSSL_EXTRA
87038709
XFREE(ssl->param, ssl->heap, DYNAMIC_TYPE_OPENSSL);
87048710
#endif
8705-
#if defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY))
8706-
if (ssl->ocspResp) {
8707-
XFREE(ssl->ocspResp, NULL, 0);
8708-
ssl->ocspResp = NULL;
8709-
ssl->ocspRespSz = 0;
8711+
#if defined(HAVE_OCSP)
8712+
{
8713+
size_t i;
8714+
for (i = 0; i < XELEM_CNT(ssl->ocspCsrResp); i++)
8715+
XFREE(ssl->ocspCsrResp[i].buffer, NULL, 0);
8716+
XMEMSET(ssl->ocspCsrResp, 0, sizeof(ssl->ocspCsrResp));
87108717
}
87118718
#endif /* defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) */
87128719
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
@@ -9037,11 +9044,12 @@ void FreeHandshakeResources(WOLFSSL* ssl)
90379044
* !WOLFSSL_POST_HANDSHAKE_AUTH */
90389045
#endif /* HAVE_TLS_EXTENSIONS && !NO_TLS */
90399046

9040-
#if defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY))
9041-
if (ssl->ocspResp != NULL) {
9042-
XFREE(ssl->ocspResp, NULL, 0);
9043-
ssl->ocspResp = NULL;
9044-
ssl->ocspRespSz = 0;
9047+
#if defined(HAVE_OCSP)
9048+
{
9049+
size_t i;
9050+
for (i = 0; i < XELEM_CNT(ssl->ocspCsrResp); i++)
9051+
XFREE(ssl->ocspCsrResp[i].buffer, NULL, 0);
9052+
XMEMSET(ssl->ocspCsrResp, 0, sizeof(ssl->ocspCsrResp));
90459053
}
90469054
#endif /* defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) */
90479055

@@ -13897,6 +13905,29 @@ int CopyDecodedAcertToX509(WOLFSSL_X509_ACERT* x509, DecodedAcert* dAcert)
1389713905

1389813906
#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
1389913907
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && !defined(WOLFSSL_NO_TLS12)
13908+
static int CsrDoStatusVerifyCb(WOLFSSL* ssl, byte* input, word32 inputSz, word32 idx,
13909+
int ret)
13910+
{
13911+
if (ssl->ctx->ocspStatusVerifyCb != NULL) {
13912+
int verRet;
13913+
WOLFSSL_MSG("Calling OCSP status verify callback");
13914+
verRet = ssl->ctx->ocspStatusVerifyCb(ssl, ret,
13915+
input, inputSz, idx, ssl->ctx->ocspStatusVerifyCbArg);
13916+
if (verRet > 0) {
13917+
WOLFSSL_MSG("\tInvalid OCSP status verify callback return");
13918+
ret = BAD_CERTIFICATE_STATUS_ERROR;
13919+
}
13920+
else {
13921+
if (ret == 0 && verRet < 0)
13922+
WOLFSSL_MSG("\tforcing error");
13923+
else if (ret < 0 && verRet == 0)
13924+
WOLFSSL_MSG("\toverriding error");
13925+
ret = verRet;
13926+
}
13927+
}
13928+
return ret;
13929+
}
13930+
1390013931
static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1390113932
word32 status_length, int idx)
1390213933
{
@@ -13949,9 +13980,6 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1394913980
return BUFFER_ERROR;
1395013981
} while(0);
1395113982

13952-
if (request == NULL)
13953-
return BAD_CERTIFICATE_STATUS_ERROR; /* not expected */
13954-
1395513983
#ifdef WOLFSSL_SMALL_STACK
1395613984
status = (CertStatus*)XMALLOC(sizeof(CertStatus), ssl->heap,
1395713985
DYNAMIC_TYPE_OCSP_STATUS);
@@ -13976,22 +14004,34 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1397614004
#endif
1397714005

1397814006
/* InitOcspResponse sets single and status to response struct. */
13979-
InitOcspResponse(response, single, status, input +*inOutIdx, status_length, ssl->heap);
14007+
InitOcspResponse(response, single, status, input +*inOutIdx, status_length,
14008+
ssl->heap);
1398014009

13981-
if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 0, 0) != 0)
13982-
ret = BAD_CERTIFICATE_STATUS_ERROR;
13983-
else if (CompareOcspReqResp(request, response) != 0)
13984-
ret = BAD_CERTIFICATE_STATUS_ERROR;
13985-
else if (response->responseStatus != OCSP_SUCCESSFUL)
14010+
/* Extract producedDate */
14011+
if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0)
1398614012
ret = BAD_CERTIFICATE_STATUS_ERROR;
13987-
else if (response->single->status->status == CERT_REVOKED)
13988-
ret = OCSP_CERT_REVOKED;
13989-
else if (response->single->status->status != CERT_GOOD)
13990-
ret = BAD_CERTIFICATE_STATUS_ERROR;
13991-
13992-
else {
13993-
XMEMCPY(ssl->ocspProducedDate, response->producedDate, sizeof ssl->ocspProducedDate);
14013+
if (ret == 0) {
14014+
XMEMCPY(ssl->ocspProducedDate, response->producedDate,
14015+
sizeof(ssl->ocspProducedDate));
1399414016
ssl->ocspProducedDateFormat = response->producedDateFormat;
14017+
14018+
/* Reset response */
14019+
FreeOcspResponse(response);
14020+
InitOcspResponse(response, single, status, input + *inOutIdx,
14021+
status_length, ssl->heap);
14022+
14023+
if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 0, 0) != 0)
14024+
ret = BAD_CERTIFICATE_STATUS_ERROR;
14025+
else if (CompareOcspReqResp(request, response) != 0)
14026+
ret = BAD_CERTIFICATE_STATUS_ERROR;
14027+
else if (response->responseStatus != OCSP_SUCCESSFUL)
14028+
ret = BAD_CERTIFICATE_STATUS_ERROR;
14029+
else if (response->single->status->status == CERT_REVOKED)
14030+
ret = OCSP_CERT_REVOKED;
14031+
else if (response->single->status->status != CERT_GOOD)
14032+
ret = BAD_CERTIFICATE_STATUS_ERROR;
14033+
14034+
ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret);
1399514035
}
1399614036

1399714037
*inOutIdx += status_length;
@@ -17121,15 +17161,16 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1712117161
else if (CompareOcspReqResp(request, response) != 0) {
1712217162
ret = BAD_CERTIFICATE_STATUS_ERROR;
1712317163
}
17124-
else {
17125-
if (idx == 0) /* server cert must be OK */
17126-
endCertificateOK = 1;
17127-
}
1712817164
}
1712917165

1713017166
/* only frees 'single' if single->isDynamic is set */
1713117167
FreeOcspResponse(response);
1713217168

17169+
ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length,
17170+
idx, ret);
17171+
if (ret == 0 && idx == 0) /* server cert must be OK */
17172+
endCertificateOK = 1;
17173+
1713317174
*inOutIdx += status_length;
1713417175
list_length -= status_length;
1713517176
}
@@ -24325,10 +24366,9 @@ int CreateOcspRequest(WOLFSSL* ssl, OcspRequest* request,
2432524366

2432624367
InitDecodedCert(cert, certData, length, ssl->heap);
2432724368
/* TODO: Setup async support here */
24328-
ret = ParseCertRelative(cert, CERT_TYPE, VERIFY, SSL_CM(ssl), NULL);
24329-
if (ret != 0) {
24369+
ret = ParseCertRelative(cert, CERT_TYPE, NO_VERIFY, SSL_CM(ssl), NULL);
24370+
if (ret != 0)
2433024371
WOLFSSL_MSG("ParseCert failed");
24331-
}
2433224372
if (ret == 0)
2433324373
ret = InitOcspRequest(request, cert, 0, ssl->heap);
2433424374
if (ret == 0) {
@@ -25081,51 +25121,53 @@ static int BuildCertificateStatus(WOLFSSL* ssl, byte type, buffer* status,
2508125121
}
2508225122
#endif
2508325123

25084-
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
25085-
(defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
25086-
defined(WOLFSSL_HAPROXY))
25087-
static int BuildCertificateStatusWithStatusCB(WOLFSSL* ssl)
25124+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
25125+
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
25126+
static int BuildCertificateStatusWithStatusCB(WOLFSSL* ssl, byte status_type)
2508825127
{
2508925128
WOLFSSL_OCSP *ocsp;
25090-
void *ioCtx = NULL;
25091-
buffer response;
25092-
int ret;
25129+
int ret = 0;
2509325130

25094-
if (ssl == NULL) {
25131+
if (ssl == NULL || (status_type != WOLFSSL_CSR2_OCSP &&
25132+
status_type != WOLFSSL_CSR2_OCSP_MULTI))
2509525133
return BAD_FUNC_ARG;
25096-
}
2509725134

2509825135
ocsp = SSL_CM(ssl)->ocsp_stapling;
2509925136
if (ocsp == NULL || ocsp->statusCb == NULL)
2510025137
return BAD_FUNC_ARG;
25101-
ioCtx = (ssl->ocspIOCtx != NULL) ? ssl->ocspIOCtx : ocsp->cm->ocspIOCtx;
25102-
XMEMSET(&response, 0, sizeof(response));
2510325138
WOLFSSL_MSG("Calling ocsp->statusCb");
25104-
ret = ocsp->statusCb(ssl, ioCtx);
25139+
ret = ocsp->statusCb(ssl, ocsp->statusCbArg);
2510525140
switch (ret) {
25106-
case SSL_TLSEXT_ERR_OK:
25107-
if (ssl->ocspResp == NULL || ssl->ocspRespSz == 0) {
25108-
ret = 0;
25109-
break;
25141+
case WOLFSSL_OCSP_STATUS_CB_OK: {
25142+
byte cnt = 1;
25143+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
25144+
if (status_type == WOLFSSL_CSR2_OCSP_MULTI) {
25145+
/* Find last response set */
25146+
for (cnt = XELEM_CNT(ssl->ocspCsrResp);
25147+
cnt > 0 && ssl->ocspCsrResp[cnt-1].buffer == NULL;
25148+
cnt--);
25149+
cnt = MIN(cnt, ssl->buffers.certChainCnt + 1);
2511025150
}
25111-
response.buffer = ssl->ocspResp;
25112-
response.length = ssl->ocspRespSz;
25113-
ret = BuildCertificateStatus(ssl, WOLFSSL_CSR_OCSP, &response, 1);
25151+
#endif
25152+
ret = BuildCertificateStatus(ssl, status_type, ssl->ocspCsrResp,
25153+
cnt);
2511425154
break;
25115-
case SSL_TLSEXT_ERR_NOACK:
25155+
}
25156+
case WOLFSSL_OCSP_STATUS_CB_NOACK:
2511625157
/* No OCSP response to send */
2511725158
ret = 0;
2511825159
break;
25119-
case SSL_TLSEXT_ERR_ALERT_FATAL:
25160+
case WOLFSSL_OCSP_STATUS_CB_ALERT_FATAL:
2512025161
/* fall through */
2512125162
default:
2512225163
ret = WOLFSSL_FATAL_ERROR;
2512325164
break;
2512425165
}
25166+
2512525167
return ret;
2512625168
}
25127-
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST && (defined(OPENSSL_ALL) ||
25128-
defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)) */
25169+
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST ||
25170+
* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
2512925171

2513025172
#endif /* NO_WOLFSSL_SERVER */
2513125173

@@ -25151,13 +25193,11 @@ int SendCertificateStatus(WOLFSSL* ssl)
2515125193
status_type = status_type ? status_type : ssl->status_request_v2;
2515225194
#endif
2515325195

25154-
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
25155-
(defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
25156-
defined(WOLFSSL_HAPROXY))
25196+
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
25197+
defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
2515725198
if (SSL_CM(ssl)->ocsp_stapling != NULL &&
2515825199
SSL_CM(ssl)->ocsp_stapling->statusCb != NULL) {
25159-
if (ssl->status_request == WOLFSSL_CSR_OCSP)
25160-
return BuildCertificateStatusWithStatusCB(ssl);
25200+
return BuildCertificateStatusWithStatusCB(ssl, status_type);
2516125201
}
2516225202
#endif
2516325203

@@ -25247,14 +25287,14 @@ int SendCertificateStatus(WOLFSSL* ssl)
2524725287
return MEMORY_E;
2524825288
}
2524925289

25250-
/* use certChain if available, otherwise use peer certificate */
25290+
/* use certChain if available, otherwise use certificate */
2525125291
chain = ssl->buffers.certChain;
2525225292
if (chain == NULL) {
2525325293
chain = ssl->buffers.certificate;
2525425294
}
2525525295

2525625296
if (chain && chain->buffer) {
25257-
while (idx + OPAQUE24_LEN < chain->length) {
25297+
while (ret == 0 && idx + OPAQUE24_LEN < chain->length) {
2525825298
c24to32(chain->buffer + idx, &der.length);
2525925299
idx += OPAQUE24_LEN;
2526025300

@@ -25267,7 +25307,7 @@ int SendCertificateStatus(WOLFSSL* ssl)
2526725307
der.length, &ctxOwnsRequest);
2526825308
if (ret == 0) {
2526925309
request->ssl = ssl;
25270-
ret = CheckOcspRequest(SSL_CM(ssl)->ocsp_stapling,
25310+
ret = CheckOcspRequest(SSL_CM(ssl)->ocsp_stapling,
2527125311
request, &responses[i + 1], ssl->heap);
2527225312

2527325313
/* Suppressing, not critical */
@@ -31670,7 +31710,8 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
3167031710
word16 len;
3167131711
word32 begin = *inOutIdx;
3167231712
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) || \
31673-
defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)
31713+
defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY) || \
31714+
defined(WOLFSSL_CERT_SETUP_CB)
3167431715
int ret;
3167531716
#endif
3167631717
#ifdef OPENSSL_EXTRA
@@ -31817,6 +31858,7 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
3181731858
len -= (word16)(OPAQUE16_LEN) + dnSz;
3181831859
}
3181931860

31861+
#ifdef WOLFSSL_CERT_SETUP_CB
3182031862
#ifdef OPENSSL_EXTRA
3182131863
/* call client cert callback if no cert has been loaded */
3182231864
if ((ssl->ctx->CBClientCert != NULL) &&
@@ -31838,6 +31880,7 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
3183831880
return WOLFSSL_ERROR_WANT_X509_LOOKUP;
3183931881
}
3184031882
}
31883+
#endif
3184131884
if ((ret = CertSetupCbWrapper(ssl)) != 0)
3184231885
return ret;
3184331886
#endif
@@ -38671,7 +38714,7 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
3867138714
#endif
3867238715
#endif
3867338716

38674-
#ifdef OPENSSL_EXTRA
38717+
#ifdef WOLFSSL_CERT_SETUP_CB
3867538718
/* Give user last chance to provide a cert for cipher selection */
3867638719
if (ret == 0 && ssl->ctx->certSetupCb != NULL)
3867738720
ret = CertSetupCbWrapper(ssl);

0 commit comments

Comments
 (0)