]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add a test for an early DTLS CCS with extra data on the last record
authorMatt Caswell <matt@openssl.foundation>
Thu, 19 Mar 2026 11:44:48 +0000 (11:44 +0000)
committerTomas Mraz <tomas@openssl.foundation>
Fri, 3 Apr 2026 15:06:49 +0000 (17:06 +0200)
We move the DTLS CCS early, and then add extra trailing data on the
last record before the epoch change. We expect to see an unexpected
message error.

Reviewed-by: Frederik Wedel-Heinen <fwh.openssl@gmail.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Fri Apr  3 15:06:52 2026
(Merged from https://github.com/openssl/openssl/pull/30503)

test/build.info
test/dtls_ccs_reorder_test.c
test/helpers/ssltestlib.c
test/helpers/ssltestlib.h

index c7a9bd28f6e6d673f0af5373a333fab9404fdec3..4789b5b596751821aba93f86106378e082a5625f 100644 (file)
@@ -54,7 +54,7 @@ IF[{- !$disabled{tests} -}]
           dtlsv1listentest ct_test threadstest d2i_test \
           ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \
           bio_callback_test bio_memleak_test bio_core_test bio_dgram_test param_build_test \
-          sslapitest ssl_handshake_rtt_test dtlstest dtls_ccs_reorder_test sslcorrupttest \
+          sslapitest ssl_handshake_rtt_test dtlstest sslcorrupttest \
           bio_base64_test bio_enc_test pkey_meth_kdf_test evp_kdf_test uitest \
           cipherbytes_test threadstest_fips threadpool_test \
           asn1_encode_test asn1_decode_test asn1_string_table_test asn1_stable_parse_test \
@@ -98,6 +98,10 @@ IF[{- !$disabled{tests} -}]
     PROGRAMS{noinst}=cert_comp_test
   ENDIF
 
+  IF[{- !$disabled{dtls} -}]
+    PROGRAMS{noinst}=dtls_ccs_reorder_test
+  ENDIF
+
   SOURCE[confdump]=confdump.c
   INCLUDE[confdump]=../include ../apps/include
   DEPEND[confdump]=../libcrypto
@@ -657,9 +661,11 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[dtlstest]=../include ../apps/include
   DEPEND[dtlstest]=../libcrypto ../libssl libtestutil.a
 
-  SOURCE[dtls_ccs_reorder_test]=dtls_ccs_reorder_test.c helpers/ssltestlib.c
-  INCLUDE[dtls_ccs_reorder_test]=../include ../apps/include
-  DEPEND[dtls_ccs_reorder_test]=../libcrypto ../libssl libtestutil.a
+  IF[{- !$disabled{dtls} -}]
+    SOURCE[dtls_ccs_reorder_test]=dtls_ccs_reorder_test.c helpers/ssltestlib.c
+    INCLUDE[dtls_ccs_reorder_test]=../include ../apps/include
+    DEPEND[dtls_ccs_reorder_test]=../libcrypto ../libssl libtestutil.a
+  ENDIF
 
   SOURCE[sslcorrupttest]=sslcorrupttest.c helpers/ssltestlib.c
   INCLUDE[sslcorrupttest]=../include ../apps/include
index 5e145c961d128ab91a9799e5207dbba383003d51..5794c5e02fd3416fdd10331b7c0f0570b20972ce 100644 (file)
@@ -22,8 +22,6 @@
 static char *cert = NULL;
 static char *privkey = NULL;
 
-#ifndef OPENSSL_NO_DTLS
-
 static unsigned int infinite_timer_cb(SSL *s, unsigned int timer_us)
 {
     (void)s;
@@ -462,7 +460,64 @@ end:
     return testresult;
 }
 
-#endif /* OPENSSL_NO_DTLS */
+static int test_dtls_data_after_ccs(void)
+{
+    SSL_CTX *sctx = NULL, *cctx = NULL;
+    SSL *sssl = NULL, *cssl = NULL;
+    BIO *bio;
+    int testresult = 0, ret;
+    int target_pkt, target_rec;
+
+    if (!TEST_true(create_ssl_ctx_pair(NULL, DTLS_server_method(),
+            DTLS_client_method(),
+            DTLS1_2_VERSION, DTLS1_2_VERSION,
+            &sctx, &cctx, cert, privkey)))
+        return 0;
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL)))
+        goto end;
+
+    DTLS_set_timer_cb(sssl, infinite_timer_cb);
+    DTLS_set_timer_cb(cssl, infinite_timer_cb);
+
+    if (!TEST_int_le(SSL_connect(cssl), 0))
+        goto end;
+
+    if (!TEST_int_le(SSL_accept(sssl), 0))
+        goto end;
+
+    if (!TEST_int_le(SSL_connect(cssl), 0))
+        goto end;
+
+    bio = SSL_get_wbio(cssl);
+    if (!TEST_ptr(bio)
+        || !TEST_true(reorder_ccs(bio, SSL3_MT_CLIENT_KEY_EXCHANGE)))
+        goto end;
+
+    if (!TEST_true(mempacket_find_record(bio, SSL3_RT_HANDSHAKE,
+            SSL3_MT_CLIENT_KEY_EXCHANGE,
+            &target_pkt, &target_rec)))
+        goto end;
+    if (!TEST_true(mempacket_append_to_record(bio, target_pkt, target_rec,
+            (unsigned char *)"test data", 9)))
+        goto end;
+
+    ret = SSL_accept(sssl);
+    if (!TEST_int_le(ret, 0))
+        goto end;
+    if (!TEST_int_eq(SSL_get_error(sssl, ret), SSL_ERROR_SSL))
+        goto end;
+    if (!TEST_int_eq(ERR_GET_REASON(ERR_get_error()), SSL_R_UNEXPECTED_MESSAGE))
+        goto end;
+
+    testresult = 1;
+end:
+    SSL_free(sssl);
+    SSL_free(cssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    return testresult;
+}
 
 int setup_tests(void)
 {
@@ -475,11 +530,10 @@ int setup_tests(void)
         || !TEST_ptr(privkey = test_get_argument(1)))
         return 0;
 
