Mercurial > hg > nginx-tests
comparison ssl_verify_client.t @ 1865:0e1865aa9b33
Tests: reworked http SSL tests to use IO::Socket::SSL.
Relevant infrastructure is provided in Test::Nginx http() functions.
This also ensures that SSL handshake and various read and write operations
are guarded with timeouts.
The ssl_sni_reneg.t test uses IO::Socket::SSL::_get_ssl_object() to access
the Net::SSLeay object directly and trigger renegotation. While
not exactly correct, this seems to be good enough for tests.
Similarly, IO::Socket::SSL::_get_ssl_object() is used in ssl_stapling.t,
since SSL_ocsp_staple_callback is called with the socket instead of the
Net::SSLeay object.
Similarly, IO::Socket::SSL::_get_ssl_object() is used in ssl_verify_client.t,
since there seems to be no way to obtain CA list with IO::Socket::SSL.
Notable change to http() request interface is that http_end() now closes
the socket. This is to make sure that SSL connections are properly
closed and SSL sessions are not removed from the IO::Socket::SSL session
cache. This affected access_log.t, which was modified accordingly.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 18 May 2023 18:07:17 +0300 |
parents | 818e6d8c43b5 |
children | b72a8c4a1bef |
comparison
equal
deleted
inserted
replaced
1864:46351d990aee | 1865:0e1865aa9b33 |
---|---|
15 use Socket qw/ CRLF /; | 15 use Socket qw/ CRLF /; |
16 | 16 |
17 BEGIN { use FindBin; chdir($FindBin::Bin); } | 17 BEGIN { use FindBin; chdir($FindBin::Bin); } |
18 | 18 |
19 use lib 'lib'; | 19 use lib 'lib'; |
20 use Test::Nginx; | 20 use Test::Nginx qw/ :DEFAULT http_end /; |
21 | 21 |
22 ############################################################################### | 22 ############################################################################### |
23 | 23 |
24 select STDERR; $| = 1; | 24 select STDERR; $| = 1; |
25 select STDOUT; $| = 1; | 25 select STDOUT; $| = 1; |
26 | 26 |
27 eval { | 27 my $t = Test::Nginx->new()->has(qw/http http_ssl sni socket_ssl_sni/) |
28 require Net::SSLeay; | |
29 Net::SSLeay::load_error_strings(); | |
30 Net::SSLeay::SSLeay_add_ssl_algorithms(); | |
31 Net::SSLeay::randomize(); | |
32 }; | |
33 plan(skip_all => 'Net::SSLeay not installed') if $@; | |
34 | |
35 eval { | |
36 my $ctx = Net::SSLeay::CTX_new() or die; | |
37 my $ssl = Net::SSLeay::new($ctx) or die; | |
38 Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die; | |
39 }; | |
40 plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@; | |
41 | |
42 my $t = Test::Nginx->new()->has(qw/http http_ssl sni/) | |
43 ->has_daemon('openssl')->plan(13); | 28 ->has_daemon('openssl')->plan(13); |
44 | 29 |
45 $t->write_file_expand('nginx.conf', <<'EOF'); | 30 $t->write_file_expand('nginx.conf', <<'EOF'); |
46 | 31 |
47 %%TEST_GLOBALS%% | 32 %%TEST_GLOBALS%% |
70 ssl_verify_client on; | 55 ssl_verify_client on; |
71 ssl_client_certificate 2.example.com.crt; | 56 ssl_client_certificate 2.example.com.crt; |
72 } | 57 } |
73 | 58 |
74 server { | 59 server { |
75 listen 127.0.0.1:8081 ssl; | 60 listen 127.0.0.1:8443 ssl; |
76 server_name on; | 61 server_name on; |
77 | 62 |
78 ssl_certificate_key 1.example.com.key; | 63 ssl_certificate_key 1.example.com.key; |
79 ssl_certificate 1.example.com.crt; | 64 ssl_certificate 1.example.com.crt; |
80 | 65 |
81 ssl_verify_client on; | 66 ssl_verify_client on; |
82 ssl_client_certificate 2.example.com.crt; | 67 ssl_client_certificate 2.example.com.crt; |
83 } | 68 } |
84 | 69 |
85 server { | 70 server { |
86 listen 127.0.0.1:8081 ssl; | 71 listen 127.0.0.1:8443 ssl; |
87 server_name optional; | 72 server_name optional; |
88 | 73 |
89 ssl_certificate_key 1.example.com.key; | 74 ssl_certificate_key 1.example.com.key; |
90 ssl_certificate 1.example.com.crt; | 75 ssl_certificate 1.example.com.crt; |
91 | 76 |
93 ssl_client_certificate 2.example.com.crt; | 78 ssl_client_certificate 2.example.com.crt; |
94 ssl_trusted_certificate 3.example.com.crt; | 79 ssl_trusted_certificate 3.example.com.crt; |
95 } | 80 } |
96 | 81 |
97 server { | 82 server { |
98 listen 127.0.0.1:8081 ssl; | 83 listen 127.0.0.1:8443 ssl; |
99 server_name off; | 84 server_name off; |
100 | 85 |
101 ssl_certificate_key 1.example.com.key; | 86 ssl_certificate_key 1.example.com.key; |
102 ssl_certificate 1.example.com.crt; | 87 ssl_certificate 1.example.com.crt; |
103 | 88 |
105 ssl_client_certificate 2.example.com.crt; | 90 ssl_client_certificate 2.example.com.crt; |
106 ssl_trusted_certificate 3.example.com.crt; | 91 ssl_trusted_certificate 3.example.com.crt; |
107 } | 92 } |
108 | 93 |
109 server { | 94 server { |
110 listen 127.0.0.1:8081 ssl; | 95 listen 127.0.0.1:8443 ssl; |
111 server_name optional.no.ca; | 96 server_name optional.no.ca; |
112 | 97 |
113 ssl_certificate_key 1.example.com.key; | 98 ssl_certificate_key 1.example.com.key; |
114 ssl_certificate 1.example.com.crt; | 99 ssl_certificate 1.example.com.crt; |
115 | 100 |
116 ssl_verify_client optional_no_ca; | 101 ssl_verify_client optional_no_ca; |
117 ssl_client_certificate 2.example.com.crt; | 102 ssl_client_certificate 2.example.com.crt; |
118 } | 103 } |
119 | 104 |
120 server { | 105 server { |
121 listen 127.0.0.1:8081 ssl; | 106 listen 127.0.0.1:8443 ssl; |
122 server_name no.context; | 107 server_name no.context; |
123 | 108 |
124 ssl_verify_client on; | 109 ssl_verify_client on; |
125 } | 110 } |
126 } | 111 } |
189 } | 174 } |
190 | 175 |
191 sub get { | 176 sub get { |
192 my ($sni, $cert, $host) = @_; | 177 my ($sni, $cert, $host) = @_; |
193 | 178 |
194 local $SIG{PIPE} = 'IGNORE'; | |
195 | |
196 $host = $sni if !defined $host; | 179 $host = $sni if !defined $host; |
197 | 180 |
198 my $s = IO::Socket::INET->new('127.0.0.1:' . port(8081)); | 181 my $s = http( |
199 my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!"); | 182 "GET /t HTTP/1.0" . CRLF . |
200 Net::SSLeay::set_cert_and_key($ctx, "$d/$cert.crt", "$d/$cert.key") | 183 "Host: $host" . CRLF . CRLF, |
201 or die if $cert; | 184 start => 1, |
202 my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!"); | 185 SSL => 1, |
203 Net::SSLeay::set_tlsext_host_name($ssl, $sni) == 1 or die; | 186 SSL_hostname => $sni, |
204 Net::SSLeay::set_fd($ssl, fileno($s)); | 187 $cert ? ( |
205 Net::SSLeay::connect($ssl) or die("ssl connect"); | 188 SSL_cert_file => "$d/$cert.crt", |
206 | 189 SSL_key_file => "$d/$cert.key" |
207 Net::SSLeay::write($ssl, 'GET /t HTTP/1.0' . CRLF); | 190 ) : () |
208 Net::SSLeay::write($ssl, "Host: $host" . CRLF . CRLF); | 191 ); |
209 my $buf = Net::SSLeay::read($ssl); | 192 |
210 log_in($buf); | 193 return http_end($s) unless wantarray(); |
211 return $buf unless wantarray(); | 194 |
212 | 195 # Note: this uses IO::Socket::SSL::_get_ssl_object() internal method. |
196 # While not exactly correct, it looks like there is no other way to | |
197 # obtain CA list with IO::Socket::SSL, and this seems to be good | |
198 # enough for tests. | |
199 | |
200 my $ssl = $s->_get_ssl_object(); | |
213 my $list = Net::SSLeay::get_client_CA_list($ssl); | 201 my $list = Net::SSLeay::get_client_CA_list($ssl); |
214 my @names; | 202 my @names; |
215 for my $i (0 .. Net::SSLeay::sk_X509_NAME_num($list) - 1) { | 203 for my $i (0 .. Net::SSLeay::sk_X509_NAME_num($list) - 1) { |
216 my $name = Net::SSLeay::sk_X509_NAME_value($list, $i); | 204 my $name = Net::SSLeay::sk_X509_NAME_value($list, $i); |
217 push @names, Net::SSLeay::X509_NAME_oneline($name); | 205 push @names, Net::SSLeay::X509_NAME_oneline($name); |