add test for rebuilding inner CH
diff --git a/lib/picotls.c b/lib/picotls.c
index c6654cf..3a6eaa8 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -3717,6 +3717,56 @@
return ret;
}
+static int rebuild_ch_inner_extensions(ptls_buffer_t *buf, const uint8_t **src, const uint8_t *const end, const uint8_t *outer_ext,
+ const uint8_t *outer_ext_end)
+{
+ int ret;
+
+ ptls_buffer_push_block(buf, 2, {
+ ptls_decode_open_block(*src, end, 2, {
+ while (*src != end) {
+ uint16_t exttype;
+ if ((ret = ptls_decode16(&exttype, src, end)) != 0)
+ goto Exit;
+ ptls_decode_open_block(*src, end, 2, {
+ if (exttype == PTLS_EXTENSION_TYPE_ECH_OUTER_EXTENSIONS) {
+ ptls_decode_open_block(*src, end, 1, {
+ do {
+ uint16_t reftype;
+ uint16_t outertype;
+ uint16_t outersize;
+ if ((ret = ptls_decode16(&reftype, src, end)) != 0)
+ goto Exit;
+ while (1) {
+ if ((ret = ptls_decode16(&outertype, &outer_ext, outer_ext_end)) != 0 ||
+ (ret = ptls_decode16(&outersize, &outer_ext, outer_ext_end)) != 0)
+ goto Exit;
+ assert(outer_ext_end - outer_ext >= outersize);
+ if (outertype == reftype)
+ break;
+ outer_ext += outersize;
+ }
+ buffer_push_extension(buf, reftype, {
+ ptls_buffer_pushv(buf, outer_ext, outersize);
+ outer_ext += outersize;
+ });
+ } while (*src != end);
+ });
+ } else {
+ buffer_push_extension(buf, exttype, {
+ ptls_buffer_pushv(buf, *src, end - *src);
+ *src = end;
+ });
+ }
+ });
+ }
+ });
+ });
+
+Exit:
+ return ret;
+}
+
static int rebuild_ch_inner(ptls_buffer_t *buf, const uint8_t *src, const uint8_t *const end,
struct st_ptls_client_hello_t *outer_ch, const uint8_t *outer_ext, const uint8_t *outer_ext_end)
{
@@ -3760,46 +3810,8 @@
COPY_BLOCK(1);
/* extensions */
- ptls_buffer_push_block(buf, 2, {
- ptls_decode_open_block(src, end, 2, {
- while (src != end) {
- uint16_t exttype;
- if ((ret = ptls_decode16(&exttype, &src, end)) != 0)
- goto Exit;
- ptls_decode_open_block(src, end, 2, {
- if (exttype == PTLS_EXTENSION_TYPE_ECH_OUTER_EXTENSIONS) {
- ptls_decode_open_block(src, end, 1, {
- do {
- uint16_t reftype;
- uint16_t outertype;
- uint16_t outersize;
- if ((ret = ptls_decode16(&reftype, &src, end)) != 0)
- goto Exit;
- while (1) {
- if ((ret = ptls_decode16(&outertype, &outer_ext, outer_ext_end)) != 0 ||
- (ret = ptls_decode16(&outersize, &outer_ext, outer_ext_end)) != 0)
- goto Exit;
- assert(outer_ext_end - outer_ext >= outersize);
- if (outertype == reftype)
- break;
- outer_ext += outersize;
- }
- buffer_push_extension(buf, reftype, {
- ptls_buffer_pushv(buf, outer_ext, outersize);
- outer_ext += outersize;
- });
- } while (src != end);
- });
- } else {
- buffer_push_extension(buf, exttype, {
- ptls_buffer_pushv(buf, src, end - src);
- src = end;
- });
- }
- });
- }
- });
- });
+ if ((ret = rebuild_ch_inner_extensions(buf, &src, end, outer_ext, outer_ext_end)) != 0)
+ goto Exit;
});
/* padding must be all zero */
diff --git a/t/picotls.c b/t/picotls.c
index f2ee970..083c9d0 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -538,9 +538,65 @@
}
}
+static void test_rebuild_ch_inner(void)
+{
+ ptls_buffer_t buf;
+ ptls_buffer_init(&buf, "", 0);
+
+#define TEST(_expected_err) \
+ do { \
+ const uint8_t *src = encoded_inner; \
+ buf.off = 0; \
+ ok(rebuild_ch_inner_extensions(&buf, &src, encoded_inner + sizeof(encoded_inner), outer, outer + sizeof(outer)) == \
+ _expected_err); \
+ if (_expected_err == 0) { \
+ ok(src == encoded_inner + sizeof(encoded_inner)); \
+ ok(buf.off == sizeof(expected)); \
+ ok(memcmp(buf.base, expected, sizeof(expected)) == 0); \
+ } \
+ } while (0)
+
+ { /* replace none */
+ static const uint8_t encoded_inner[] = {0x00, 0x09, 0x12, 0x34, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, outer[] = {},
+ expected[] = {0x00, 0x09, 0x12, 0x34, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f};
+ TEST(0);
+ }
+
+ { /* replace one */
+ static const uint8_t encoded_inner[] = {0x00, 0x07, 0xfd, 0x00, 0x00, 0x03, 0x02, 0x00, 0x01},
+ outer[] = {0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f},
+ expected[] = {0x00, 0x09, 0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f};
+ TEST(0);
+ }
+
+ { /* replace multi */
+ static const uint8_t encoded_inner[] = {0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x31, 0xfd, 0x00, 0x00, 0x05,
+ 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x01, 0x35},
+ outer[] = {0x00, 0x01, 0x00, 0x01, 0x41, 0x00, 0x02, 0x00, 0x01, 0x42, 0x00, 0x03, 0x00,
+ 0x01, 0x43, 0x00, 0x04, 0x00, 0x01, 0x44, 0x00, 0x05, 0x00, 0x01, 0x45},
+ expected[] = {0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x01,
+ 0x42, 0x00, 0x04, 0x00, 0x01, 0x44, 0x00, 0x05, 0x00, 0x01, 0x35};
+ TEST(0);
+ }
+
+ { /* outer extension not found */
+ static const uint8_t encoded_inner[] = {0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x31, 0xfd, 0x00, 0x00, 0x05,
+ 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x01, 0x35},
+ outer[] = {0x00, 0x01, 0x00, 0x01, 0x41, 0x00, 0x02, 0x00, 0x01, 0x42, 0x00, 0x03, 0x00,
+ 0x01, 0x43},
+ expected[] = {0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x01,
+ 0x42, 0x00, 0x04, 0x00, 0x01, 0x44, 0x00, 0x05, 0x00, 0x01, 0x35};
+ TEST(PTLS_ALERT_ILLEGAL_PARAMETER);
+ }
+
+#undef TEST
+ ptls_buffer_dispose(&buf);
+}
+
static void test_ech(void)
{
subtest("decode-config", test_ech_decode_config);
+ subtest("rebuild_ch_inner", test_rebuild_ch_inner);
}
static struct {