RFC 8446 section 8 requires any server instance to accept 0-RTT for a
given ClientHello at most once. Prior to this change wolfSSL's behaviour
diverged from that requirement in several ways:
* ctx->maxEarlyDataSz defaulted to MAX_EARLY_DATA_SZ whenever the
library was built with WOLFSSL_EARLY_DATA, so servers auto-
advertised 0-RTT in NewSessionTicket without the application
asking. RFC 8446 E.5 says 0-RTT MUST NOT be enabled unless
specifically requested.
* The post-accept eviction is compiled out under NO_SESSION_CACHE,
so builds without the cache accepted 0-RTT with no replay defence.
* Stateless self-encrypted tickets do not carry a session ID on the
stateless DoClientTicket decrypt path, so wolfSSL_SSL_CTX_remove_
session could not locate them to evict.
* wolfSSL_SSL_CTX_remove_session always returned 0 on success
regardless of whether the session was actually in the cache,
diverging from OpenSSL's SSL_CTX_remove_session (1 on success,
0 on not-found).
Changes:
* src/internal.c: ctx->maxEarlyDataSz defaults to 0; applications
must opt in with wolfSSL_CTX_set_max_early_data.
* src/tls13.c: #error when WOLFSSL_EARLY_DATA is built with
HAVE_SESSION_TICKET and NO_SESSION_CACHE. Escape hatch
WOLFSSL_EARLY_DATA_NO_ANTI_REPLAY for deployments that take
application-layer responsibility.
* wolfssl/internal.h: imply WOLFSSL_TICKET_HAVE_ID from
WOLFSSL_EARLY_DATA so stateless-ticket issuance populates the
cache under an ID that eviction can find.
* src/ssl_sess.c: wolfSSL_SSL_CTX_remove_session returns 1 when the
session was found (internal-cache hit, or ctx->rem_sess_cb fired
for an external cache), 0 otherwise. Matches OpenSSL semantics.
* src/tls13.c: the 0-RTT acceptance condition in CheckPreSharedKeys
now calls wolfSSL_SSL_CTX_remove_session and checks its return:
the eviction is the check. If the session was in the cache, 0-RTT
is accepted and the single-use requirement is satisfied. If not,
the early_data extension is rejected through the normal path so
the record layer correctly skips in-flight 0-RTT records.
WOLFSSL_MSG at each rejection site.
* doc/dox_comments/header_files/ssl.h: document runtime opt-in.
* tests: four new tests —
test_tls13_0rtt_default_off (fails without default-to-0 fix),
test_tls13_0rtt_stateless_replay (fails without TICKET_HAVE_ID
implication and remove_session gate),
test_tls13_remove_session_return (fails without return-value fix),
test_tls13_0rtt_ext_cache_eviction (fails without ext-cache
counts-as-found fix).
test_tls13_early_data explicitly opts in via
wolfSSL_CTX_set_max_early_data.
tests/api.c: two SSL_CTX_remove_session == 0 assertions updated
to == 1.
Implement RFC8773bis (draft-ietf-tls-8773bis-13)
cert_with_extern_psk for TLS 1.3, including protocol checks
and API support.
Includes unit tests for API and handshake behavior as well
as tests in the testsuite using extended examples.
Exposes dynamic TLS certificate loading and OCSP stapling to allow applications to load certs lazily.
The server no longer needs to load the CA to staple OCSP responses.
Adds a certificate setup callback (WOLFSSL_CERT_SETUP_CB)
Adds an OCSP status callback to load OCSP responses directly
Adds `wc_NewOCSP`, `wc_FreeOCSP`, and `wc_CheckCertOcspResponse`
Don't call verify twice on the same error
Send correct alert on status response error
- wolfDTLS_accept_stateless - statelessly listen for incoming connections
- wolfSSL_inject - insert data into WOLFSSL object
- wolfSSL_SSL(Enable|Disable)Read - enable/disable reading from IO
- wolfSSL_get_wfd - get the write side file descriptor
- wolfSSL_dtls_set_pending_peer - set the pending peer that will be upgraded to regular peer when we successfully de-protect a DTLS record
- wolfSSL_dtls_get0_peer - zero copy access to the peer address
- wolfSSL_is_stateful - boolean to check if we have entered stateful processing
- wolfSSL_dtls_cid_get0_rx - zero copy access to the rx cid
- wolfSSL_dtls_cid_get0_tx - zero copy access to the tx cid
- wolfSSL_dtls_cid_parse - extract cid from a datagram/message
* tls: negotiate until hs is complete in wolfSSL_read/wolfSSL_write
Don't rely on ssl->options.handShakeSate == HANDSHAKE_DONE to check if
negotiation is needed. wolfSSL_Connect() or wolfSSL_Accept() job may not yet be
completed and/or some messages may be waiting in the buffer because of
non-blocking I/O.
* tests: test case for handshake with wolfSSL_read()/wolfSSL_write()
* doc: clarify wolfSSL_write()
* internal.c: rename: need_negotiate -> ssl_in_handshake