@@ -5873,3 +5873,157 @@ int test_tls13_clear_preserves_psk_dhe(void)
58735873#endif
58745874 return EXPECT_RESULT ();
58755875}
5876+
5877+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
5878+ defined(WOLFSSL_TLS13 ) && defined(WOLFSSL_POST_HANDSHAKE_AUTH ) && \
5879+ defined(HAVE_CERTIFICATE_STATUS_REQUEST ) && defined(HAVE_OCSP ) && \
5880+ !defined(NO_CERTS ) && !defined(NO_RSA ) && \
5881+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER )
5882+ /* Mock OCSP I/O callback: returns 0 bytes so the server stapling slot
5883+ * stays empty. This intentionally exercises the "no staple available"
5884+ * path on both peers. */
5885+ static int test_pha_ocsp_io_cb (void * ioCtx , const char * url , int urlSz ,
5886+ unsigned char * req , int reqSz , unsigned char * * resp )
5887+ {
5888+ (void )ioCtx ; (void )url ; (void )urlSz ; (void )req ; (void )reqSz ;
5889+ * resp = NULL ;
5890+ return 0 ;
5891+ }
5892+
5893+ static void test_pha_ocsp_resp_free_cb (void * ioCtx , unsigned char * resp )
5894+ {
5895+ (void )ioCtx ; (void )resp ;
5896+ }
5897+ #endif
5898+
5899+ /* Post-Handshake Authentication combined with OCSP stapling
5900+ * (status_request) on the TLS 1.3 CertificateRequest message.
5901+ *
5902+ * Regression for two related issues:
5903+ * 1. The server's PHA CertificateRequest must include the
5904+ * status_request extension (with an empty body) when the client
5905+ * offered status_request in its ClientHello (RFC 8446 4.2 / 4.3.2).
5906+ * Without the fix the extension was suppressed and the size and
5907+ * write paths disagreed by 4 bytes, causing the client to send a
5908+ * decode_error alert (BUFFER_ERROR / -328).
5909+ * 2. The server-side OCSP-status check in ProcessPeerCerts must run
5910+ * for the PHA-received client Certificate. The check must also
5911+ * tolerate a missing/empty stapled response unless the verifier
5912+ * enforces must-staple, per RFC 8446 4.4.2.1 (client OCSP staple
5913+ * is MAY) and RFC 7633 (must-staple). Without the fix the server
5914+ * either skipped the check entirely or returned
5915+ * BAD_CERTIFICATE_STATUS_ERROR (-406) for the no-staple case.
5916+ *
5917+ * The test exercises a single TLS 1.3 connection: an initial handshake
5918+ * without client authentication, followed by a server-initiated PHA
5919+ * exchange. The server expects to receive (and verify) the client
5920+ * certificate even though no OCSP staple is supplied.
5921+ */
5922+ int test_tls13_pha_status_request (void )
5923+ {
5924+ EXPECT_DECLS ;
5925+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
5926+ defined(WOLFSSL_TLS13 ) && defined(WOLFSSL_POST_HANDSHAKE_AUTH ) && \
5927+ defined(HAVE_CERTIFICATE_STATUS_REQUEST ) && defined(HAVE_OCSP ) && \
5928+ !defined(NO_CERTS ) && !defined(NO_RSA ) && \
5929+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER )
5930+ struct test_memio_ctx test_ctx ;
5931+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
5932+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
5933+ WOLFSSL_X509 * peer = NULL ;
5934+ const char msg [] = "ping" ;
5935+ char buf [8 ];
5936+
5937+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
5938+
5939+ /* --- Client CTX ------------------------------------------------ */
5940+ ExpectNotNull (ctx_c = wolfSSL_CTX_new (wolfTLSv1_3_client_method ()));
5941+ ExpectIntEQ (wolfSSL_CTX_load_verify_locations (ctx_c , caCertFile , 0 ),
5942+ WOLFSSL_SUCCESS );
5943+ ExpectIntEQ (wolfSSL_CTX_use_certificate_file (ctx_c , cliCertFile ,
5944+ WOLFSSL_FILETYPE_PEM ), WOLFSSL_SUCCESS );
5945+ ExpectIntEQ (wolfSSL_CTX_use_PrivateKey_file (ctx_c , cliKeyFile ,
5946+ WOLFSSL_FILETYPE_PEM ), WOLFSSL_SUCCESS );
5947+ /* Must opt in to PHA before wolfSSL_connect to add the
5948+ * post_handshake_auth extension to the ClientHello. */
5949+ ExpectIntEQ (wolfSSL_CTX_allow_post_handshake_auth (ctx_c ), 0 );
5950+ ExpectIntEQ (wolfSSL_CTX_EnableOCSPStapling (ctx_c ), WOLFSSL_SUCCESS );
5951+ wolfSSL_SetIORecv (ctx_c , test_memio_read_cb );
5952+ wolfSSL_SetIOSend (ctx_c , test_memio_write_cb );
5953+
5954+ /* --- Server CTX ------------------------------------------------ */
5955+ ExpectNotNull (ctx_s = wolfSSL_CTX_new (wolfTLSv1_3_server_method ()));
5956+ ExpectIntEQ (wolfSSL_CTX_use_certificate_file (ctx_s , svrCertFile ,
5957+ WOLFSSL_FILETYPE_PEM ), WOLFSSL_SUCCESS );
5958+ ExpectIntEQ (wolfSSL_CTX_use_PrivateKey_file (ctx_s , svrKeyFile ,
5959+ WOLFSSL_FILETYPE_PEM ), WOLFSSL_SUCCESS );
5960+ ExpectIntEQ (wolfSSL_CTX_load_verify_locations (ctx_s , caCertFile , 0 ),
5961+ WOLFSSL_SUCCESS );
5962+ /* Trust the client cert issuer as well, otherwise the PHA
5963+ * Certificate verification would fail with ASN_SELF_SIGNED_E. */
5964+ ExpectIntEQ (wolfSSL_CTX_load_verify_locations (ctx_s ,
5965+ "./certs/client-ca.pem" , 0 ), WOLFSSL_SUCCESS );
5966+ ExpectIntEQ (wolfSSL_CTX_EnableOCSPStapling (ctx_s ), WOLFSSL_SUCCESS );
5967+ /* Mock callback: stapling negotiates but the response is empty. */
5968+ ExpectIntEQ (wolfSSL_CTX_SetOCSP_Cb (ctx_s , test_pha_ocsp_io_cb ,
5969+ test_pha_ocsp_resp_free_cb , NULL ), WOLFSSL_SUCCESS );
5970+ /* Initial handshake: do not request the client certificate yet -
5971+ * the server promotes verification only when triggering PHA. */
5972+ wolfSSL_CTX_set_verify (ctx_s , WOLFSSL_VERIFY_NONE , NULL );
5973+ wolfSSL_SetIORecv (ctx_s , test_memio_read_cb );
5974+ wolfSSL_SetIOSend (ctx_s , test_memio_write_cb );
5975+
5976+ /* --- SSL objects ----------------------------------------------- */
5977+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
5978+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
5979+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
5980+ /* Causes status_request in the ClientHello so that the server's
5981+ * PHA CertificateRequest re-emits the same extension. */
5982+ ExpectIntEQ (wolfSSL_UseOCSPStapling (ssl_c , WOLFSSL_CSR_OCSP , 0 ),
5983+ WOLFSSL_SUCCESS );
5984+
5985+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
5986+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
5987+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
5988+
5989+ /* --- Initial handshake (no client cert requested) -------------- */
5990+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
5991+ ExpectNull (wolfSSL_get_peer_certificate (ssl_s ));
5992+
5993+ /* --- Trigger PHA: server now requires the client certificate -- */
5994+ if (EXPECT_SUCCESS ()) {
5995+ wolfSSL_set_verify (ssl_s ,
5996+ WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT ,
5997+ NULL );
5998+ ExpectIntEQ (wolfSSL_request_certificate (ssl_s ), WOLFSSL_SUCCESS );
5999+ }
6000+
6001+ /* The server's wolfSSL_write below carries the PHA
6002+ * CertificateRequest record. The client's wolfSSL_read consumes
6003+ * the request, transmits Certificate/CertificateVerify/Finished
6004+ * and surfaces the application data to us. */
6005+ ExpectIntEQ (wolfSSL_write (ssl_s , msg , (int )sizeof (msg ) - 1 ),
6006+ (int )sizeof (msg ) - 1 );
6007+ ExpectIntEQ (wolfSSL_read (ssl_c , buf , sizeof (buf ) - 1 ),
6008+ (int )sizeof (msg ) - 1 );
6009+
6010+ /* The client's reply lets the server's wolfSSL_read drain the
6011+ * incoming PHA Certificate flight before the application data. */
6012+ ExpectIntEQ (wolfSSL_write (ssl_c , msg , (int )sizeof (msg ) - 1 ),
6013+ (int )sizeof (msg ) - 1 );
6014+ ExpectIntEQ (wolfSSL_read (ssl_s , buf , sizeof (buf ) - 1 ),
6015+ (int )sizeof (msg ) - 1 );
6016+
6017+ /* PHA succeeded: the server now holds the client certificate.
6018+ * Reaching this point also implies the server tolerated the
6019+ * empty OCSP staple instead of failing with -406. */
6020+ ExpectNotNull (peer = wolfSSL_get_peer_certificate (ssl_s ));
6021+ wolfSSL_X509_free (peer );
6022+
6023+ wolfSSL_free (ssl_c );
6024+ wolfSSL_free (ssl_s );
6025+ wolfSSL_CTX_free (ctx_c );
6026+ wolfSSL_CTX_free (ctx_s );
6027+ #endif
6028+ return EXPECT_RESULT ();
6029+ }
0 commit comments