From 0cfa660de17c7c3b078064713b0acc2575d8c8d3 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Dec 2022 16:30:17 +0900 Subject: [PATCH] add ECH test (at the moment, only for TCP) --- examples/h2o/ech.key | 5 ++ h2o.xcodeproj/project.pbxproj | 2 + t/40tls-ech.t | 90 +++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 examples/h2o/ech.key create mode 100644 t/40tls-ech.t diff --git a/examples/h2o/ech.key b/examples/h2o/ech.key new file mode 100644 index 000000000..b6eda5339 --- /dev/null +++ b/examples/h2o/ech.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg885/2uV+GjENh/Hr +vebzKL4Kmc28rfTWWJzyneS4/9KhRANCAAT+jBnOCQUZHrwpipJFeSUx8m8M7OJG +BjnovDnLf3Bqgmp3m0z5abig5TnH9i+z0wrWqo+A4w8dEoqv1oos5y6g +-----END PRIVATE KEY----- diff --git a/h2o.xcodeproj/project.pbxproj b/h2o.xcodeproj/project.pbxproj index 038a1188d..85cfb7e3f 100644 --- a/h2o.xcodeproj/project.pbxproj +++ b/h2o.xcodeproj/project.pbxproj @@ -738,6 +738,7 @@ 08819C2C218C9FA90057ED23 /* qif */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = qif; sourceTree = BUILT_PRODUCTS_DIR; }; 08819C2D218C9FF70057ED23 /* qif.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = qif.c; sourceTree = ""; }; 08B3297E29407664009D6766 /* hpke.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hpke.c; sourceTree = ""; }; + 08B329832941B407009D6766 /* 40tls-ech.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = "40tls-ech.t"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; 08B3D43A26042CAF002F195C /* 50connect-deadlock.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = "50connect-deadlock.t"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; 08C7C365262AB30F009C944C /* 40mtls.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = 40mtls.t; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; 08CEA9CF2662136B00B4BB6B /* 80http3-header-linefeed.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = "80http3-header-linefeed.t"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.perl; }; @@ -2249,6 +2250,7 @@ 107D4D501B58B342004A9B21 /* 40session-ticket.t */, 0810E6AB286DACB600333FA4 /* 40soft-connection-limit.t */, 104B9A321A59E27A009EEE64 /* 40ssl-cipher-suite.t */, + 08B329832941B407009D6766 /* 40tls-ech.t */, 086001CC273BBBCF0043886F /* 40tls-multiple-certs.t */, E93BB6D025E09504009C24D8 /* 40tls-raw-pubkey.t */, E9F677D82008686B006476D3 /* 40tls13-early-data.t */, diff --git a/t/40tls-ech.t b/t/40tls-ech.t new file mode 100644 index 000000000..c8b681676 --- /dev/null +++ b/t/40tls-ech.t @@ -0,0 +1,90 @@ +use strict; +use warnings; +use File::Temp qw(tempdir); +use Net::EmptyPort qw(empty_port); +use Test::More; +use Time::HiRes qw(sleep); +use t::Util; + +my $tempdir = tempdir(CLEANUP => 1); +my $tls_port = empty_port(); + +my $server = spawn_h2o_raw(<<"EOT", [ $tls_port ]); +num-threads: 1 +listen: + port: $tls_port + ssl: &ssl + identity: + - key-file: deps/picotls/t/assets/secp256r1/key.pem + certificate-file: deps/picotls/t/assets/secp256r1/cert.pem + - key-file: examples/h2o/server.key + certificate-file: examples/h2o/server.crt + ech: + - key-file: examples/h2o/ech.key + config-id: 0 + public-name: ech.examp1e.net +listen: + port: $tls_port + type: quic + ssl: + <<: *ssl +hosts: + default: + paths: + /: + file.dir: t/assets/doc_root +EOT + +my $req_fn = "$tempdir/req"; +my $ech_config_fn = "$tempdir/echconfig"; +my $trace_fn = "$tempdir/trace.out"; + +{ # build request + open my $fh, ">", $req_fn + or die "failed to create file:$req_fn:$!"; + print $fh "GET /index.txt HTTP/1.0\r\n\r\n"; +} + +subtest "tcp" => sub { + create_empty_file($ech_config_fn); + create_empty_file($trace_fn); + + # first connection is grease ECH + my $resp = fetch(); + like $resp, qr{\r\n\r\nhello\n$}s, "response"; + sleep 0.1; + ok !trace_says_ech(), "connection is non-ECH"; + isnt +(stat $ech_config_fn)[7], 0, "got retry_configs"; + + create_empty_file($trace_fn); + + # second connection is ECH + $resp = fetch(); + like $resp, qr{\r\n\r\nhello\n$}s, "response"; + sleep 0.1; + ok trace_says_ech(), "connection is ECH"; + isnt +(stat $ech_config_fn)[7], 0, "got retry_configs"; +}; + +done_testing; + +sub fetch { + open my $fh, "@{[bindir()]}/picotls/cli -j $trace_fn -I -E $ech_config_fn localhost.examp1e.net $tls_port < $req_fn |" + or die "failed to launch @{[bindir()]}/picotls/cli:$!"; + join "", <$fh>; +} + +sub trace_says_ech { + open my $fh, "<", $trace_fn + or die "failed to open file:$trace_fn:$!"; + my $lines = join "", <$fh>; + $lines =~ /[{,]"type":"ech_selection".*,"is_ech":(true|false)[,}]/ + or die "unexpected trace:$lines"; + $1 eq "true"; +} + +sub create_empty_file { + my $fn = shift; + open my $fh, ">", $fn + or die "failed to create file:$fn:$!"; +}