From a913676a881b5a872f0e26662dabd6dc8942a949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 21 Sep 2026 18:25:52 +0200 Subject: [PATCH 1/3] zephyr: resolve an OCSP responder through getaddrinfo HAVE_OCSP makes wolfio.h define HAVE_HTTP_CLIENT, which compiles wolfIO_TcpConnect() into a Zephyr build. Without HAVE_SOCKADDR its body is the stub that always fails, and zephyr/user_settings.h defined HAVE_SOCKADDR only for CONFIG_WOLFSSL_DTLS, so a Zephyr client with OCSP but no DTLS could never reach a responder. With HAVE_SOCKADDR set, the body took the gethostbyname() branch, because nothing defined HAVE_GETADDRINFO for Zephyr. That fails with an implicit declaration and an incomplete struct hostent: Zephyr has no gethostbyname() at all, only gethostent() in its POSIX netdb.h. Name resolution goes through zsock_getaddrinfo(), which this block already maps getaddrinfo/freeaddrinfo/ADDRINFO onto; only the switch was missing. Define HAVE_SOCKADDR in the Zephyr socket block whenever the HTTP client is compiled in (HAVE_OCSP or HAVE_CRL_IO), and HAVE_GETADDRINFO for every Zephyr build. The OCSP responder screen, wolfIO_OcspDestAllowed(), has the same resolver fallback and now uses getaddrinfo too. Nothing in CI built the HTTP client for Zephyr, so add an OCSP and stapling build without DTLS to the Zephyr 4.x list. It compiles the client in and runs the TLS socket sample, which does no OCSP lookup. --- .github/scripts/zephyr-4.x/builds.txt | 1 + .github/scripts/zephyr-4.x/ocsp.conf | 3 +++ wolfssl/wolfio.h | 7 +++++++ 3 files changed, 11 insertions(+) create mode 100644 .github/scripts/zephyr-4.x/ocsp.conf diff --git a/.github/scripts/zephyr-4.x/builds.txt b/.github/scripts/zephyr-4.x/builds.txt index ea987610af9..b1316f7b98c 100644 --- a/.github/scripts/zephyr-4.x/builds.txt +++ b/.github/scripts/zephyr-4.x/builds.txt @@ -3,6 +3,7 @@ native_sim samples/wolfssl_tls_sock native_sim samples/wolfssl_tls_sock external_libc.conf native_sim samples/wolfssl_tls_sock tls_cert.conf +native_sim samples/wolfssl_tls_sock ocsp.conf native_sim samples/wolfssl_test native_sim samples/wolfssl_test external_libc.conf native_sim samples/wolfssl_benchmark diff --git a/.github/scripts/zephyr-4.x/ocsp.conf b/.github/scripts/zephyr-4.x/ocsp.conf new file mode 100644 index 00000000000..beda6b3dce3 --- /dev/null +++ b/.github/scripts/zephyr-4.x/ocsp.conf @@ -0,0 +1,3 @@ +# OCSP and stapling +CONFIG_WOLFSSL_OCSP=y +CONFIG_WOLFSSL_OCSP_STAPLING=y diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 56b3f96879e..b359cace2bd 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -505,6 +505,10 @@ #define SEND_FUNCTION send #define RECV_FUNCTION recv #endif + #if defined(HAVE_HTTP_CLIENT) && !defined(HAVE_SOCKADDR) && \ + !defined(WOLFSSL_NO_SOCK) + #define HAVE_SOCKADDR + #endif #elif defined(WOLFSSL_LINUXKM) #define SEND_FUNCTION linuxkm_send #define RECV_FUNCTION linuxkm_recv @@ -578,6 +582,9 @@ #endif /* HAVE_SOCKADDR */ #if defined(WOLFSSL_ZEPHYR) + #ifndef HAVE_GETADDRINFO + #define HAVE_GETADDRINFO + #endif typedef struct zsock_addrinfo ADDRINFO; #define getaddrinfo zsock_getaddrinfo #define freeaddrinfo zsock_freeaddrinfo From 0fa604a11bfe2d8177b7cc89cd0a65d807e490a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 2 Nov 2026 13:24:12 +0100 Subject: [PATCH 2/3] Let a client-only build set the OCSP status verify callback wolfSSL_CTX_set_ocsp_status_verify_cb() hooks the client's check of a stapled OCSP response: ProcessCSR_ex() and the TLS 1.2 certificate_status handler pass their result through it, so the application can record the outcome or override an error. Its setter, the WOLFSSL_CTX fields and both call sites were all under NO_WOLFSSL_SERVER, next to the server's own stapling state, so a build with NO_WOLFSSL_SERVER declared the setter in ssl.h but did not define it, and never consulted the callback. Guard them on HAVE_CERTIFICATE_STATUS_REQUEST(_V2) alone, like the rest of the status request code that runs on the client. The new test sets the callback on a client CTX, so the client-only os-check builds link and run the setter. --- src/internal.c | 6 --- src/ssl_api_crl_ocsp.c | 2 - tests/api/test_ssl_crl_ocsp.c | 43 +++++++++++++++++++ tests/api/test_ssl_crl_ocsp.h | 3 ++ .../unit-mcdc/test_internal_status_whitebox.c | 17 +++++--- wolfssl/internal.h | 7 ++- 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/internal.c b/src/internal.c index 0c54d776a0d..5f500f60aec 100644 --- a/src/internal.c +++ b/src/internal.c @@ -16596,7 +16596,6 @@ int CsrDoChainFallbackLookup(WOLFSSL* ssl, OcspRequest* request, int idx) (defined(HAVE_OCSP) && defined(WOLFSSL_TLS13) && \ defined(HAVE_CERTIFICATE_STATUS_REQUEST))) #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) -#ifndef NO_WOLFSSL_SERVER static int CsrDoStatusVerifyCb(WOLFSSL* ssl, byte* input, word32 inputSz, word32 idx, int ret) { @@ -16619,7 +16618,6 @@ static int CsrDoStatusVerifyCb(WOLFSSL* ssl, byte* input, word32 inputSz, word32 } return ret; } -#endif /* !NO_WOLFSSL_SERVER */ /* Parses one certificate_status message. TLS 1.3 reads the per-certificate * entries of the chain through this, so it is not tied to TLS 1.2. */ @@ -16726,9 +16724,7 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, else if (response->single->status->status != CERT_GOOD) ret = BAD_CERTIFICATE_STATUS_ERROR; -#ifndef NO_WOLFSSL_SERVER ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); -#endif } *inOutIdx += status_length; @@ -20976,10 +20972,8 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* only frees 'single' if single->isDynamic is set */ FreeOcspResponse(response); - #ifndef NO_WOLFSSL_SERVER ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); - #endif if (ret == 0 && idx == 0) /* server cert must be OK */ endCertificateOK = 1; #if defined(HAVE_OCSP) && defined(WOLFSSL_NONBLOCK_OCSP) diff --git a/src/ssl_api_crl_ocsp.c b/src/ssl_api_crl_ocsp.c index e65e38a1db8..8afa84699c8 100644 --- a/src/ssl_api_crl_ocsp.c +++ b/src/ssl_api_crl_ocsp.c @@ -1289,7 +1289,6 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, return ret; } -#ifndef NO_WOLFSSL_SERVER /* Set the callback that verifies a stapled OCSP response. * * @param [in, out] ctx SSL/TLS context. @@ -1304,7 +1303,6 @@ void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, ctx->ocspStatusVerifyCbArg = cbArg; } } -#endif /* NO_WOLFSSL_SERVER */ #endif /* HAVE_CERTIFICATE_STATUS_REQUEST || * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ diff --git a/tests/api/test_ssl_crl_ocsp.c b/tests/api/test_ssl_crl_ocsp.c index eefae57313f..3bdf6dae3ea 100644 --- a/tests/api/test_ssl_crl_ocsp.c +++ b/tests/api/test_ssl_crl_ocsp.c @@ -257,6 +257,49 @@ int test_wolfSSL_CTX_tlsext_status_cb(void) return EXPECT_RESULT(); } +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) +static int test_ssl_crl_ocsp_verify_cb(WOLFSSL* ssl, int err, byte* resp, + word32 respSz, word32 idx, void* arg) +{ + (void)ssl; + (void)resp; + (void)respSz; + (void)idx; + (void)arg; + return err; +} +#endif + +/* Test setting the OCSP status verify callback on a client CTX. + * + * @return TEST_SUCCESS on success. + */ +int test_wolfSSL_CTX_set_ocsp_status_verify_cb(void) +{ + EXPECT_DECLS; +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + int arg = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + wolfSSL_CTX_set_ocsp_status_verify_cb(ctx, test_ssl_crl_ocsp_verify_cb, + &arg); + ExpectTrue((ctx != NULL) && + (ctx->ocspStatusVerifyCb == test_ssl_crl_ocsp_verify_cb)); + ExpectTrue((ctx != NULL) && (ctx->ocspStatusVerifyCbArg == &arg)); + + wolfSSL_CTX_set_ocsp_status_verify_cb(ctx, NULL, NULL); + ExpectTrue((ctx != NULL) && (ctx->ocspStatusVerifyCb == NULL)); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /* Test storing and retrieving a stapled OCSP response. * * @return TEST_SUCCESS on success. diff --git a/tests/api/test_ssl_crl_ocsp.h b/tests/api/test_ssl_crl_ocsp.h index d3cbbb4d6b7..cc3abc449b2 100644 --- a/tests/api/test_ssl_crl_ocsp.h +++ b/tests/api/test_ssl_crl_ocsp.h @@ -28,6 +28,7 @@ int test_wolfSSL_ocsp_url_api(void); int test_wolfSSL_get_ocsp_producedDate(void); int test_wolfSSL_tlsext_status_type(void); int test_wolfSSL_CTX_tlsext_status_cb(void); +int test_wolfSSL_CTX_set_ocsp_status_verify_cb(void); int test_wolfSSL_tlsext_status_ocsp_resp(void); int test_wolfSSL_OCSP_parse_url_api(void); @@ -36,6 +37,8 @@ int test_wolfSSL_OCSP_parse_url_api(void); TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_get_ocsp_producedDate), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_tlsext_status_type), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_CTX_tlsext_status_cb), \ + TEST_DECL_GROUP("ssl_crl_ocsp", \ + test_wolfSSL_CTX_set_ocsp_status_verify_cb), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_tlsext_status_ocsp_resp), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_OCSP_parse_url_api) diff --git a/tests/unit-mcdc/test_internal_status_whitebox.c b/tests/unit-mcdc/test_internal_status_whitebox.c index ea8c1bd10e1..91738a5b1bf 100644 --- a/tests/unit-mcdc/test_internal_status_whitebox.c +++ b/tests/unit-mcdc/test_internal_status_whitebox.c @@ -64,9 +64,16 @@ static int wb_send_sink(WOLFSSL* ssl, char* buf, int sz, void* ctx) /* ------------------------------------------------- CsrDoStatusVerifyCb */ -#if !defined(NO_WOLFSSL_SERVER) && \ - (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ - defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + (!defined(WOLFSSL_NO_TLS12) || \ + (defined(HAVE_OCSP) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST))) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) + #define WB_HAVE_CSR_VERIFY_CB +#endif + +#ifdef WB_HAVE_CSR_VERIFY_CB static int g_verRet; /* what the mock callback returns */ @@ -207,9 +214,7 @@ int main(void) goto done; } -#if !defined(NO_WOLFSSL_SERVER) && \ - (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ - defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) +#ifdef WB_HAVE_CSR_VERIFY_CB wb_csr_status_verify(ssl, ctx); #endif wb_do_certificate_status(ssl, ctx); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d293decb603..dcf0ba4e0c3 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4790,13 +4790,16 @@ struct WOLFSSL_CTX { #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) OcspRequest* certOcspRequest; - ocspVerifyStatusCb ocspStatusVerifyCb; - void* ocspStatusVerifyCbArg; #endif #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) OcspRequest* chainOcspRequest[MAX_CHAIN_DEPTH]; #endif #endif + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + ocspVerifyStatusCb ocspStatusVerifyCb; + void* ocspStatusVerifyCbArg; + #endif #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) SessionTicketEncCb ticketEncCb; /* enc/dec session ticket Cb */ void* ticketEncCtx; /* session encrypt context */ From c597aef559710008fd61676b6e3441bab14ea44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 3 Nov 2026 14:45:43 +0100 Subject: [PATCH 3/3] Let the OCSP status verify callback see a staple that does not decode ProcessCSR_ex() decodes a stapled response twice, the first time only to read producedAt, and called CsrDoStatusVerifyCb() only when that first decode succeeded. A staple that is not a well-formed OCSPResponse therefore failed the handshake with BAD_CERTIFICATE_STATUS_ERROR without reaching the callback, so the application could neither see nor override that error, although it can for a response that decodes and then fails verification. ProcessCSR() handles a TLS 1.2 status_request through this function, and TLS 1.3 reads each certificate's staple through it. Call the callback after both decodes whatever their result, as the status_request_v2 multi handler already does. A failed first decode now also clears the recorded producedAt format, so a handshake the callback lets through does not report an earlier staple's date from wolfSSL_get_ocsp_producedDate(). The callback's documentation now says when it runs and what its return value does, since a callback that returns 0 for BAD_CERTIFICATE_STATUS_ERROR now also accepts a staple that does not decode. The new test staples a truncated response over TLS 1.2 and TLS 1.3, checks that the callback runs once for index 0 with the staple's length and BAD_CERTIFICATE_STATUS_ERROR, that the handshake fails with a bad_certificate_status_response alert unless the callback overrides the error, and that no produced date is reported. --- doc/dox_comments/header_files-ja/ssl.h | 2 + doc/dox_comments/header_files/ssl.h | 9 ++ src/internal.c | 8 +- tests/api.c | 1 + tests/api/test_ocsp.c | 154 +++++++++++++++++++++++++ tests/api/test_ocsp.h | 1 + 6 files changed, 172 insertions(+), 3 deletions(-) diff --git a/doc/dox_comments/header_files-ja/ssl.h b/doc/dox_comments/header_files-ja/ssl.h index b8398d1c9bc..2b1e139f362 100644 --- a/doc/dox_comments/header_files-ja/ssl.h +++ b/doc/dox_comments/header_files-ja/ssl.h @@ -4869,6 +4869,8 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, \brief OCSPステータスレスポンスを検証するコールバックを設定します。 + クライアントは処理するステープルOCSPレスポンスごとに、デコードできないものも含めてこのコールバックを呼び出します。クライアント証明書を検証するTLS 1.3サーバーも同様です。errにはライブラリの判定結果(0または負のエラーコード)が渡されます。証明書チェーンの処理は最初に失敗したレスポンスで停止するため、それ以降のレスポンスは渡されません。戻り値がerrを置き換えます。0はレスポンスを受け入れ、負の値はハンドシェイクを失敗させ、正の値はBAD_CERTIFICATE_STATUS_ERRORとして扱われます。 + OCSP検証中にピアの証明書チェーンにアクセスできるようにするため、SESSION_CERTSを有効にすることを推奨します。 \param ctx WOLFSSL_CTXオブジェクト。 diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 5884a417171..195f9cddf06 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -6611,6 +6611,15 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, \brief Sets a callback to verify the OCSP status response. + The client calls it for each stapled OCSP response it processes, as does a + TLS 1.3 server checking the client's certificate, including a response + that does not decode. err holds the library's result (0 or a negative + error code). Processing of a certificate chain stops at the first + response that fails, so later responses are not passed to it. The return + value replaces err: 0 accepts the response, a negative value fails the + handshake, and a positive value is treated as + BAD_CERTIFICATE_STATUS_ERROR. + It is recommended to enable SESSION_CERTS in order to have access to the peer's certificate chain during OCSP verification. diff --git a/src/internal.c b/src/internal.c index 5f500f60aec..5e272f29609 100644 --- a/src/internal.c +++ b/src/internal.c @@ -16701,8 +16701,10 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, ssl->heap); /* Extract producedDate */ - if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0) + if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0) { + ssl->ocspProducedDateFormat = 0; ret = BAD_CERTIFICATE_STATUS_ERROR; + } if (ret == 0) { XMEMCPY(ssl->ocspProducedDate, response->producedDate, sizeof(ssl->ocspProducedDate)); @@ -16723,10 +16725,10 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = OCSP_CERT_REVOKED; else if (response->single->status->status != CERT_GOOD) ret = BAD_CERTIFICATE_STATUS_ERROR; - - ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); } + ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); + *inOutIdx += status_length; /* FreeOcspResponse frees status and single only if diff --git a/tests/api.c b/tests/api.c index d03a32080f4..e510632bf24 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47395,6 +47395,7 @@ TEST_CASE testCases[] = { TEST_DECL_GROUP("ocsp", test_ocsp_resp_times), TEST_DECL(test_ocsp_tls_cert_cb), TEST_DECL_GROUP("ocsp", test_ocsp_status_request_v2_multi_revoked_single), + TEST_DECL_GROUP("ocsp", test_ocsp_status_verify_cb_undecodable_staple), TEST_DECL_GROUP("ocsp", test_ocsp_cert_unknown_crl_fallback), TEST_DECL_GROUP("ocsp", test_ocsp_cert_unknown_crl_fallback_nonleaf), TEST_DECL_GROUP("ocsp", test_ocsp_no_url_policy), diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index c68f939df42..fbe6be01573 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -1973,11 +1973,165 @@ int test_ocsp_status_request_v2_multi_revoked_single(void) } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 && !WOLFSSL_NO_TLS12 */ +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST +/* A SEQUENCE header that claims more bytes than follow */ +static const byte test_ocsp_undecodable_staple_junk[] = { + 0x30, 0x05, 0x0a, 0x01, 0x00 +}; +static int test_ocsp_undecodable_staple_calls; +static int test_ocsp_undecodable_staple_err; +static word32 test_ocsp_undecodable_staple_idx; +static word32 test_ocsp_undecodable_staple_sz; + +static int test_ocsp_undecodable_staple_status_cb(WOLFSSL* ssl, void* ioCtx) +{ + byte* staple; + + (void)ioCtx; + staple = (byte*)XMALLOC(sizeof(test_ocsp_undecodable_staple_junk), NULL, + 0); + if (staple == NULL) + return WOLFSSL_OCSP_STATUS_CB_ALERT_FATAL; + XMEMCPY(staple, test_ocsp_undecodable_staple_junk, + sizeof(test_ocsp_undecodable_staple_junk)); + if (wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, staple, + sizeof(test_ocsp_undecodable_staple_junk), 0) != WOLFSSL_SUCCESS) { + XFREE(staple, NULL, 0); + return WOLFSSL_OCSP_STATUS_CB_ALERT_FATAL; + } + return WOLFSSL_OCSP_STATUS_CB_OK; +} + +static int test_ocsp_undecodable_staple_verify_cb(WOLFSSL* ssl, int err, + byte* staple, word32 stapleSz, word32 idx, void* arg) +{ + (void)ssl; + (void)staple; + test_ocsp_undecodable_staple_calls++; + test_ocsp_undecodable_staple_err = err; + test_ocsp_undecodable_staple_idx = idx; + test_ocsp_undecodable_staple_sz = stapleSz; + return (arg != NULL) ? 0 : err; +} + +/* + * The OCSP status verify callback sees a stapled response that does not + * decode, and can override the error like any other staple failure. + */ +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + EXPECT_DECLS; + size_t i; + int override; + WOLFSSL_ALERT_HISTORY h; +#ifndef NO_ASN_TIME + byte date[MAX_DATE_SIZE]; + int fmt = 0; +#endif + struct { + method_provider client_meth; + method_provider server_meth; + const char* tls_version; + } params[] = { +#if !defined(WOLFSSL_NO_TLS12) + { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }, +#endif +#ifdef WOLFSSL_TLS13 + { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }, +#endif + }; + + for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { + for (override = 0; override <= 1 && !EXPECT_FAIL(); override++) { + struct test_ssl_memio_ctx test_ctx; + + printf("\nTesting %s, %s\n", params[i].tls_version, + override ? "callback overrides" : "callback keeps error"); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.c_cb.caPemFile = ""; + test_ctx.s_cb.certPemFile = ""; + test_ctx.s_cb.keyPemFile = ""; + test_ctx.c_cb.method = params[i].client_meth; + test_ctx.s_cb.method = params[i].server_meth; + test_ocsp_tls_cert_cb_opts.chainLen = 1; + test_ocsp_tls_cert_cb_opts.failStaple = 0; + test_ctx.s_cb.ctx_ready = test_ocsp_tls_cert_cb_ctx_ready; + + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); + ExpectIntEQ(wolfSSL_UnloadCertsKeys(test_ctx.s_ssl), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.s_ctx), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx, + test_ocsp_undecodable_staple_status_cb), WOLFSSL_SUCCESS); + + wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_DEFAULT, + test_ocsp_tls_cert_cb_verify_cb); + wolfSSL_SetCertCbCtx(test_ctx.c_ssl, test_ctx.c_ssl); + wolfSSL_CTX_set_ocsp_status_verify_cb(test_ctx.c_ctx, + test_ocsp_undecodable_staple_verify_cb, + override ? &test_ctx : NULL); + ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseOCSPStapling(test_ctx.c_ssl, + WOLFSSL_CSR_OCSP, 0), WOLFSSL_SUCCESS); + + #ifndef NO_ASN_TIME + /* Stale date from an earlier staple */ + if (test_ctx.c_ssl != NULL) { + XSTRNCPY((char*)test_ctx.c_ssl->ocspProducedDate, + "260101000000Z", + sizeof(test_ctx.c_ssl->ocspProducedDate)); + test_ctx.c_ssl->ocspProducedDateFormat = ASN_UTC_TIME; + } + #endif + + test_ocsp_undecodable_staple_calls = 0; + test_ocsp_undecodable_staple_err = 0; + test_ocsp_undecodable_staple_idx = 1; + test_ocsp_undecodable_staple_sz = 0; + ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), + override ? TEST_SUCCESS : TEST_FAIL); + ExpectIntEQ(test_ocsp_undecodable_staple_calls, 1); + ExpectIntEQ(test_ocsp_undecodable_staple_err, + WC_NO_ERR_TRACE(BAD_CERTIFICATE_STATUS_ERROR)); + ExpectIntEQ(test_ocsp_undecodable_staple_idx, 0); + ExpectIntEQ(test_ocsp_undecodable_staple_sz, + sizeof(test_ocsp_undecodable_staple_junk)); + if (!override) { + ExpectIntEQ(wolfSSL_get_alert_history(test_ctx.s_ssl, &h), + WOLFSSL_SUCCESS); + ExpectIntEQ(h.last_rx.level, alert_fatal); + ExpectIntEQ(h.last_rx.code, bad_certificate_status_response); + } + #ifndef NO_ASN_TIME + ExpectIntEQ(wolfSSL_get_ocsp_producedDate(test_ctx.c_ssl, date, + sizeof(date), &fmt), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + #endif + + test_ssl_memio_cleanup(&test_ctx); + } + } + return EXPECT_RESULT(); +} +#else +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + return TEST_SKIPPED; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + #else /* feature guards */ int test_ocsp_tls_cert_cb(void) { return TEST_SKIPPED; } +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + return TEST_SKIPPED; +} int test_ocsp_status_request_v2_multi_revoked_single(void) { return TEST_SKIPPED; diff --git a/tests/api/test_ocsp.h b/tests/api/test_ocsp.h index 43431890751..0c0c6eb2d27 100644 --- a/tests/api/test_ocsp.h +++ b/tests/api/test_ocsp.h @@ -37,6 +37,7 @@ int test_ocsp_responder_keyhash_binding(void); int test_ocsp_response_parsing(void); int test_ocsp_tls_cert_cb(void); int test_ocsp_status_request_v2_multi_revoked_single(void); +int test_ocsp_status_verify_cb_undecodable_staple(void); int test_ocsp_cert_unknown_crl_fallback(void); int test_ocsp_cert_unknown_crl_fallback_nonleaf(void); int test_ocsp_no_url_policy(void);