comparison mail_ssl.t @ 1861:7b7b64569f55

Tests: reworked mail SSL tests to use IO::Socket::SSL. Relevant infrastructure is provided in Test::Nginx::IMAP (and also POP3 and SMTP for completeness). This also ensures that SSL handshake and various read operations are guarded with timeouts.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 18 May 2023 18:07:08 +0300
parents 58951cf933e1
children 7a27a4e4fdae
comparison
equal deleted inserted replaced
1860:58951cf933e1 1861:7b7b64569f55
25 select STDERR; $| = 1; 25 select STDERR; $| = 1;
26 select STDOUT; $| = 1; 26 select STDOUT; $| = 1;
27 27
28 local $SIG{PIPE} = 'IGNORE'; 28 local $SIG{PIPE} = 'IGNORE';
29 29
30 eval { 30 my $t = Test::Nginx->new()->has(qw/mail mail_ssl imap pop3 smtp socket_ssl/)
31 require Net::SSLeay; 31 ->has_daemon('openssl')->plan(19);
32 Net::SSLeay::load_error_strings();
33 Net::SSLeay::SSLeay_add_ssl_algorithms();
34 Net::SSLeay::randomize();
35 };
36 plan(skip_all => 'Net::SSLeay not installed') if $@;
37
38 eval { exists &Net::SSLeay::P_alpn_selected or die; };
39 plan(skip_all => 'Net::SSLeay with OpenSSL ALPN support required') if $@;
40
41 my $t = Test::Nginx->new()->has(qw/mail mail_ssl imap pop3 smtp/)
42 ->has_daemon('openssl')->plan(18);
43 32
44 $t->write_file_expand('nginx.conf', <<'EOF'); 33 $t->write_file_expand('nginx.conf', <<'EOF');
45 34
46 %%TEST_GLOBALS%% 35 %%TEST_GLOBALS%%
47 36
141 . "-key $d/$name.key -passin pass:localhost" 130 . "-key $d/$name.key -passin pass:localhost"
142 . ">>$d/openssl.out 2>&1") == 0 131 . ">>$d/openssl.out 2>&1") == 0
143 or die "Can't create certificate for $name: $!\n"; 132 or die "Can't create certificate for $name: $!\n";
144 } 133 }
145 134
146 my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
147 $t->write_file('password', 'localhost'); 135 $t->write_file('password', 'localhost');
148 136
149 open OLDERR, ">&", \*STDERR; close STDERR; 137 open OLDERR, ">&", \*STDERR; close STDERR;
150 $t->run(); 138 $t->run();
151 open STDERR, ">&", \*OLDERR; 139 open STDERR, ">&", \*OLDERR;
162 $s->send('1 AUTHENTICATE LOGIN'); 150 $s->send('1 AUTHENTICATE LOGIN');
163 $s->check(qr/\+ VXNlcm5hbWU6/, 'login'); 151 $s->check(qr/\+ VXNlcm5hbWU6/, 'login');
164 152
165 # ssl_certificate inheritance 153 # ssl_certificate inheritance
166 154
167 ($s, $ssl) = get_ssl_socket(8145); 155 $s = Test::Nginx::IMAP->new(PeerAddr => '127.0.0.1:' . port(8145), SSL => 1);
168 like(Net::SSLeay::dump_peer_certificate($ssl), qr/CN=localhost/, 'CN'); 156 $s->ok('greeting ssl');
169 157
170 ($s, $ssl) = get_ssl_socket(8148); 158 like($s->socket()->dump_peer_certificate(), qr/CN=localhost/, 'CN');
171 like(Net::SSLeay::dump_peer_certificate($ssl), qr/CN=inherits/, 'CN inner'); 159
160 $s = Test::Nginx::IMAP->new(PeerAddr => '127.0.0.1:' . port(8148), SSL => 1);
161 $s->read();
162
163 like($s->socket()->dump_peer_certificate(), qr/CN=inherits/, 'CN inner');
172 164
173 # alpn 165 # alpn
174 166
175 ok(get_ssl_socket(8148, ['imap']), 'alpn'); 167 $s = Test::Nginx::IMAP->new(
168 PeerAddr => '127.0.0.1:' . port(8148),
169 SSL => 1,
170 SSL_alpn_protocols => [ 'imap' ]
171 );
172 $s->ok('alpn');
176 173
177 SKIP: { 174 SKIP: {
178 skip 'LibreSSL too old', 1 175 skip 'LibreSSL too old', 1
179 if $t->has_module('LibreSSL') 176 if $t->has_module('LibreSSL')
180 and not $t->has_feature('libressl:3.4.0'); 177 and not $t->has_feature('libressl:3.4.0');
182 if $t->has_module('OpenSSL') 179 if $t->has_module('OpenSSL')
183 and not $t->has_feature('openssl:1.1.0'); 180 and not $t->has_feature('openssl:1.1.0');
184 181
185 TODO: { 182 TODO: {
186 local $TODO = 'not yet' unless $t->has_version('1.21.4'); 183 local $TODO = 'not yet' unless $t->has_version('1.21.4');
187 184 local $TODO = 'no ALPN support in IO::Socket::SSL'
188 ok(!get_ssl_socket(8148, ['unknown']), 'alpn rejected'); 185 unless $t->has_feature('socket_ssl_alpn');
186
187 $s = Test::Nginx::IMAP->new(
188 PeerAddr => '127.0.0.1:' . port(8148),
189 SSL => 1,
190 SSL_alpn_protocols => [ 'unknown' ]
191 );
192 ok(!$s->read(), 'alpn rejected');
189 193
190 } 194 }
191 195
192 } 196 }
193 197
268 272
269 $s->send('STARTTLS'); 273 $s->send('STARTTLS');
270 $s->ok('smtp starttls only'); 274 $s->ok('smtp starttls only');
271 275
272 ############################################################################### 276 ###############################################################################
273
274 sub get_ssl_socket {
275 my ($port, $alpn) = @_;
276
277 my $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
278 my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
279 Net::SSLeay::set_alpn_protos($ssl, $alpn) if defined $alpn;
280 Net::SSLeay::set_fd($ssl, fileno($s));
281 Net::SSLeay::connect($ssl) == 1 or return;
282 return ($s, $ssl);
283 }
284
285 ###############################################################################