Skip to content

Commit a28ff69

Browse files
committed
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.
1 parent 335c961 commit a28ff69

11 files changed

+293
-441
lines changed

access_log.t

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,11 @@ http_get('/varlog?logname=0');
161161
http_get('/varlog?logname=filename');
162162

163163
my $s = http('', start => 1);
164-
http_get('/addr', socket => $s);
165164
my $addr = $s->sockhost();
166165
my $port = $s->sockport();
167166
my $saddr = $s->peerhost();
168167
my $sport = $s->peerport();
168+
http_get('/addr', socket => $s);
169169

170170
http_get('/binary');
171171

lib/Test/Nginx.pm

+21-2
Original file line numberDiff line numberDiff line change
@@ -838,24 +838,41 @@ sub http($;%) {
838838
my $s = http_start($request, %extra);
839839

840840
return $s if $extra{start} or !defined $s;
841-
return http_end($s);
841+
return http_end($s, %extra);
842842
}
843843

844844
sub http_start($;%) {
845845
my ($request, %extra) = @_;
846846
my $s;
847847

848+
my $port = $extra{SSL} ? 8443 : 8080;
849+
848850
eval {
849851
local $SIG{ALRM} = sub { die "timeout\n" };
850852
local $SIG{PIPE} = sub { die "sigpipe\n" };
851853
alarm(8);
852854

853855
$s = $extra{socket} || IO::Socket::INET->new(
854856
Proto => 'tcp',
855-
PeerAddr => '127.0.0.1:' . port(8080)
857+
PeerAddr => '127.0.0.1:' . port($port),
858+
%extra
856859
)
857860
or die "Can't connect to nginx: $!\n";
858861

862+
if ($extra{SSL}) {
863+
require IO::Socket::SSL;
864+
IO::Socket::SSL->start_SSL(
865+
$s,
866+
SSL_verify_mode =>
867+
IO::Socket::SSL::SSL_VERIFY_NONE(),
868+
%extra
869+
)
870+
or die $IO::Socket::SSL::SSL_ERROR . "\n";
871+
872+
log_in("ssl cipher: " . $s->get_cipher());
873+
log_in("ssl cert: " . $s->peer_certificate('issuer'));
874+
}
875+
859876
log_out($request);
860877
$s->print($request);
861878

@@ -890,6 +907,8 @@ sub http_end($;%) {
890907
local $/;
891908
$reply = $s->getline();
892909

910+
$s->close();
911+
893912
alarm(0);
894913
};
895914
alarm(0);

ssl_certificate.t

+38-48
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,15 @@ use Socket qw/ CRLF /;
1717
BEGIN { use FindBin; chdir($FindBin::Bin); }
1818

1919
use lib 'lib';
20-
use Test::Nginx;
20+
use Test::Nginx qw/ :DEFAULT http_end /;
2121

2222
###############################################################################
2323

2424
select STDERR; $| = 1;
2525
select STDOUT; $| = 1;
2626

27-
eval {
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 geo openssl:1.0.2/)
27+
my $t = Test::Nginx->new()
28+
->has(qw/http http_ssl geo openssl:1.0.2 socket_ssl_sni/)
4329
->has_daemon('openssl');
4430

4531
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -67,6 +53,7 @@ http {
6753
}
6854
6955
add_header X-SSL $ssl_server_name:$ssl_session_reused;
56+
add_header X-SSL-Protocol $ssl_protocol;
7057
ssl_session_cache shared:SSL:1m;
7158
ssl_session_tickets on;
7259
@@ -177,60 +164,63 @@ like(get('password', 8083), qr/password/, 'ssl_password_file');
177164

178165
# session reuse
179166

180-
my ($s, $ssl) = get('default', 8080);
181-
my $ses = Net::SSLeay::get_session($ssl);
167+
my $s = session('default', 8080);
182168

183-
like(get('default', 8080, $ses), qr/default:r/, 'session reused');
169+
TODO: {
170+
local $TODO = 'no TLSv1.3 sessions, old Net::SSLeay'
171+
if $Net::SSLeay::VERSION < 1.88 && test_tls13();
172+
local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
173+
if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
174+
175+
like(get('default', 8080, $s), qr/default:r/, 'session reused');
184176

185177
TODO: {
186178
# ticket key name mismatch prevents session resumption
187179
local $TODO = 'not yet' unless $t->has_version('1.23.2');
188180

189-
like(get('default', 8081, $ses), qr/default:r/, 'session id context match');
181+
like(get('default', 8081, $s), qr/default:r/, 'session id context match');
190182

183+
}
191184
}
192185

193-
like(get('default', 8082, $ses), qr/default:\./, 'session id context distinct');
186+
like(get('default', 8082, $s), qr/default:\./, 'session id context distinct');
194187

195188
# errors
196189

197-
Net::SSLeay::ERR_clear_error();
198-
get_ssl_socket('nx', 8084);
199-
ok(Net::SSLeay::ERR_peek_error(), 'no certificate');
190+
ok(!get('nx', 8084), 'no certificate');
200191

201192
###############################################################################
202193

203194
sub get {
204-
my ($host, $port, $ctx) = @_;
205-
my ($s, $ssl) = get_ssl_socket($host, $port, $ctx) or return;
195+
my $s = get_socket(@_) || return;
196+
return http_end($s);
197+
}
206198

207-
local $SIG{PIPE} = 'IGNORE';
199+
sub cert {
200+
my $s = get_socket(@_) || return;
201+
return $s->dump_peer_certificate();
202+
}
208203

209-
Net::SSLeay::write($ssl, 'GET / HTTP/1.0' . CRLF . CRLF);
210-
my $r = Net::SSLeay::read($ssl);
211-
Net::SSLeay::shutdown($ssl);
212-
$s->close();
213-
return $r unless wantarray();
214-
return ($s, $ssl);
204+
sub session {
205+
my $s = get_socket(@_) || return;
206+
http_end($s);
207+
return $s;
215208
}
216209

217-
sub cert {
210+
sub get_socket {
218211
my ($host, $port, $ctx) = @_;
219-
my ($s, $ssl) = get_ssl_socket($host, $port, $ctx) or return;
220-
Net::SSLeay::dump_peer_certificate($ssl);
212+
return http_get(
213+
'/', start => 1, PeerAddr => '127.0.0.1:' . port($port),
214+
SSL => 1,
215+
SSL_hostname => $host,
216+
SSL_session_cache_size => 100,
217+
SSL_session_key => 1,
218+
SSL_reuse_ctx => $ctx
219+
);
221220
}
222221

223-
sub get_ssl_socket {
224-
my ($host, $port, $ses) = @_;
225-
226-
my $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
227-
my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
228-
my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
229-
Net::SSLeay::set_tlsext_host_name($ssl, $host);
230-
Net::SSLeay::set_session($ssl, $ses) if defined $ses;
231-
Net::SSLeay::set_fd($ssl, fileno($s));
232-
Net::SSLeay::connect($ssl);
233-
return ($s, $ssl);
222+
sub test_tls13 {
223+
return get('default', 8080) =~ /TLSv1.3/;
234224
}
235225

236226
###############################################################################

ssl_certificate_perl.t

+9-32
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,8 @@ use Test::Nginx;
2222
select STDERR; $| = 1;
2323
select STDOUT; $| = 1;
2424

25-
eval {
26-
require Net::SSLeay;
27-
Net::SSLeay::load_error_strings();
28-
Net::SSLeay::SSLeay_add_ssl_algorithms();
29-
Net::SSLeay::randomize();
30-
};
31-
plan(skip_all => 'Net::SSLeay not installed') if $@;
32-
33-
eval {
34-
my $ctx = Net::SSLeay::CTX_new() or die;
35-
my $ssl = Net::SSLeay::new($ctx) or die;
36-
Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
37-
};
38-
plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
39-
4025
my $t = Test::Nginx->new()
41-
->has(qw/http http_ssl perl openssl:1.0.2/)
26+
->has(qw/http http_ssl perl openssl:1.0.2 socket_ssl_sni/)
4227
->has_daemon('openssl');
4328

4429
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -66,7 +51,7 @@ http {
6651
';
6752
6853
server {
69-
listen 127.0.0.1:8080 ssl;
54+
listen 127.0.0.1:8443 ssl;
7055
server_name localhost;
7156
7257
ssl_certificate data:$pem;
@@ -98,27 +83,19 @@ $t->run()->plan(2);
9883

9984
###############################################################################
10085

101-
like(cert('one', 8080), qr/CN=one/, 'certificate');
102-
like(cert('two', 8080), qr/CN=two/, 'certificate 2');
86+
like(cert('one'), qr/CN=one/, 'certificate');
87+
like(cert('two'), qr/CN=two/, 'certificate 2');
10388

10489
###############################################################################
10590

10691
sub cert {
107-
my ($host, $port) = @_;
108-
my ($s, $ssl) = get_ssl_socket($host, $port) or return;
109-
Net::SSLeay::dump_peer_certificate($ssl);
92+
my $s = get_socket(@_) || return;
93+
return $s->dump_peer_certificate();
11094
}
11195

112-
sub get_ssl_socket {
113-
my ($host, $port) = @_;
114-
115-
my $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
116-
my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
117-
my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
118-
Net::SSLeay::set_tlsext_host_name($ssl, $host);
119-
Net::SSLeay::set_fd($ssl, fileno($s));
120-
Net::SSLeay::connect($ssl) or die("ssl connect");
121-
return ($s, $ssl);
96+
sub get_socket {
97+
my $host = shift;
98+
return http_get('/', start => 1, SSL => 1, SSL_hostname => $host);
12299
}
123100

124101
###############################################################################

0 commit comments

Comments
 (0)