# HG changeset patch # User Sergey Kandaurov # Date 1677158757 -14400 # Node ID 1023354f3a412ef897f66de119aabb0810739936 # Parent 90a310f3cee674fc2af1c4536cb3b22f77283ea6 Tests: ssl_reject_handshake tests with HTTP/3. Notably, LibreSSL fails to properly implement QUIC send_alert callback. It uses to return send_alert result as the result of TLS handshake. diff --git a/h3_ssl_reject_handshake.t b/h3_ssl_reject_handshake.t new file mode 100644 --- /dev/null +++ b/h3_ssl_reject_handshake.t @@ -0,0 +1,166 @@ +#!/usr/bin/perl + +# (C) Sergey Kandaurov +# (C) Nginx, Inc. + +# Tests for HTTP/3 protocol, ssl_reject_handshake. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::HTTP3; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +eval { require Crypt::Misc; die if $Crypt::Misc::VERSION < 0.067; }; +plan(skip_all => 'CryptX version >= 0.067 required') if $@; + +my $t = Test::Nginx->new()->has(qw/http http_v3/) + ->has_daemon('openssl')->plan(7) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + add_header X-Name $ssl_server_name; + + server { + listen 127.0.0.1:%%PORT_8980_UDP%% quic; + server_name localhost; + + ssl_reject_handshake on; + } + + server { + listen 127.0.0.1:%%PORT_8980_UDP%% quic; + server_name virtual; + + ssl_certificate localhost.crt; + ssl_certificate_key localhost.key; + } + + server { + listen 127.0.0.1:%%PORT_8982_UDP%% quic; + server_name localhost; + + ssl_certificate localhost.crt; + ssl_certificate_key localhost.key; + } + + server { + listen 127.0.0.1:%%PORT_8982_UDP%% quic; + server_name virtual1; + } + + server { + listen 127.0.0.1:%%PORT_8982_UDP%% quic; + server_name virtual2; + + ssl_reject_handshake on; + } +} + +EOF + +$t->write_file('openssl.conf', <testdir(); + +foreach my $name ('localhost') { + system('openssl req -x509 -new ' + . "-config $d/openssl.conf -subj /CN=$name/ " + . "-out $d/$name.crt -keyout $d/$name.key " + . ">>$d/openssl.out 2>&1") == 0 + or die "Can't create certificate for $name: $!\n"; +} + +$t->write_file('index.html', ''); + +$t->run(); + +############################################################################### + +my $alert = 0x100 + 112; # "unrecognized_name" + +SKIP: { +# OpenSSL < 1.1.1j requires TLSv1.3-capable certificates in the default server +# See commit "Modify is_tls13_capable() to take account of the servername cb" +# Additionally, it was seen with OpenSSL 1.1.1k FIPS as found on RHEL 8.1 + +my $got = bad('default', 8980); +skip "OpenSSL too old", 3 if $got && $got == 0x100 + 70; # "protocol_version" + +# default virtual server rejected + +TODO: { +local $TODO = 'broken send_alert in LibreSSL' if $t->has_module('LibreSSL'); + +is(bad('default', 8980), $alert, 'default rejected'); +is(bad(undef, 8980), $alert, 'absent sni rejected'); + +} + +like(get('virtual', 8980), qr/virtual/, 'virtual accepted'); + +} + +# non-default server "virtual2" rejected + +like(get('default', 8982), qr/default/, 'default accepted'); +like(get(undef, 8982), qr/200/, 'absent sni accepted'); +like(get('virtual1', 8982), qr/virtual1/, 'virtual 1 accepted'); + +TODO: { +local $TODO = 'broken send_alert in LibreSSL' if $t->has_module('LibreSSL'); + +is(bad('virtual2', 8982), $alert, 'virtual 2 rejected'); + +} + +############################################################################### + +sub get { + my ($sni, $port) = @_; + my $s = Test::Nginx::HTTP3->new($port, sni => $sni); + my $sid = $s->new_stream({ host => $sni }); + my $frames = $s->read(all => [{ sid => $sid, fin => 1 }]); + + my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames; + return $frame->{headers}->{':status'} + . ($frame->{headers}->{'x-name'} || ''); +} + +sub bad { + my ($sni, $port) = @_; + my $s = Test::Nginx::HTTP3->new($port, sni => $sni, probe => 1); + my $frames = $s->read(all => [{ type => "CONNECTION_CLOSE" }]); + + my ($frame) = grep { $_->{type} eq "CONNECTION_CLOSE" } @$frames; + return $frame->{error}; +} + +############################################################################### diff --git a/lib/Test/Nginx/HTTP3.pm b/lib/Test/Nginx/HTTP3.pm --- a/lib/Test/Nginx/HTTP3.pm +++ b/lib/Test/Nginx/HTTP3.pm @@ -53,6 +53,7 @@ sub new { $self->init(); $self->init_key_schedule(); $self->initial(); + return $self if $extra{probe}; $self->handshake() or return; # RFC 9204, 4.3.1. Set Dynamic Table Capacity @@ -2171,6 +2172,7 @@ sub build_tls_client_hello { sub build_tlsext_server_name { my ($name) = @_; + return '' if !defined $name; my $sname = pack('xn', length($name)) . $name; my $snamelist = pack('n', length($sname)) . $sname; pack('n2', 0, length($snamelist)) . $snamelist;