-#ifndef OPENSSL_NO_DTLS
     ADD_ALL_TESTS(test_dtls_ccs_full_hs, OSSL_NELEM(full_hs_tests));
     ADD_ALL_TESTS(test_dtls_ccs_before_nst, OSSL_NELEM(nst_versions));
     ADD_ALL_TESTS(test_dtls_ccs_resume, OSSL_NELEM(resume_tests));
-#endif
+    ADD_TEST(test_dtls_data_after_ccs);
 
     return 1;
 }
index 8e512eaabb936a15cce5ee1e38a4384405ed88ec..57b8c3e0403cb5e4c738010c112e39c2b255f4d6 100644 (file)
@@ -636,6 +636,59 @@ int mempacket_split_packet_at(BIO *bio, int pktidx, int recidx)
     return 1;
 }
 
+/*
+ * Append arbitrary data to a given record. The record must be the last record
+ * in the packet
+ */
+int mempacket_append_to_record(BIO *bio, int pktidx, int recidx,
+    unsigned char *data, size_t datalen)
+{
+    MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+    MEMPACKET *srcpkt;
+    size_t rem, len;
+    int i;
+    unsigned char *rec, *tmp;
+
+    if (ctx == NULL)
+        return 0;
+    srcpkt = sk_MEMPACKET_value(ctx->pkts, pktidx);
+    if (srcpkt == NULL)
+        return 0;
+
+    tmp = OPENSSL_realloc(srcpkt->data, srcpkt->len + datalen);
+    if (tmp == NULL)
+        return 0;
+    srcpkt->data = tmp;
+
+    /* Parse the records in the packet looking for the target record index */
+    for (i = 0, rem = srcpkt->len, rec = srcpkt->data;
+        rem >= DTLS1_RT_HEADER_LENGTH && i < recidx;
+        i++, rem -= len, rec += len) {
+        len = ((rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO])
+            + DTLS1_RT_HEADER_LENGTH;
+        if (rem < len)
+            return 0;
+    }
+
+    if (i != recidx || rem < DTLS1_RT_HEADER_LENGTH)
+        return 0;
+
+    len = (rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO];
+    /* We can only append to the last record */
+    if (rem != len + DTLS1_RT_HEADER_LENGTH)
+        return 0;
+
+    /* Check we can fit the extra data in the record */
+    if (0xffff - len < datalen)
+        return 0;
+    len += datalen;
+    rec[RECORD_LEN_HI] = (len >> 8) & 0xff;
+    rec[RECORD_LEN_LO] = len & 0xff;
+    memcpy(srcpkt->data + srcpkt->len, data, datalen);
+    srcpkt->len += (int)datalen;
+    return 1;
+}
+
 int mempacket_dup_last_packet(BIO *bio)
 {
     MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
index 54aeb6b50c8e3ceac65ec43bb2148e8f0019d25b..68a10b24bd1aa660b69421a5e01f82a9e62646e0 100644 (file)
@@ -77,6 +77,8 @@ int mempacket_move_packet(BIO *bio, int d, int s);
 int mempacket_find_record(BIO *bio, int rectype, int hs_msg_type,
     int *pktidx, int *recidx);
 int mempacket_split_packet_at(BIO *bio, int pktidx, int recidx);
+int mempacket_append_to_record(BIO *bio, int pktidx, int recidx,
+    unsigned char *data, size_t datalen);
 int mempacket_dup_last_packet(BIO *bio);
 int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum,
     int type);