Commit 1234697b33 for openssl.org

commit 1234697b33694bea6e7df35704b126108d1391ea
Author: Bob Beck <beck@openssl.org>
Date:   Wed Sep 9 17:28:18 2026 -0600

    Bring recent comments into line with the STYLE.md comment rules

    Comments added by AI-assisted commits over the last three months
    often narrate the change rather than describe the code: the
    behaviour being replaced, the alternative not taken, or the bug the
    test was written for. STYLE.md now says that a comment states what
    the code does and the constraint it satisfies, and that the
    reasoning behind a change does not belong in one.

    Reword those comments to that standard.

    Reviewed-by: Milan Broz <mbroz@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Merge-date: Fri Oct  2 08:06:12 2026
    Merged-from: https://github.com/openssl/openssl/pull/32779

diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index 41491b92a1..8d4b782abc 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.c
@@ -149,9 +149,7 @@ int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
                  * truncated.  Only a clean EOF at a top-level object boundary
                  * (i == 0, diff == 0, eos == 0) is the normal end of input:
                  * fail without queuing an error so that callers looping over
-                 * concatenated DER values (e.g. the libcrypto d2i_*_bio()
-                 * consumers in CPython's ssl module) terminate cleanly instead
-                 * of seeing a spurious ASN1_R_NOT_ENOUGH_DATA.
+                 * concatenated DER values terminate cleanly.
                  */
                 if (i < 0 || diff != 0 || eos != 0)
                     ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA);
