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);