QUIC TXP: Test packet size boundary cases
authorHugo Landau <hlandau@openssl.org>
Tue, 11 Jul 2023 14:30:46 +0000 (15:30 +0100)
committerTomas Mraz <tomas@openssl.org>
Fri, 21 Jul 2023 06:43:52 +0000 (08:43 +0200)
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21458)

test/quic_txp_test.c

index 52026d3569130ccec6524388296b98f51313aeab..0056d46172c0430e69eacf9fd152afd28840b37d 100644 (file)
@@ -1224,18 +1224,19 @@ static void skip_padding(struct helper *h)
         ossl_quic_wire_decode_padding(&h->pkt);
 }
 
-static int run_script(const struct script_op *script)
+static int run_script(int script_idx, const struct script_op *script)
 {
     int testresult = 0, have_helper = 0;
     QUIC_TXP_STATUS status;
     struct helper h;
     const struct script_op *op;
+    size_t opn = 0;
 
     if (!helper_init(&h))
         goto err;
 
     have_helper = 1;
-    for (op = script; op->opcode != OPK_END; ++op) {
+    for (op = script, opn = 0; op->opcode != OPK_END; ++op, ++opn) {
         switch (op->opcode) {
         case OPK_TXP_GENERATE:
             if (!TEST_int_eq(ossl_quic_tx_packetiser_generate(h.txp, (int)op->arg0,
@@ -1535,6 +1536,8 @@ static int run_script(const struct script_op *script)
 
     testresult = 1;
 err:
+    if (!testresult)
+        TEST_error("script %d failed at op %zu", script_idx + 1, opn + 1);
     if (have_helper)
         helper_cleanup(&h);
     return testresult;
@@ -1542,11 +1545,71 @@ err:
 
 static int test_script(int idx)
 {
-    return run_script(scripts[idx]);
+    if (idx + 1 != 18) return 1;
+    return run_script(idx, scripts[idx]);
+}
+
+/*
+ * Dynamic Script 1.
+ *
+ * This script exists to test the interactions between multiple packets (ELs) in
+ * the same datagram when there is a padding requirement (due to the datagram
+ * containing an Initial packet). There are boundary cases which are difficult
+ * to get right so it is important to test this entire space. Examples of such
+ * edge cases include:
+ *
+ * - If we are planning on generating both an Initial and Handshake packet in a
+ *   datagram ordinarily we would plan on adding the padding frames to meet the
+ *   mandatory minimum size to the last packet in the datagram (i.e., the
+ *   Handshake packet). But if the amount of room remaining in a datagram is
+ *   e.g. only 3 bytes after generating the Initial packet, this is not
+ *   enough room for another packet and we have a problem as having finished
+ *   the Initial packet we have no way to add the necessary padding.
+ *
+ * - If we do have room for another packet but it is not enough room to encode
+ *   any desired frame.
+ *
+ * This test confirms we handle these cases correctly for multi-packet datagrams
+ * by placing two packets in a datagram and varying the size of the first
+ * datagram.
+ */
+static const unsigned char dyn_script_1_crypto_1a[1200];
+static const unsigned char dyn_script_1_crypto_1b[1];
+
+static struct script_op dyn_script_1[] = {
+    OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_INITIAL, QRL_SUITE_AES128GCM, secret_1)
+    OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_HANDSHAKE, QRL_SUITE_AES128GCM, secret_1)
+    OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
+    OP_CRYPTO_SEND(QUIC_PN_SPACE_INITIAL, dyn_script_1_crypto_1a) /* [crypto_idx] */
+    OP_CRYPTO_SEND(QUIC_PN_SPACE_HANDSHAKE, dyn_script_1_crypto_1b)
+    OP_TXP_GENERATE(TX_PACKETISER_ARCHETYPE_NORMAL)
+    OP_RX_PKT()
+    OP_EXPECT_DGRAM_LEN(1200, 1200)
+    OP_END
+};
+
+static const size_t dyn_script_1_crypto_idx = 3;
+static const size_t dyn_script_1_start_from = 1000;
+
+static int test_dyn_script_1(int idx)
+{
+    size_t target_size = dyn_script_1_start_from + (size_t)idx;
+
+    dyn_script_1[dyn_script_1_crypto_idx].buf_len = target_size;
+
+    if (!run_script(idx, dyn_script_1)) {
+        TEST_error("failed dyn script 1 with target size %zu", target_size);
+        return 0;
+    }
+
+    return 1;
 }
 
 int setup_tests(void)
 {
     ADD_ALL_TESTS(test_script, OSSL_NELEM(scripts));
+    ADD_ALL_TESTS(test_dyn_script_1,
+                  OSSL_NELEM(dyn_script_1_crypto_1a)
+                  - dyn_script_1_start_from + 1);
     return 1;
 }