diff --git a/crypto/mem.c b/crypto/mem.c
index f5286e4aa5..2bdbc2d11d 100644
--- a/crypto/mem.c
+++ b/crypto/mem.c
@@ -119,7 +119,7 @@ static void parseit(void)

     /*
      * Get the count (parsing stops at the '@' if present), and percentage.
-     * Ignore an unparsable/overflowing count rather than acting on garbage.
+     * An unparsable or overflowing count is ignored.
      * Validate that the count is followed by '@' or end-of-string.
      */
     if (!ossl_strtol(md_failstring, &end, 10, &md_count)
diff --git a/crypto/property/property.c b/crypto/property/property.c
index 80f657f2be..81cb6a8d6d 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -1243,10 +1243,8 @@ static ossl_inline int ossl_method_store_cache_set_atomic(OSSL_METHOD_STORE *sto
          *
          * Only insert it if no NULL-provider entry exists yet for this nid and
          * property query.  The first provider to cache this nid owns that
-         * entry, which matches the provider ossl_method_store_fetch would pick
-         * by implementation order.  Without this check, a later cache_set from
-         * a different provider would overwrite it and change which provider an
-         * "any provider" lookup resolves to.
+         * entry, which is the provider ossl_method_store_fetch picks by
+         * implementation order.
          */
         if (ossl_method_store_atomic_find_in_list(sa, nid, NULL, prop_query) == NULL) {
             p = QUERY_new(strlen(prop_query));
diff --git a/crypto/rand/prov_seed.c b/crypto/rand/prov_seed.c
index d0c7c63551..5e2f6328ef 100644
--- a/crypto/rand/prov_seed.c
+++ b/crypto/rand/prov_seed.c
@@ -49,10 +49,8 @@ size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx,

     if (ossl_rand_seed_source_strict(ctx)) {
         /*
-         * With strict seeding the seed source must be used, even when the
-         * request arrives before anything instantiated it: create it now
-         * and fail instead of silently substituting the operating system
-         * entropy sources.
+         * With strict seeding the configured seed source must be used,
+         * even when the request arrives before anything instantiated it.
          */
         rng = ossl_rand_get0_seed(ctx);
         if (rng == NULL || !evp_rand_can_seed(rng)) {
diff --git a/demos/dtlsecho/main.c b/demos/dtlsecho/main.c
index e9856171f9..1b6b0b5b11 100644
--- a/demos/dtlsecho/main.c
+++ b/demos/dtlsecho/main.c
@@ -49,9 +49,9 @@ static SOCKET create_socket(void)
     char port_str[6];

     /*
-     * Resolve the wildcard address for our port. Requesting AF_INET6 gives a
-     * single socket that, BIO_listen will clear IPV6_V6ONLY below, and the
-     * socket accepts both IPv6 and IPv4 clients.
+     * Resolve the wildcard address for our port. With AF_INET6 and
+     * IPV6_V6ONLY cleared by BIO_listen below, a single socket accepts both
+     * IPv6 and IPv4 clients.
      */
     snprintf(port_str, sizeof(port_str), "%d", server_port);
     if (!BIO_lookup_ex(NULL, port_str, BIO_LOOKUP_SERVER, AF_INET6,
diff --git a/demos/dtlslistenerecho/main.c b/demos/dtlslistenerecho/main.c
index bdaf445d2f..a208b7e20d 100644
--- a/demos/dtlslistenerecho/main.c
+++ b/demos/dtlslistenerecho/main.c
@@ -96,7 +96,7 @@ static SSL_CTX *create_context(bool isServer)
  * invoked for each handshake flight to choose the next retransmit interval.
  * timer_us holds the previous interval (0 on the first call). We start at 1s
  * and double, but cap the backoff so a stalled handshake is abandoned in a
- * reasonable time rather than the library default of nearly 8 minutes.
+ * reasonable time.
  */
 static unsigned int dtls_timer_cb(SSL *s, unsigned int timer_us)
 {
@@ -255,8 +255,8 @@ static void handle_connection(struct connection_thread_args *conn_args)
         }

         /*
-         * Wait for the socket to become ready rather than busy-looping. Size
-         * the wait to the DTLS retransmit timer so we wake when a flight is
+         * Wait for the socket to become ready. Size the wait to the DTLS
+         * retransmit timer so the loop wakes when a flight is
          * due for retransmission; fall back to a fixed interval if no timer is
          * armed.
          */
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 7ca3725b5d..f0247525c5 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -579,11 +579,9 @@ int dtls1_handle_timeout(SSL_CONNECTION *s)

     if (dtls1_check_timeout_num(s) < 0) {
         /*
-         * SSLfatal() already called, so the connection is finished. Stop the
-         * timer rather than returning with next_timeout left in the past:
-         * nothing will re-arm or clear it from here, so DTLSv1_get_timeout()
-         * would report "due now" for ever and spin any caller which waits on
-         * it.
+         * SSLfatal() already called, so the connection is finished. Nothing
+         * re-arms or clears the timer after this, and an expired timeout left
+         * in place makes DTLSv1_get_timeout() report it due for ever.
          */
         dtls1_stop_timer(s);
         return -1;
@@ -1441,10 +1439,9 @@ static void dtls_listener_packet_handler(DGRAM_URXE *urxe, void *arg)
     /* Create new pending connection if needed */
     if (conn_ssl == NULL) {
         /*
-         * Reject before allocating anything if we have reached the pending
-         * connection limit. The LHASH item count is O(1), and this check does
-         * not need a conn_ssl, so performing it first avoids creating and then
-         * immediately freeing a connection when we are at capacity.
+         * Reject before allocating anything if the pending connection limit
+         * is reached. The LHASH item count is O(1) and the check does not
+         * need a conn_ssl.
          */
         if (ossl_dgram_conn_lookup_num_items(dl->pending_conns) >= dl->max_pending_conns)
             goto release;
@@ -2483,9 +2480,8 @@ SSL *ossl_dtls_accept_connection(SSL *ssl, uint64_t flags)

     /*
      * Wait only if the caller has not asked us not to and the listener is in
-     * blocking mode. Note that the check for a network BIO below is deliberately
-     * left ahead of this, so that asking to wait on a listener which has none
-     * remains an error rather than silently returning nothing.
+     * blocking mode. A listener with no network BIO takes the blocking path,
+     * which reports the missing BIO as an error.
      */
     if (!no_block && !ossl_dtls_blocking(ssl) && dl->net_rbio != NULL)
         no_block = 1;
@@ -3122,11 +3118,7 @@ int ossl_dtls_set_blocking_mode(SSL *s, int blocking)
         return 0;
     }

-    /*
-     * Refuse to claim blocking we cannot deliver, as QUIC does. Checked before
-     * anything is written, so that a call which fails leaves the mode alone
-     * rather than reporting failure having already changed it.
-     */
+    /* Blocking mode which cannot be delivered is refused, as in QUIC. */
     if (blocking && !ossl_dtls_can_support_blocking(s)) {
         ERR_raise(ERR_LIB_SSL, ERR_R_UNSUPPORTED);
         return 0;
@@ -3220,27 +3212,16 @@ int ossl_dtls_conn_wait_for_datagram(SSL *s)
  * connection which is in blocking mode.
  *
  * The socket is shared with every other connection and is always
- * non-blocking, so a send which cannot be completed has nowhere to wait. For
- * DTLS the record layer would otherwise discard the datagram - a reasonable
- * default for an unreliable transport, but not what an application which asked
- * for blocking writes expects.
+ * non-blocking, so a send which cannot be completed has nowhere else to wait.
  *
  * Only one wait is performed. The caller retries the send, and comes back here
- * if it still cannot proceed, so a wakeup which turns out not to leave room in
- * the socket buffer costs an extra attempt rather than a lost datagram.
- *
- * The retransmission timer deliberately does not shorten this wait, unlike the
- * one for a datagram above. There the wakeup is useful, because the wait can
- * service the timer itself; here it cannot. Servicing it would mean
- * retransmitting a flight from inside tls_retry_write_records(), which is
- * part-way through sending one and holds write buffer state that a
- * re-entrant do_dtls1_write() would clobber. Waking for a timer nothing then
- * services would be worse than not waking: the timeout stays expired, and an
- * expired timeout reads as a zero deadline, so every later wait would return
- * at once and the caller's retry loop would spin without sleeping. Waiting for
- * the socket alone is also what the send actually needs. Retransmission is not
- * the right response to a flight which has not finished going out, and once it
- * has, the state machine handles the timer as usual.
+ * if it still cannot proceed.
+ *
+ * The retransmission timer does not bound this wait. The timer cannot be
+ * serviced from here: the caller is inside tls_retry_write_records(), which
+ * holds write buffer state that do_dtls1_write() uses. A wait woken by a
+ * timer nothing services finds the timeout still expired, which reads as a
+ * zero deadline, and returns at once on every later call.
  *
  * Returns 1 if the send should be retried, or 0 if the wait could not be
  * performed or the listener has failed.
diff --git a/ssl/quic/quic_ackm.c b/ssl/quic/quic_ackm.c
index 5da8af882a..a249d6db12 100644
--- a/ssl/quic/quic_ackm.c
+++ b/ssl/quic/quic_ackm.c
@@ -1144,11 +1144,9 @@ int ossl_ackm_on_tx_ack_only_packet(OSSL_ACKM *ackm, OSSL_ACKM_TX_PKT *pkt)
         return 0;

     /*
-     * A packet containing only an ACK frame must not be treated as
-     * in-flight or ack-eliciting; if it were, ossl_ackm_on_tx_packet()
-     * below would (correctly) perform bytes-in-flight/timer/CC bookkeeping
-     * for a packet we are about to discard from history, which would be
-     * incorrect.
+     * A packet containing only an ACK frame is not kept in history, so it
+     * must not be in-flight or ack-eliciting: ossl_ackm_on_tx_packet() below
+     * performs bytes-in-flight, timer and CC bookkeeping for such packets.
      */
     if (pkt->is_inflight || pkt->is_ack_eliciting)
         return 0;
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c
index dc62238211..8f363c093a 100644
--- a/ssl/quic/quic_channel.c
+++ b/ssl/quic/quic_channel.c
@@ -598,8 +598,7 @@ int ossl_quic_channel_set0_tls(QUIC_CHANNEL *ch, SSL *ssl)
 {
     /*
      * Rebind the handshake layer first, so that a failure leaves the channel
-     * entirely unmodified rather than with a TLS connection the handshake
-     * layer does not know about.
+     * unmodified.
      */
     if (!ossl_assert(ch != NULL && ssl != NULL && ch->tls == NULL)
         || !ossl_quic_tls_set0_ssl(ch->qtls, ssl))
diff --git a/ssl/record/methods/dtls_meth.c b/ssl/record/methods/dtls_meth.c
index f4dce6427e..68a5349894 100644
--- a/ssl/record/methods/dtls_meth.c
+++ b/ssl/record/methods/dtls_meth.c
@@ -325,9 +325,9 @@ static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, struct pqueue_st *qu
     }

     /*
-     * Take a copy of just this record's on-wire bytes (header + ciphertext)
-     * rather than the whole (much larger) read buffer. The live rl->rbuf is
-     * left untouched and continues to be used for subsequent reads.
+     * Take a copy of just this record's on-wire bytes (header + ciphertext).
+     * rl->rbuf is left untouched and continues to be used for subsequent
+     * reads.
      */
     rdata->packet_length = rl->packet_length;
     rdata->packet = OPENSSL_memdup(rl->packet, rl->packet_length);
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index ef7b469b65..e3c7d7e7de 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1178,11 +1178,9 @@ static int rlayer_dtls_get_urxe_packet(void *cbarg, unsigned char **data,

     /*
      * Still nothing. In blocking mode this is where the caller waits: the
-     * connection has no BIO of its own to block in, so returning here would
-     * report SSL_ERROR_WANT_READ instead of blocking. Waiting inside this
-     * callback keeps that out of the record layer and the state machine, which
-     * see only a read which took a while, exactly as a blocking BIO would give
-     * them.
+     * connection has no BIO of its own to block in. The record layer and the
+     * state machine see only a read which took a while, as with a blocking
+     * BIO.
      */
     if (urxe == NULL && s->d1->listener != NULL
         && ossl_dtls_blocking(SSL_CONNECTION_GET_SSL(s))
@@ -1630,9 +1628,8 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
      * For DTLS listener-created connections the peer address must be applied
      * to every record layer as it is created (including the encrypted layers
      * built during the handshake). SSL_set1_initial_peer_addr() only updates
-     * the record layers that exist when it is called, so writes on a later
-     * layer would otherwise fall back to BIO_write() on the shared listener
-     * BIO instead of BIO_sendmmsg() to the peer.
+     * the record layers that exist when it is called. A layer without a peer
+     * address writes with BIO_write() on the shared listener BIO.
      */
 #ifndef OPENSSL_NO_SOCK
     if (SSL_CONNECTION_IS_DTLS(s)
diff --git a/ssl/rio/poll_builder.c b/ssl/rio/poll_builder.c
index 509c79918f..32d67744bb 100644
--- a/ssl/rio/poll_builder.c
+++ b/ssl/rio/poll_builder.c
@@ -156,12 +156,12 @@ int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline)
     /*
      * Waiting with no file descriptors is legitimate: a DTLS connection whose
      * BIO cannot provide a poll descriptor has no readiness to wait for, but
-     * still has a retransmission deadline to wake for. Handle that here rather
-     * than leaving it to the OS, because poll() treats an empty descriptor set
-     * as a plain sleep whereas Windows' select() rejects it outright.
+     * still has a retransmission deadline to wake for. poll() treats an empty
+     * descriptor set as a plain sleep and Windows' select() rejects it, so
+     * the sleep is done here.
      *
-     * With no descriptors and no deadline nothing could ever wake us, so that
-     * is a caller error rather than an indefinite sleep.
+     * With no descriptors and no deadline nothing can wake the wait; that is
+     * a caller error.
      */
     if (rio_poll_builder_is_empty(rpb)) {
         if (ossl_time_is_infinite(deadline))
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 6f1ba3cfe2..8dd8b63653 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -3374,17 +3374,11 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s,
     s->session->not_resumable = 0;

     /*
-     * Refresh the session's recollection of the negotiated ALPN protocol to
-     * match this connection, rather than leaving it as whatever the session
-     * (or the session it was duplicated from, on a resumption) previously
-     * carried. Without this, a connection that resumes a session but
-     * negotiates no ALPN (or a different one) leaves the stale protocol
-     * name in place, and a later 0-RTT attempt against this ticket can
-     * incorrectly trip the "inconsistent early data alpn" check -- or, if
-     * the client happens to offer that same stale protocol again by
-     * coincidence, incorrectly appear consistent. This mirrors, on the
-     * client, the server-side fix for issue #11197 in
-     * tls_construct_new_session_ticket().
+     * The session's ALPN protocol must match what this connection
+     * negotiated, including none. A resumed session carries the protocol
+     * from the handshake that created it, and a later 0-RTT attempt checks
+     * that ALPN is consistent with the session (GitHub issue #11197). The
+     * server side is in tls_construct_new_session_ticket().
      */
     OPENSSL_free(s->session->ext.alpn_selected);
     if (s->s3.alpn_selected != NULL) {
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 75dc8d5f50..ffb935873a 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -4857,12 +4857,11 @@ CON_FUNC_RETURN tls_construct_new_session_ticket(SSL_CONNECTION *s, WPACKET *pkt
             s->session->ext.alpn_selected_len = s->s3.alpn_selected_len;
         } else {
             /*
-             * No ALPN was negotiated on this handshake. If we resumed a
-             * session that had previously negotiated ALPN, the stale value
-             * must be cleared from the (copied) session before it is stored
-             * in the new ticket. Otherwise a subsequent 0-RTT attempt using
-             * that ticket would incorrectly assume an ALPN protocol had been
-             * negotiated. See tls_handle_alpn().
+             * No ALPN was negotiated on this handshake. A resumed session
+             * carries the protocol from the handshake that created it, and
+             * a 0-RTT attempt using the new ticket checks that ALPN is
+             * consistent with the session, so clear it. See
+             * tls_handle_alpn().
              */
             OPENSSL_free(s->session->ext.alpn_selected);
             s->session->ext.alpn_selected = NULL;
diff --git a/test/cmp_extracerts_dos_test.c b/test/cmp_extracerts_dos_test.c
index edb2dc8c4a..50c9364abd 100644
--- a/test/cmp_extracerts_dos_test.c
+++ b/test/cmp_extracerts_dos_test.c
@@ -8,40 +8,13 @@
  */

 /*
- * Regression test for: CMP server unauthenticated memory/CPU DoS via
- * cached extraCerts on failed protection checks.
+ * The extraCerts of a CMP message which fails its protection check must not
+ * remain in ctx->untrusted.
  *
- * Root cause (crypto/cmp/cmp_vfy.c, ossl_cmp_msg_check_update(), current
- * master as of this writing):
- *
- *   res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, ...);
- *   ...
- *   res = OSSL_CMP_validate_msg(ctx, msg) || (cb...);   // may be 0 (rejected)
- *
- *   if (ctx->noCacheExtraCerts)                          // <-- rollback is
- *       while (num_added-- > 0)                          //  gated on this
- *           X509_free(sk_X509_shift(ctx->untrusted));    //  flag only, NOT
- *                                                          //  on the
- *                                                          //  validation
- *                                                          //  result (res)
- *
- *   if (!res) { ...; return 0; }   // certs from a REJECTED msg are kept
- *
- * This test exercises ossl_cmp_msg_check_update() directly -- no sockets,
- * no HTTP server, no apps/cmp.c -- and asserts on the resulting size of
- * ctx->untrusted. It builds a genuinely PBM-protected OSSL_CMP_MSG using
- * the project's own internal message-creation function
- * (ossl_cmp_genm_new(), same one exercised in test/cmp_msg_test.c) so the
- * message is not hand-crafted to "look" rejectable -- it is rejected for a
- * real reason (the receiving ctx has no matching secret configured), the
- * same way OSSL_CMP_validate_msg() would reject any unauthenticated CMP
- * request in the field.
- *
- * Expected results:
- *   - BEFORE the fix: untrusted_count_after == untrusted_count_before + N
- *     (every rejected message's extraCerts persist)
- *   - AFTER the fix:  untrusted_count_after == untrusted_count_before
- *     (rejected messages leave no residue)
+ * This test calls ossl_cmp_msg_check_update() directly and asserts on the
+ * resulting size of ctx->untrusted. The message is a PBM-protected
+ * OSSL_CMP_MSG built with ossl_cmp_genm_new(), rejected because the receiving
+ * ctx has no matching secret configured.
  */

 #include "helpers/cmp_testlib.h"
@@ -75,20 +48,9 @@ static CMP_DOS_TEST_FIXTURE *set_up(const char *const test_case_name)
         return NULL;
     }
     /*
-     * Deliberately do NOT call OSSL_CMP_CTX_set1_secretValue() on the
-     * server ctx. Per OSSL_CMP_validate_msg() (crypto/cmp/cmp_vfy.c):
-     *   case NID_id_PasswordBasedMAC:
-     *     if (ctx->secretValue == NULL) {
-     *         ossl_cmp_info(ctx, "no secret available for verifying..");
-     *         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION);
-     *         return 0;
-     *     }
-     * so every PBM-protected message this ctx receives is unconditionally
-     * rejected -- a deterministic, content-independent rejection path that
-     * models "missing or invalid protection" from the report's repro
-     * steps, without needing to forge a bad MAC by hand.
-     * ctx->noCacheExtraCerts is left at its default (0), exactly as in the
-     * vulnerable deployment ("not setting -no_cache_extracerts").
+     * No secret is set on the server ctx, so OSSL_CMP_validate_msg() rejects
+     * every PBM-protected message it receives. noCacheExtraCerts is left at
+     * its default of 0.
      */
     return fixture;
 }
@@ -241,13 +203,7 @@ err:
     return NULL;
 }

-/*
- * Core assertion: N distinct rejected requests must not grow
- * server_ctx->untrusted at all.
- *
- * Before the fix this fails with e.g.:
- *   ERROR: untrusted count after (25) != count before (0)
- */
+/* N distinct rejected requests must not grow server_ctx->untrusted. */
 static int execute_no_unbounded_growth_test(CMP_DOS_TEST_FIXTURE *fixture)
 {
     OSSL_CMP_CTX *server_ctx = fixture->server_ctx;
@@ -293,9 +249,8 @@ static int execute_no_unbounded_growth_test(CMP_DOS_TEST_FIXTURE *fixture)
 }

 /*
- * Single-request variant of the same check, useful in isolation since it
- * pins down that even ONE rejected request leaves no residue -- ruling out
- * X509_ADD_FLAG_NO_DUP coincidentally masking the bug in the N-request test.
+ * Single-request variant of the same check. One rejected request cannot be
+ * masked by X509_ADD_FLAG_NO_DUP.
  */
 static int execute_single_rejected_request_test(CMP_DOS_TEST_FIXTURE *fixture)
 {
diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c
index 80ce1fb758..513ee05ff7 100644
--- a/test/cmp_protect_test.c
+++ b/test/cmp_protect_test.c
@@ -187,13 +187,11 @@ static int test_cmp_calc_protection_pbmac(void)
 }

 /*
- * Regression test for the ossl_cmp_calc_protection() protectionAlg
- * type-confusion DoS: a PKIMessage whose protectionAlg has the
- * id-PasswordBasedMAC OID but carries a BOOLEAN parameter instead of the
- * expected PBMParameter SEQUENCE. X509_ALGOR_get0() then returns the boolean's
- * union member (0xff) via ppval; the unpatched code took the non-NULL ppval as
- * a valid ASN1_STRING * and dereferenced 0xff, crashing with a near-NULL
- * access.  The fixed code must reject the malformed parameter and return NULL.
+ * ossl_cmp_calc_protection() must reject a PKIMessage whose protectionAlg has
+ * the id-PasswordBasedMAC OID but carries a BOOLEAN parameter in place of the
+ * PBMParameter SEQUENCE. For such a parameter X509_ALGOR_get0() returns the
+ * boolean's union member (0xff) via ppval, which is not an ASN1_STRING *
+ * (CVE-2026-63076).
  */
 static int test_cmp_calc_protection_pbmac_bad_alg_param(void)
 {
diff --git a/test/cmsapitest.c b/test/cmsapitest.c
index f30a0be8c6..35ffa79ca0 100644
--- a/test/cmsapitest.c
+++ b/test/cmsapitest.c
@@ -1372,18 +1372,16 @@ end:

 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_X963KDF)
 /*
- * Regression test for CVE-2026-63072: an 8-byte out-of-bounds heap write
- * reachable through CMS_decrypt() when a KeyAgreeRecipientInfo names an
- * id-aesNNN-wrap-pad key-wrap OID. CMS sizes the unwrap output buffer from
- * the cipher's length query (inlen - 8), but AES-WRAP-PAD unwrap cleanses
- * inlen bytes of it on every RFC 5649 integrity-failure path.
+ * CVE-2026-63072: CMS_decrypt() with a KeyAgreeRecipientInfo naming an
+ * id-aesNNN-wrap-pad key-wrap OID. AES-WRAP-PAD unwrap cleanses inlen bytes of
+ * the output buffer on every RFC 5649 integrity-failure path, and CMS sizes
+ * that buffer from the cipher's length query.
  *
- * We build a valid ECDH KARI message (which uses non-padded id-aes256-wrap),
- * flip the single OID byte an attacker would flip on the wire to turn it into
- * id-aes256-wrap-pad (key length unchanged), and decrypt with the matching
- * private key. The unwrap must fail its integrity check without writing past
- * the CMS-allocated buffer; CMS_decrypt() must fail cleanly.  Under a
- * memory-checking build (e.g. valgrind) the overflow is flagged directly.
+ * Build a valid ECDH KARI message (non-padded id-aes256-wrap), flip the single
+ * OID byte that turns it into id-aes256-wrap-pad (key length unchanged), and
+ * decrypt with the matching private key. The unwrap must fail its integrity
+ * check without writing past the CMS-allocated buffer and CMS_decrypt() must
+ * fail cleanly. Under a memory-checking build the overflow is flagged directly.
  */
 static int test_kari_wrap_pad_unwrap_overflow(void)
 {
@@ -1438,8 +1436,8 @@ static int test_kari_wrap_pad_unwrap_overflow(void)
         goto end;

     /*
-     * The wrap-pad unwrap fails the AIV check; with the fix it does so without
-     * writing past the CMS-allocated buffer.  CMS_decrypt() must fail cleanly.
+     * The wrap-pad unwrap fails the AIV check without writing past the
+     * CMS-allocated buffer, and CMS_decrypt() must fail cleanly.
      */
     if (!TEST_ptr(outbio = BIO_new(BIO_s_mem()))
         || !TEST_false(CMS_decrypt(cms2, eckey, eccert, NULL, outbio, 0)))
diff --git a/test/dtls_multithread_test.c b/test/dtls_multithread_test.c
index a478590fb8..066f68a853 100644
--- a/test/dtls_multithread_test.c
+++ b/test/dtls_multithread_test.c
@@ -731,11 +731,9 @@ static unsigned int blocking_accept_thread(void *arg)
  * readiness rather than for a datagram, which is what this exercises - a
  * client is only created once the accepting thread is already in the call.
  *
- * Note that this cannot distinguish waiting from spinning: the accept returns
- * the connection either way, and the difference is CPU consumed rather than
- * anything observable through the API. It is a test that the blocking path
- * works at all, which was previously only covered for the failure case of
- * having no BIO set.
+ * This cannot distinguish waiting from spinning: the accept returns the
+ * connection either way, and the difference is not observable through the
+ * API.
  */
 static int test_dtls_blocking_accept(void)
 {
@@ -756,10 +754,7 @@ static int test_dtls_blocking_accept(void)
     if (!TEST_true(create_listener(sctx, &listener, &server_addr, &server_fd)))
         goto err;

-    /*
-     * This test needs the blocking accept, so ask for it rather than relying
-     * on the default.
-     */
+    /* This test needs the blocking accept. */
     if (!TEST_true(SSL_set_blocking_mode(listener, 1)))
         goto err;

@@ -923,10 +918,8 @@ static unsigned int blocking_read_thread(void *arg)
  * assertion rather than as a hang.
  *
  * idx 0 blocks in the handshake as well as in the read. idx 1 handshakes in
- * non-blocking mode and only then switches the connection to blocking, which
- * leaves the read as the sole assertion the emulation has to satisfy - without
- * it, idx 0 fails at SSL_accept() and never reaches the read, so on its own it
- * would not tell us the read path works.
+ * non-blocking mode and only then switches the connection to blocking, so
+ * the read is the only thing relying on the emulation.
  *
  * Only the client is driven from this thread: the accepting thread ticks the
  * listener itself, which is what lets a blocked connection make progress at
diff --git a/test/dtlsssllistenertest.c b/test/dtlsssllistenertest.c
index 16565ec318..8740ce8bf8 100644
--- a/test/dtlsssllistenertest.c
+++ b/test/dtlsssllistenertest.c
@@ -3808,15 +3808,9 @@ end:
 /*
  * Test DTLS 1.3 SSL Listener handshake message buffering.
  *
- * This test verifies that when a DTLS 1.3 SSL Listener sends handshake
- * messages, multiple records are buffered into a single datagram
- * rather than being sent as separate datagrams.
- *
- * Expected behavior with buffering:
- *   - At least one datagram contains multiple DTLS records
- *
- * Without buffering (the bug this tests for):
- *   - Each record would be in its own datagram
+ * When a DTLS 1.3 SSL Listener sends handshake messages, multiple records
+ * are buffered into a single datagram: at least one datagram must contain
+ * multiple DTLS records.
  */
 static int test_dtls13_listener_msg_buffering(void)
 {
@@ -4133,12 +4127,11 @@ static int big_ch_ext_add_cb(SSL *s, unsigned int ext_type,
 }

 /*
- * Helper to create a DTLS client on a *connected* UDP socket. Unlike the
- * BIO_dgram_set_peer() helpers above (which use an unconnected socket and so
- * cause DTLS to fragment the ClientHello into sub-MTU datagrams), a connected
- * socket lets DTLS discover the large loopback path MTU and send the whole
- * ClientHello in a single datagram - which is what exercises the listener demux
- * receive-buffer sizing.
+ * Helper to create a DTLS client on a connected UDP socket. A connected socket
+ * lets DTLS discover the large loopback path MTU and send the whole
+ * ClientHello in a single datagram, which exercises the listener demux
+ * receive-buffer sizing; on an unconnected socket DTLS fragments it into
+ * sub-MTU datagrams.
  */
 static int create_dtls_client_connected(SSL_CTX *cctx,
     const BIO_ADDR *server_addr, SSL **clientssl, int *client_fd)
@@ -4952,48 +4945,19 @@ static int test_new_pending_cb_alternate(void)
  * A thread waiting in SSL_poll() for SSL_POLL_EVENT_IC is blocked on the
  * listener's network socket and on its notifier. Where another thread does the
  * demuxing, that socket does not necessarily become readable on the waiter's
- * behalf, so the notifier is what has to wake it.
- *
- * Most of the time the bug this covers is masked. Every connection reaching
- * the accept queue got there because a datagram was demuxed into its receive
- * queue, and the packet handler has always signalled on that injection, so the
- * waiter is woken, ticks the listener itself during its readout, and finds the
- * connection. What is not covered by that is the window in which the injection
- * and the queue push straddle a waiter registering, because signalling is
- * conditional on there being a waiter at the time.
- *
- * The numbered steps below are that window - the interleaving of two threads
- * which the fix exists to handle. They are not what this test does, and are
- * given only so that what it does assert makes sense; see the end of this
- * comment for how it is actually checked.
+ * behalf, so the notifier is what wakes it. Signalling is conditional on a
+ * registered waiter, and the demux of a ClientHello and the push of the
+ * completed connection onto the accept queue are separate steps of a tick, so
+ * a waiter which registers between them is woken only by the push.
  *
- *   1. Accept thread A polls the listener for SSL_POLL_EVENT_IC. Its readout
- *      ticks the listener, finds nothing, and it decides to block. It is not
- *      a registered waiter yet.
- *   2. Worker thread B polls one of its own connections, which also ticks the
- *      listener. The pump reads a client's final ClientHello and injects it
- *      into that pending connection's queue. There are no waiters, so nothing
- *      is signalled.
- *   3. A enters the blocking section. Its re-check runs without ticking, so it
- *      sees only the accept queue, which is still empty, and it blocks.
- *   4. B's tick reaches dtls_listener_drive_pending(), which completes the
- *      connection against the buffered ClientHello and pushes it onto the
- *      accept queue.
+ * The interleaving cannot be forced from outside the library, so this drives
+ * its essential part on one thread: pumping the demux directly performs the
+ * injection, the signal it raises is cleared, and the tick which follows can
+ * only signal by way of the queue push.
  *
- * Without a signal at step 4, A sleeps on with a validated connection sitting
- * ready, until some unrelated datagram makes the socket readable again. B
- * consumed the only one in flight, and the client is now waiting on the
- * server, so on a quiet listener that is until the client retransmits.
- *
- * That interleaving cannot be forced from outside the library, so rather than
- * reproducing the steps above, this drives their essential part by hand and on
- * one thread: pumping the demux directly performs step 2, the signal it raises
- * is then cleared, and the tick which follows can only signal by way of step 4.
- * Asserting that it did is therefore asserting that a queue push signals.
- *
- * signalled_notifier is protected by the listener mutex in the library, which
- * has to assume concurrent access. This test is single threaded throughout, so
- * it reads the field directly without holding the mutex.
+ * signalled_notifier is protected by the listener mutex in the library. This
+ * test is single threaded throughout, so it reads the field directly without
+ * holding the mutex.
  */
 static int test_dtls_notifier_signalled_on_accept_queue_push(void)
 {
@@ -5118,60 +5082,26 @@ end:
 /*
  * Test that a blocking SSL_poll() on a listener enters a blocking section.
  *
- * Unless it does, three things follow: the notifier is not in the poll set, so
- * it cannot wake this thread; cur_blocking_waiters is never incremented, and
- * since signalling is conditional on there being a waiter, no other thread
- * even attempts to signal; and there is no re-check after registering, so
- * readiness arising between the readout and the wait is lost.
- *
- * Polling the socket alone is not enough, though not because a wakeup can be
- * missed outright. poll() reports whatever is currently sitting in the socket
- * buffer and returns immediately if there is any, so a thread cannot miss a
- * datagram just by being outside poll() when it arrives. What it can miss is a
- * datagram another thread has already taken. With several threads polling the
- * one shared socket that happens constantly: an arriving datagram wakes all of
- * them, only one gets it, and the rest find nothing. Any of them can be the
- * one that takes it, because SSL_read() on a connection pumps the demux and
- * SSL_poll() on a connection ticks the whole listener.
+ * The blocking section puts the notifier in the poll set, registers this
+ * thread as a waiter so other threads signal it, and re-checks readiness after
+ * registering. Several threads poll the one shared socket; a datagram wakes all
+ * of them and one takes it, and that thread's tick can complete a pending
+ * connection and push it onto the accept queue. A thread watching the socket
+ * alone then sleeps with a connection on the queue.
  *
- *   1. Accept thread A polls the listener for SSL_POLL_EVENT_IC. Its readout
- *      ticks the listener, finds nothing, and it decides to block.
- *   2. A client's final ClientHello lands on the shared socket.
- *   3. Worker thread B, polling one of its own connections, ticks the listener
- *      and is the one that takes the datagram. Its tick completes the pending
- *      connection and pushes it onto the accept queue. Signalling is attempted,
- *      but A never registered as a waiter, so nothing is signalled.
- *   4. A reaches its poll, watching the socket alone. B drained it, so it is
- *      empty, and A sleeps with a validated connection sitting on the accept
- *      queue.
+ * Entering a blocking section has no public observable. The last waiter out of
+ * a blocking section drains a raised notifier signal, so this raises one
+ * beforehand, polls briefly with nothing ready, and checks afterwards: drained
+ * means a blocking section was entered and left.
  *
- * A's readout, back at step 1, would have found that connection had it run
- * after step 3 rather than before it. Registering as a waiter and re-checking
- * is what removes the dependency on that ordering.
+ * signalled_notifier is protected by the listener mutex in the library. This
+ * test is single threaded throughout, so it reads and writes the field
+ * directly without holding the mutex.
  *
- * Note that the signal added for the step 3 queue push is itself conditional on
- * a registered waiter, so it does nothing for a thread polling the listener
- * until that thread registers. The two fixes are complementary.
- *
- * None of that has a public observable, and this deliberately does not time
- * the wait. Instead it relies on the last waiter out of a blocking section
- * draining a raised notifier signal: raise one beforehand, poll briefly with
- * nothing ready, and check afterwards. Drained means a blocking section was
- * entered and left, since only a leave drains it and only an enter can be left;
- * still standing means neither happened.
- *
- * signalled_notifier is protected by the listener mutex in the library, which
- * has to assume concurrent access. This test is single threaded throughout, so
- * it reads and writes the field directly without holding the mutex.
- *
- * Note what this does not cover. That the notifier is in the poll set, and so
- * can actually deliver a wakeup, is not checked: with a signal raised the poll
- * returns at once if the notifier is being watched and sleeps out its timeout
- * if it is not, and only timing separates those. A longer timeout would not
- * help, because the first iteration's leave drains the notifier and the next
- * one sleeps out the remainder either way. The re-check after registering is
- * not covered either, since readiness arriving between the readout and the
- * registration cannot be produced from a single thread.
+ * Not covered: that the notifier in the poll set delivers a wakeup (only
+ * timing separates that from sleeping out the timeout), and the re-check
+ * after registering (readiness arriving between the readout and the
+ * registration cannot be produced from a single thread).
  */
 static int test_dtls_poll_listener_enters_blocking_section(void)
 {
@@ -5376,8 +5306,7 @@ static int test_dtls_poll_conn_honours_retransmit_timer(void)

     /*
      * Install the short timeout before the server sends anything, so that it
-     * is picked up when the retransmission timer is first started rather than
-     * only on a later expiry.
+     * is picked up when the retransmission timer is first started.
      */
     DTLS_set_timer_cb(serverssl, short_timer_cb);

@@ -5731,11 +5660,8 @@ end:
  * Test that a rejected SSL_set_blocking_mode() leaves the mode alone.
  *
  * Whether blocking can be supported depends on the listener's BIO, so a
- * request can be refused now and be perfectly deliverable later. The refusal
- * must therefore not record the mode it refused to set: the effect only becomes
- * visible once a BIO which can supply a poll descriptor is in place, at which
- * point the listener would be found blocking on the strength of a call which
- * failed.
+ * request refused before a BIO which can supply a poll descriptor is in place
+ * must not be recorded, or the listener is found blocking once one is.
  */
 static int test_dtls_blocking_mode_failed_set_is_inert(void)
 {
@@ -5864,18 +5790,12 @@ static const BIO_METHOD *bio_f_failing_send_filter(void)

 /*
  * Test that a write on a blocking listener connection waits for the socket and
- * sends again, rather than reporting that it needs to be retried.
- *
- * A datagram which cannot be sent is normally dropped, which is reasonable for
- * an unreliable transport but is not what an application asking for blocking
- * writes expects: it gets no data sent and a WANT_WRITE it did not ask to have
- * to handle. The listener's socket is shared and always non-blocking, so there
- * is nothing for such a write to block in by itself.
+ * sends again. The listener's socket is shared and always non-blocking, so
+ * there is nothing for such a write to block in by itself.
  *
  * A loopback socket's send buffer does not fill, so a filter BIO supplies the
- * transient failure instead. Only one send is rejected: the retry then goes
- * through, and the client is read to confirm the datagram was really sent
- * rather than merely reported as sent.
+ * transient failure. Only one send is rejected: the retry then goes through,
+ * and the client is read to confirm the datagram was sent.
  *
  * The handshake runs with the listener non-blocking, so this test drives both
  * ends from the one thread as the others here do, and only the connection is
@@ -5953,12 +5873,7 @@ static int test_dtls_blocking_write(void)
         || !TEST_size_t_eq(written, 3))
         goto end;

-    /*
-     * The send really was rejected, and was retried rather than reported: the
-     * count proves a second attempt was made, which is the whole behaviour
-     * under test. Without it, a write which never reached the filter at all
-     * would look the same as one which was retried.
-     */
+    /* The count shows the send was rejected once and then retried. */
     if (!TEST_int_eq(data.fails_remaining, 0)
         || !TEST_int_ge(data.sends, 2))
         goto end;
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 385272faf5..e321619b46 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -4295,9 +4295,8 @@ static int test_RSA_verify_recover_empty_payload(void)
         goto done;

     /*
-     * The actual recovery call is essential: a NULL output buffer would only
-     * run the size-query path, which never decodes the signature and so would
-     * not reproduce the regression.
+     * A NULL output buffer runs only the size-query path, which never decodes
+     * the signature.
      */
     recovered_len = (size_t)recovered_cap;
     if (!TEST_int_gt(EVP_PKEY_verify_recover(verify_ctx, recovered,
diff --git a/test/quic_tserver_test.c b/test/quic_tserver_test.c
index ac3d879e46..06c2174d81 100644
--- a/test/quic_tserver_test.c
+++ b/test/quic_tserver_test.c
@@ -366,7 +366,7 @@ static int do_test(int use_thread_assist, int use_fake_time, int use_inject)
                 /*
                  * The assist thread alone keeps the idle connection alive. It
                  * waits on real time internally, so advancing fake time can
-                 * outrun it. Rather than race it, wait until it has caught up:
+                 * outrun it. Wait until it has caught up:
                  * the event timeout is computed against fake time, so once the
                  * next deadline is back in the future all events due up to now
                  * - including any keepalive - have been serviced.
diff --git a/test/radix/quic_tests.c b/test/radix/quic_tests.c
index 529a254394..3f65cd4c17 100644
--- a/test/radix/quic_tests.c
+++ b/test/radix/quic_tests.c
@@ -484,16 +484,11 @@ DEF_FUNC(check_poll_abort_blocking)

     /*
      * C0 and Cb0 are streams of two independent client connections, and so
-     * belong to two independent QUIC_REACTORs. The bug being tested for does
-     * not actually require this: it reproduces just as well if all items
-     * share one reactor. What needs two reactors is poll_abort_test_step_cb()
-     * below, which forces Cb0 ready by ticking its reactor directly, on this
-     * thread, while C0's blocking section is still open. Doing that on C0's
-     * own (shared) reactor would deadlock: ossl_quic_reactor_tick() would see
-     * a nonzero cur_blocking_waiters left over from C0 and call
-     * rtor_notify_other_threads(), which waits on a condvar for some *other*
-     * thread to clear the notifier signal - a thread that doesn't exist here.
-     * Using Cb0's own, still-untouched reactor keeps that tick a no-op.
+     * belong to two independent QUIC_REACTORs. poll_abort_test_step_cb() below
+     * forces Cb0 ready by ticking its reactor directly, on this thread, while
+     * C0's blocking section is still open. Ticking a reactor with a nonzero
+     * cur_blocking_waiters calls rtor_notify_other_threads(), which waits for
+     * another thread to clear the notifier signal.
      */
     REQUIRE_SSL_4(C, C0, Cb0, Lb0);

@@ -816,7 +811,7 @@ DEF_FUNC(check_flood_stats)
     /*
      * The flood is delivered over a real socket and processed by the
      * connection's assist thread asynchronously, so give it a chance to
-     * catch up rather than failing on the first observation.
+     * catch up.
      */
     if (path_challenge_count < 16 || path_response_count < 1)
         F_SPIN_AGAIN();
diff --git a/test/rand_test.c b/test/rand_test.c
index 3843afe446..e11dc12f92 100644
--- a/test/rand_test.c
+++ b/test/rand_test.c
@@ -398,10 +398,9 @@ static int provider_side_drbg_instantiate(EVP_RAND_CTX *rctx)
 }

 /*
- * Regression test for #25941: with strict seeding the configured seed
- * source must be instantiated on demand and used when a provider
- * requests seeding material before anything else created it, instead of
- * being silently replaced by the operating system entropy sources.
+ * With strict seeding the configured seed source must be instantiated on
+ * demand and used when a provider requests seeding material before
+ * anything else created it (#25941).
  */
 static int test_rand_seed_source_strict(void)
 {
diff --git a/test/recipes/20-test_app_s_client_msg.t b/test/recipes/20-test_app_s_client_msg.t
index 75d388efe8..7feebc0959 100644
--- a/test/recipes/20-test_app_s_client_msg.t
+++ b/test/recipes/20-test_app_s_client_msg.t
@@ -28,8 +28,8 @@ my $server_key   = srctop_file("test", "certs", "serverkey.pem");
 my $resultdir    = result_dir();

 # Each case exercises the s_client message callback (-msg) over a different
-# protocol version. Every record must be decoded; before the DTLSv1.2 fix such
-# records were logged as "Not TLS data or unknown version".
+# protocol version. Every record must be decoded; none may be logged as
+# "Not TLS data or unknown version".
 my @cases = (
     { name => "TLSv1.2",  flag => "-tls1_2",  disabled => "tls1_2" },
     { name => "TLSv1.3",  flag => "-tls1_3",  disabled => "tls1_3" },
diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t
index 634ddbb6e3..41cfcee278 100644
--- a/test/recipes/80-test_cms.t
+++ b/test/recipes/80-test_cms.t
@@ -1075,9 +1075,7 @@ subtest "CMS parse authenticatedData authAttrs and unauthAttrs\n" => sub {

     # BouncyCastle authenticatedData (HMAC-SHA256, KEK) carrying both an
     # authenticated and an unauthenticated attribute. Per RFC 5652 these are
-    # SET OF Attribute, so with the CMS_AuthenticatedData template fixed to use
-    # X509_ATTRIBUTE they are rendered as attributes (object:/set:) rather than
-    # as an X509_ALGOR (algorithm:/parameter:) they were misparsed into before.
+    # SET OF Attribute, and are rendered as attributes (object:/set:).
     my $exit = 0;
     my $dump = join "\n",
                run(app(["openssl", "cms", @defaultprov, "-cmsout", "-noout",
diff --git a/test/statem_clnt_construct_test.c b/test/statem_clnt_construct_test.c
index 5452676ba0..31bc29c3c6 100644
--- a/test/statem_clnt_construct_test.c
+++ b/test/statem_clnt_construct_test.c
@@ -947,7 +947,7 @@ err:
 #ifndef OSSL_NO_USABLE_TLS1_3
 /*
  * With middlebox compat on, the TLS 1.3 path changes the write keys; without a
- * negotiated cipher that fails rather than succeeding.
+ * negotiated cipher that fails.
  */
 static int test_construct_cert_change_cipher_fail(void)
 {
diff --git a/test/tls13tickettest.c b/test/tls13tickettest.c
index 300c6b2dbc..4fad87d93c 100644
--- a/test/tls13tickettest.c
+++ b/test/tls13tickettest.c
@@ -999,37 +999,25 @@ static int test_tls13_ticket_early_data_accepted(void)
  *
  * A session that negotiated ALPN is resumed on a connection that negotiates no
  * ALPN at all (the client advertises none). The NewSessionTicket issued for the
- * resumed session must not retain the ALPN protocol from the original session;
- * otherwise a later 0-RTT attempt using that ticket would incorrectly assume
- * that protocol had been negotiated.
+ * resumed session must not carry the ALPN protocol from the original session
+ * (GitHub issue #11197).
  *
- * Regression test for GitHub issue #11197: tls_construct_new_session_ticket()
- * copied s->s3.alpn_selected into the session only when an ALPN protocol was
- * negotiated, but failed to clear s->session->ext.alpn_selected when it wasn't.
+ * A third connection resumes the ALPN-cleared ticket and negotiates
+ * "goodalpn", the original session's protocol. The ticket carries no ALPN, so
+ * 0-RTT must be rejected: the client's SSL_write_early_data() succeeds (the
+ * data is sent before the server's response is known) and
+ * SSL_get_early_data_status() reports that the server did not accept it.
  *
- * A third connection then resumes the now-ALPN-cleared ticket and negotiates
- * "goodalpn" again -- the same, non-empty protocol as the original session,
- * coincidentally. Since the ticket being resumed carries no ALPN, 0-RTT must
- * still be rejected: the client's SSL_write_early_data() appears to succeed
- * (the data is sent before the server's response is known), but a post hoc
- * SSL_get_early_data_status() check confirms the server never accepted it.
+ * A fourth connection resumes the same ticket again (anti-replay is disabled
+ * for this test) advertising no ALPN, consistent with the ticket, and 0-RTT
+ * must be accepted. This shows the rejection in connection 3 is specific to
+ * the ALPN mismatch.
  *
- * A fourth connection resumes that same ALPN-cleared ticket a second time --
- * anti-replay is disabled for this test, so reusing it twice is not itself a
- * reason for rejection -- but this time advertises no ALPN, consistent with
- * what the ticket actually recorded. 0-RTT must now be accepted. Without this
- * case, the rejection asserted for connection 3 would be unfalsifiable: it
- * would look identical if early data were simply never being accepted here
- * for any reason at all.
- *
- * The fourth connection resumes from an independent SSL_SESSION_dup() copy
- * of the ticket (taken before connection 3 uses the original), rather than
- * the original SSL_SESSION object itself: completing a handshake from a
- * resumed session marks that SSL_SESSION object not-resumable on the client
- * side as a single-use safeguard, independent of (and in addition to) the
- * server's SSL_OP_NO_ANTI_REPLAY setting. Resuming the literal object a
- * second time would therefore quietly fall back to a full, non-PSK
- * handshake instead of testing the intended 0-RTT path.
+ * The fourth connection resumes from an SSL_SESSION_dup() copy taken before
+ * connection 3 uses the original. Completing a handshake from a resumed
+ * session marks that SSL_SESSION object not-resumable on the client side,
+ * independent of the server's SSL_OP_NO_ANTI_REPLAY setting, and resuming it
+ * again falls back to a full handshake.
  */
 static int test_tls13_ticket_alpn_cleared(void)
 {
@@ -1079,7 +1067,7 @@ static int test_tls13_ticket_alpn_cleared(void)
          * Connection 2: resume the session, but the client advertises no ALPN
          * this time so nothing is negotiated. The server issues a fresh
          * NewSessionTicket for the resumed session; its stored ALPN must be
-         * cleared rather than inheriting "goodalpn" from the original session.
+         * empty.
          */
         && TEST_true(tls_channel_init(c, s, &resumed))
         && TEST_true(SSL_set_session(resumed.c.ssl, sess))
@@ -1107,14 +1095,8 @@ static int test_tls13_ticket_alpn_cleared(void)
         && TEST_true(tls_shutdown(&resumed))
         && TEST_ptr(sess2 = SSL_get1_session(resumed.c.ssl))
         /*
-         * Connection 3 is about to resume sess2 and, since 0-RTT is attempted
-         * on it, the client will mark sess2 not-resumable once that attempt
-         * completes (this happens on any full handshake completed from a
-         * resumed session, independent of the server's anti-replay setting --
-         * it is a client-side single-use restriction on the SSL_SESSION
-         * object itself). Take an independent copy now, while sess2 is still
-         * untouched, so connection 4 below has its own unconsumed ticket to
-         * resume from.
+         * Connection 3 resumes sess2, after which the client marks sess2
+         * not-resumable. Connection 4 resumes from this copy.
          */
         && TEST_ptr(sess2b = SSL_SESSION_dup(sess2))
         /*
@@ -1146,13 +1128,9 @@ static int test_tls13_ticket_alpn_cleared(void)
             SSL_EARLY_DATA_REJECTED)
         && TEST_true(tls_shutdown(&resumed2))
         /*
-         * Connection 4: resume the same ticket from connection 2 again, via
-         * the untouched copy (sess2b) taken before connection 3 consumed
-         * sess2 -- anti-replay is off, so a second use of that ticket is not
-         * itself rejected -- but this time advertise no ALPN, matching what
-         * the ticket recorded. 0-RTT must be accepted, proving connection 3
-         * was rejected for the ALPN mismatch specifically, not because early
-         * data never works.
+         * Connection 4: resume the same ticket again via the copy (sess2b),
+         * anti-replay being off, advertising no ALPN, matching the ticket.
+         * 0-RTT must be accepted.
          */
         && TEST_true(tls_channel_init(c, s, &resumed3))
         && TEST_true(SSL_set_session(resumed3.c.ssl, sess2b))
diff --git a/test/unit/crypto/bio/test_bss_dgram_win.c b/test/unit/crypto/bio/test_bss_dgram_win.c
index 080d91c4e2..abdbef4efc 100644
--- a/test/unit/crypto/bio/test_bss_dgram_win.c
+++ b/test/unit/crypto/bio/test_bss_dgram_win.c
@@ -401,8 +401,7 @@ static void test_win_get_send_timeout_converts_milliseconds(void **state)
 /*
  * GET_RECV_TIMER_EXP checks data->_errno == WSAETIMEDOUT on Windows
  * (EAGAIN elsewhere), then consumes/clears it. WSAETIMEDOUT is treated
- * as fatal by BIO_dgram_non_fatal_error, so we set _errno directly
- * rather than driving it through a recvfrom retry that never sets it.
+ * as fatal by BIO_dgram_non_fatal_error, so set _errno directly.
  */
 static void test_win_recv_timer_exp_consumes_errno(void **state)
 {