summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2022-06-17 16:37:24 +0100
committerTomas Mraz <tomas@openssl.org>2022-11-21 10:49:52 +0100
commit713f6a14e2510b9de56559f2433da3179fdc9c84 (patch)
tree08a875d7959cbd345cd6b6a4a2e3c2e3c07329bf
parent01c7d59f0358ec6cf3dd45012a2dc8abee670f3e (diff)
Add a DTLS next epoch test
Test that if we receive a packet from the next epoch, we can buffer it and still use it. Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18601) (cherry picked from commit e1c153d31d4f913ebe2202a4bc20305919274d1f)
-rw-r--r--test/dtlstest.c75
-rw-r--r--test/helpers/ssltestlib.c83
-rw-r--r--test/helpers/ssltestlib.h1
3 files changed, 159 insertions, 0 deletions
diff --git a/test/dtlstest.c b/test/dtlstest.c
index 3ada3ce2b1..35c616cabd 100644
--- a/test/dtlstest.c
+++ b/test/dtlstest.c
@@ -463,6 +463,80 @@ static int test_just_finished(void)
}
/*
+ * Test that swapping a record from the next epoch into the current epoch still
+ * works. Libssl should buffer the record until it needs it.
+ */
+static int test_swap_epoch(void)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *sssl = NULL, *cssl = NULL;
+ int testresult = 0;
+ BIO *bio;
+
+ if (!TEST_true(create_ssl_ctx_pair(NULL, DTLS_server_method(),
+ DTLS_client_method(),
+ DTLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ return 0;
+
+#ifndef OPENSSL_NO_DTLS1_2
+ if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES128-SHA")))
+ goto end;
+#else
+ /* Default sigalgs are SHA1 based in <DTLS1.2 which is in security level 0 */
+ if (!TEST_true(SSL_CTX_set_cipher_list(sctx, "AES128-SHA:@SECLEVEL=0"))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ "AES128-SHA:@SECLEVEL=0")))
+ goto end;
+#endif
+
+
+ /* BIO is freed by create_ssl_connection on error */
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl,
+ NULL, NULL)))
+ goto end;
+
+ /* Send flight 1: ClientHello */
+ if (!TEST_int_le(SSL_connect(cssl), 0))
+ goto end;
+
+ /* Recv flight 1, send flight 2: ServerHello, Certificate, ServerHelloDone */
+ if (!TEST_int_le(SSL_accept(sssl), 0))
+ goto end;
+
+ /* Recv flight 2, send flight 3: ClientKeyExchange, CCS, Finished */
+ if (!TEST_int_le(SSL_connect(cssl), 0))
+ goto end;
+
+ bio = SSL_get_wbio(cssl);
+ if (!TEST_ptr(bio)
+ || !TEST_true(mempacket_swap_epoch(bio)))
+ goto end;
+
+ /*
+ * Recv flight 3, send flight 4: CCS, Finished.
+ * This should work in a single call because we have all the messages we
+ * need. Even though we had out of order packets, the record for the next
+ * epoch that we read early should be buffered and used later.
+ */
+ if (!TEST_int_gt(SSL_accept(sssl), 0))
+ goto end;
+
+
+ /* Recv flight 4 */
+ if (!TEST_int_gt(SSL_connect(cssl), 0))
+ goto end;
+
+ testresult = 1;
+ end:
+ SSL_free(cssl);
+ SSL_free(sssl);
+ SSL_CTX_free(cctx);
+ SSL_CTX_free(sctx);
+ return testresult;
+}
+
+/*
* Test that swapping an app data record so that it is received before the
* Finished message still works.
*/
@@ -569,6 +643,7 @@ int setup_tests(void)
ADD_TEST(test_cookie);
ADD_TEST(test_dtls_duplicate_records);
ADD_TEST(test_just_finished);
+ ADD_TEST(test_swap_epoch);
ADD_TEST(test_swap_app_data);
return 1;
diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c
index 3b74ddb088..6aadc33413 100644
--- a/test/helpers/ssltestlib.c
+++ b/test/helpers/ssltestlib.c
@@ -406,10 +406,93 @@ static int mempacket_test_read(BIO *bio, char *out, int outl)
}
memcpy(out, thispkt->data, outl);
+
mempacket_free(thispkt);
return outl;
}
+/*
+ * Look for records from different epochs and swap them around
+ */
+int mempacket_swap_epoch(BIO *bio)
+{
+ MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio);
+ MEMPACKET *thispkt;
+ int rem, len, prevlen = 0, pktnum;
+ unsigned char *rec, *prevrec = NULL, *tmp;
+ unsigned int epoch;
+ int numpkts = sk_MEMPACKET_num(ctx->pkts);
+
+ if (numpkts <= 0)
+ return 0;
+
+ /*
+ * If there are multiple packets we only look in the last one. This should
+ * always be the one where any epoch change occurs.
+ */
+ thispkt = sk_MEMPACKET_value(ctx->pkts, numpkts - 1);
+ if (thispkt == NULL)
+ return 0;
+
+ for (rem = thispkt->len, rec = thispkt->data; rem > 0; rem -= len, rec += len) {
+ if (rem < DTLS1_RT_HEADER_LENGTH)
+ return 0;
+ epoch = (rec[EPOCH_HI] << 8) | rec[EPOCH_LO];
+ len = ((rec[RECORD_LEN_HI] << 8) | rec[RECORD_LEN_LO])
+ + DTLS1_RT_HEADER_LENGTH;
+ if (rem < len)
+ return 0;
+
+ /* Assumes the epoch change does not happen on the first record */
+ if (epoch != ctx->epoch) {
+ if (prevrec == NULL)
+ return 0;
+
+ /*
+ * We found 2 records with different epochs. Take a copy of the
+ * earlier record
+ */
+ tmp = OPENSSL_malloc(prevlen);
+ if (tmp == NULL)
+ return 0;
+
+ memcpy(tmp, prevrec, prevlen);
+ /*
+ * Move everything from this record onwards, including any trailing
+ * records, and overwrite the earlier record
+ */
+ memmove(prevrec, rec, rem);
+ thispkt->len -= prevlen;
+ pktnum = thispkt->num;
+
+ /*
+ * Create a new packet for the earlier record that we took out and
+ * add it to the end of the packet list.
+ */
+ thispkt = OPENSSL_malloc(sizeof(*thispkt));
+ if (thispkt == NULL) {
+ OPENSSL_free(tmp);
+ return 0;
+ }
+ thispkt->type = INJECT_PACKET;
+ thispkt->data = tmp;
+ thispkt->len = prevlen;
+ thispkt->num = pktnum + 1;
+ if (sk_MEMPACKET_insert(ctx->pkts, thispkt, numpkts) <= 0) {
+ OPENSSL_free(tmp);
+ OPENSSL_free(thispkt);
+ return 0;
+ }
+
+ return 1;
+ }
+ prevrec = rec;
+ prevlen = len;
+ }
+
+ return 0;
+}
+
/* Take the last and penultimate packets and swap them around */
int mempacket_swap_recent(BIO *bio)
{
diff --git a/test/helpers/ssltestlib.h b/test/helpers/ssltestlib.h
index 1f9e803ffc..93c5316d7a 100644
--- a/test/helpers/ssltestlib.h
+++ b/test/helpers/ssltestlib.h
@@ -49,6 +49,7 @@ void bio_s_always_retry_free(void);
#define MEMPACKET_CTRL_GET_DROP_REC (3 << 15)
#define MEMPACKET_CTRL_SET_DUPLICATE_REC (4 << 15)
+int mempacket_swap_epoch(BIO *bio);
int mempacket_swap_recent(BIO *bio);
int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum,
int type);