[PATCH 10 of 11] Tests: reworked http SSL tests to use IO::Socket::SSL
Maxim Dounin
mdounin at mdounin.ru
Mon Apr 17 03:31:34 UTC 2023
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1681702264 -10800
# Mon Apr 17 06:31:04 2023 +0300
# Node ID 2aaba5bbc0366bffe1f468105b1185cd48efbc93
# Parent 90913cb36b512c45cd9a171cbb4320b12ff24b48
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.
diff --git a/access_log.t b/access_log.t
--- a/access_log.t
+++ b/access_log.t
@@ -161,11 +161,11 @@ http_get('/varlog?logname=0');
http_get('/varlog?logname=filename');
my $s = http('', start => 1);
-http_get('/addr', socket => $s);
my $addr = $s->sockhost();
my $port = $s->sockport();
my $saddr = $s->peerhost();
my $sport = $s->peerport();
+http_get('/addr', socket => $s);
http_get('/binary');
diff --git a/lib/Test/Nginx.pm b/lib/Test/Nginx.pm
--- a/lib/Test/Nginx.pm
+++ b/lib/Test/Nginx.pm
@@ -838,13 +838,15 @@ sub http($;%) {
my $s = http_start($request, %extra);
return $s if $extra{start} or !defined $s;
- return http_end($s);
+ return http_end($s, %extra);
}
sub http_start($;%) {
my ($request, %extra) = @_;
my $s;
+ my $port = $extra{SSL} ? 8443 : 8080;
+
eval {
local $SIG{ALRM} = sub { die "timeout\n" };
local $SIG{PIPE} = sub { die "sigpipe\n" };
@@ -852,10 +854,25 @@ sub http_start($;%) {
$s = $extra{socket} || IO::Socket::INET->new(
Proto => 'tcp',
- PeerAddr => '127.0.0.1:' . port(8080)
+ PeerAddr => '127.0.0.1:' . port($port),
+ %extra
)
or die "Can't connect to nginx: $!\n";
+ if ($extra{SSL}) {
+ require IO::Socket::SSL;
+ IO::Socket::SSL->start_SSL(
+ $s,
+ SSL_verify_mode =>
+ IO::Socket::SSL::SSL_VERIFY_NONE(),
+ %extra
+ )
+ or die $IO::Socket::SSL::SSL_ERROR . "\n";
+
+ log_in("ssl cipher: " . $s->get_cipher());
+ log_in("ssl cert: " . $s->peer_certificate('issuer'));
+ }
+
log_out($request);
$s->print($request);
@@ -879,7 +896,7 @@ sub http_start($;%) {
}
sub http_end($;%) {
- my ($s) = @_;
+ my ($s, %extra) = @_;
my $reply;
eval {
@@ -890,6 +907,8 @@ sub http_end($;%) {
local $/;
$reply = $s->getline();
+ $s->close();
+
alarm(0);
};
alarm(0);
diff --git a/ssl_certificate.t b/ssl_certificate.t
--- a/ssl_certificate.t
+++ b/ssl_certificate.t
@@ -17,29 +17,15 @@ use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
-plan(skip_all => 'Net::SSLeay not installed') if $@;
-
-eval {
- my $ctx = Net::SSLeay::CTX_new() or die;
- my $ssl = Net::SSLeay::new($ctx) or die;
- Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
-};
-plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl geo openssl:1.0.2/)
+my $t = Test::Nginx->new()
+ ->has(qw/http http_ssl geo openssl:1.0.2 socket_ssl_sni/)
->has_daemon('openssl');
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -67,6 +53,7 @@ http {
}
add_header X-SSL $ssl_server_name:$ssl_session_reused;
+ add_header X-SSL-Protocol $ssl_protocol;
ssl_session_cache shared:SSL:1m;
ssl_session_tickets on;
@@ -177,60 +164,63 @@ like(get('password', 8083), qr/password/
# session reuse
-my ($s, $ssl) = get('default', 8080);
-my $ses = Net::SSLeay::get_session($ssl);
-
-like(get('default', 8080, $ses), qr/default:r/, 'session reused');
+my $s = session('default', 8080);
TODO: {
-# ticket key name mismatch prevents session resumption
+local $TODO = 'no TLSv1.3 sessions, old Net::SSLeay'
+ if $Net::SSLeay::VERSION < 1.88 && test_tls13();
+local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
+ if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
+
+like(get('default', 8080, $s), qr/default:r/, 'session reused');
+
+TODO: {
+# automatic ticket ticket key name mismatch prevents session resumption
local $TODO = 'not yet' unless $t->has_version('1.23.2');
-like(get('default', 8081, $ses), qr/default:r/, 'session id context match');
+like(get('default', 8081, $s), qr/default:r/, 'session id context match');
}
+}
-like(get('default', 8082, $ses), qr/default:\./, 'session id context distinct');
+like(get('default', 8082, $s), qr/default:\./, 'session id context distinct');
# errors
-Net::SSLeay::ERR_clear_error();
-get_ssl_socket('nx', 8084);
-ok(Net::SSLeay::ERR_peek_error(), 'no certificate');
+ok(!get('nx', 8084), 'no certificate');
###############################################################################
sub get {
- my ($host, $port, $ctx) = @_;
- my ($s, $ssl) = get_ssl_socket($host, $port, $ctx) or return;
-
- local $SIG{PIPE} = 'IGNORE';
-
- Net::SSLeay::write($ssl, 'GET / HTTP/1.0' . CRLF . CRLF);
- my $r = Net::SSLeay::read($ssl);
- Net::SSLeay::shutdown($ssl);
- $s->close();
- return $r unless wantarray();
- return ($s, $ssl);
+ my $s = get_socket(@_) || return;
+ return http_end($s);
}
sub cert {
- my ($host, $port, $ctx) = @_;
- my ($s, $ssl) = get_ssl_socket($host, $port, $ctx) or return;
- Net::SSLeay::dump_peer_certificate($ssl);
+ my $s = get_socket(@_) || return;
+ return $s->dump_peer_certificate();
+}
+
+sub session {
+ my $s = get_socket(@_) || return;
+ http_end($s);
+ return $s;
}
-sub get_ssl_socket {
- my ($host, $port, $ses) = @_;
+sub get_socket {
+ my ($host, $port, $ctx) = @_;
+ return http_get(
+ '/', start => 1, PeerAddr => '127.0.0.1:' . port($port),
+ SSL => 1,
+ SSL_hostname => $host,
+ SSL_session_cache_size => 100,
+ SSL_session_key => 1,
+ SSL_reuse_ctx => $ctx
+ );
+}
- my $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_tlsext_host_name($ssl, $host);
- Net::SSLeay::set_session($ssl, $ses) if defined $ses;
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl);
- return ($s, $ssl);
+sub test_tls13 {
+ return get('default', 8080) =~ /TLSv1.3/;
}
###############################################################################
diff --git a/ssl_certificate_perl.t b/ssl_certificate_perl.t
--- a/ssl_certificate_perl.t
+++ b/ssl_certificate_perl.t
@@ -22,23 +22,8 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
-plan(skip_all => 'Net::SSLeay not installed') if $@;
-
-eval {
- my $ctx = Net::SSLeay::CTX_new() or die;
- my $ssl = Net::SSLeay::new($ctx) or die;
- Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
-};
-plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
-
my $t = Test::Nginx->new()
- ->has(qw/http http_ssl perl openssl:1.0.2/)
+ ->has(qw/http http_ssl perl openssl:1.0.2 socket_ssl_sni/)
->has_daemon('openssl');
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -66,7 +51,7 @@ http {
';
server {
- listen 127.0.0.1:8080 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name localhost;
ssl_certificate data:$pem;
@@ -98,27 +83,19 @@ foreach my $name ('one', 'two') {
###############################################################################
-like(cert('one', 8080), qr/CN=one/, 'certificate');
-like(cert('two', 8080), qr/CN=two/, 'certificate 2');
+like(cert('one'), qr/CN=one/, 'certificate');
+like(cert('two'), qr/CN=two/, 'certificate 2');
###############################################################################
sub cert {
- my ($host, $port) = @_;
- my ($s, $ssl) = get_ssl_socket($host, $port) or return;
- Net::SSLeay::dump_peer_certificate($ssl);
+ my $s = get_socket(@_) || return;
+ return $s->dump_peer_certificate();
}
-sub get_ssl_socket {
- my ($host, $port) = @_;
-
- my $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_tlsext_host_name($ssl, $host);
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
- return ($s, $ssl);
+sub get_socket {
+ my $host = shift;
+ return http_get('/', start => 1, SSL => 1, SSL_hostname => $host);
}
###############################################################################
diff --git a/ssl_certificates.t b/ssl_certificates.t
--- a/ssl_certificates.t
+++ b/ssl_certificates.t
@@ -22,16 +22,8 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
- Net::SSLeay::SSLeay();
-};
-plan(skip_all => 'Net::SSLeay not installed or too old') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl');
+my $t = Test::Nginx->new()->has(qw/http http_ssl socket_ssl/)
+ ->has_daemon('openssl');
plan(skip_all => 'no multiple certificates') if $t->has_module('BoringSSL');
@@ -51,8 +43,10 @@ http {
ssl_certificate rsa.crt;
ssl_ciphers DEFAULT:ECCdraft;
+ add_header X-SSL-Protocol $ssl_protocol;
+
server {
- listen 127.0.0.1:8080 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name localhost;
ssl_certificate_key ec.key;
@@ -91,65 +85,54 @@ foreach my $name ('ec', 'rsa') {
or die "Can't create certificate for $name: $!\n";
}
+$t->write_file('index.html', '');
+
$t->run()->plan(2);
###############################################################################
-like(get_cert('RSA'), qr/CN=rsa/, 'ssl cert RSA');
-like(get_cert('ECDSA'), qr/CN=ec/, 'ssl cert ECDSA');
+TODO: {
+local $TODO = 'broken TLSv1.3 sigalgs in LibreSSL'
+ if $t->has_module('LibreSSL') && test_tls13();
+
+like(cert('RSA'), qr/CN=rsa/, 'ssl cert RSA');
+
+}
+
+like(cert('ECDSA'), qr/CN=ec/, 'ssl cert ECDSA');
###############################################################################
-sub get_version {
- my ($s, $ssl) = get_ssl_socket();
- return Net::SSLeay::version($ssl);
+sub test_tls13 {
+ return http_get('/', SSL => 1) =~ /TLSv1.3/;
}
-sub get_cert {
- my ($type) = @_;
- $type = 'PSS' if $type eq 'RSA' && get_version() > 0x0303;
- my ($s, $ssl) = get_ssl_socket($type);
- my $cipher = Net::SSLeay::get_cipher($ssl);
- Test::Nginx::log_core('||', "cipher: $cipher");
- return Net::SSLeay::dump_peer_certificate($ssl);
+sub cert {
+ my $s = get_socket(@_) || return;
+ return $s->dump_peer_certificate();
}
-sub get_ssl_socket {
+sub get_socket {
my ($type) = @_;
- my $s;
-
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- local $SIG{PIPE} = sub { die "sigpipe\n" };
- alarm(8);
- $s = IO::Socket::INET->new('127.0.0.1:' . port(8080));
- alarm(0);
- };
- alarm(0);
-
- if ($@) {
- log_in("died: $@");
- return undef;
- }
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
-
- if (defined $type) {
+ my $ctx_cb = sub {
+ my $ctx = shift;
+ return unless defined $type;
my $ssleay = Net::SSLeay::SSLeay();
- if ($ssleay < 0x1000200f || $ssleay == 0x20000000) {
- Net::SSLeay::CTX_set_cipher_list($ctx, $type)
- or die("Failed to set cipher list");
- } else {
- # SSL_CTRL_SET_SIGALGS_LIST
- Net::SSLeay::CTX_ctrl($ctx, 98, 0, $type . '+SHA256')
- or die("Failed to set sigalgs");
- }
- }
+ return if ($ssleay < 0x1000200f || $ssleay == 0x20000000);
+ my $sigalgs = 'RSA+SHA256:PSS+SHA256';
+ $sigalgs = $type . '+SHA256' unless $type eq 'RSA';
+ # SSL_CTRL_SET_SIGALGS_LIST
+ Net::SSLeay::CTX_ctrl($ctx, 98, 0, $sigalgs)
+ or die("Failed to set sigalgs");
+ };
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
- return ($s, $ssl);
+ return http_get(
+ '/', start => 1,
+ SSL => 1,
+ SSL_cipher_list => $type,
+ SSL_create_ctx_callback => $ctx_cb
+ );
}
###############################################################################
diff --git a/ssl_conf_command.t b/ssl_conf_command.t
--- a/ssl_conf_command.t
+++ b/ssl_conf_command.t
@@ -15,22 +15,15 @@ use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
-plan(skip_all => 'Net::SSLeay not installed') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl openssl:1.0.2/)
+my $t = Test::Nginx->new()
+ ->has(qw/http http_ssl openssl:1.0.2 socket_ssl_reused/)
->has_daemon('openssl');
plan(skip_all => 'no ssl_conf_command') if $t->has_module('BoringSSL');
@@ -91,32 +84,32 @@ foreach my $name ('localhost', 'override
###############################################################################
-my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
+my $s;
-my ($s, $ssl) = get_ssl_socket();
-like(Net::SSLeay::dump_peer_certificate($ssl), qr/CN=override/, 'Certificate');
+$s = http_get(
+ '/', start => 1,
+ SSL => 1,
+ SSL_session_cache_size => 100
+);
+
+like($s->dump_peer_certificate(), qr/CN=override/, 'Certificate');
+http_end($s);
-my $ses = Net::SSLeay::get_session($ssl);
-($s, $ssl) = get_ssl_socket(ses => $ses);
-ok(Net::SSLeay::session_reused($ssl), 'SessionTicket');
+$s = http_get(
+ '/', start => 1,
+ SSL => 1,
+ SSL_reuse_ctx => $s
+);
+
+ok($s->get_session_reused(), 'SessionTicket');
-($s, $ssl) = get_ssl_socket(ciphers =>
- 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384');
-is(Net::SSLeay::get_cipher($ssl),
- 'ECDHE-RSA-AES128-GCM-SHA256', 'ServerPreference');
+$s = http_get(
+ '/', start => 1,
+ SSL => 1,
+ SSL_cipher_list =>
+ 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
+);
+
+is($s->get_cipher(), 'ECDHE-RSA-AES128-GCM-SHA256', 'ServerPreference');
###############################################################################
-
-sub get_ssl_socket {
- my (%extra) = @_;
-
- my $s = IO::Socket::INET->new('127.0.0.1:' . port(8443));
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_session($ssl, $extra{ses}) if $extra{ses};
- Net::SSLeay::set_cipher_list($ssl, $extra{ciphers}) if $extra{ciphers};
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
- return ($s, $ssl);
-}
-
-###############################################################################
diff --git a/ssl_ocsp.t b/ssl_ocsp.t
--- a/ssl_ocsp.t
+++ b/ssl_ocsp.t
@@ -17,31 +17,15 @@ use MIME::Base64 qw/ decode_base64 /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
- Net::SSLeay::SSLeay();
- defined &Net::SSLeay::set_tlsext_status_type or die;
-};
-plan(skip_all => 'Net::SSLeay not installed or too old') if $@;
-
-eval {
- my $ctx = Net::SSLeay::CTX_new() or die;
- my $ssl = Net::SSLeay::new($ctx) or die;
- Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
-};
-plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl sni/)->has_daemon('openssl');
+my $t = Test::Nginx->new()->has(qw/http http_ssl sni socket_ssl_sni/)
+ ->has_daemon('openssl');
plan(skip_all => 'no OCSP support in BoringSSL')
if $t->has_module('BoringSSL');
@@ -70,6 +54,7 @@ http {
ssl_session_tickets off;
add_header X-Verify x${ssl_client_verify}:${ssl_session_reused}x always;
+ add_header X-SSL-Protocol $ssl_protocol always;
server {
listen 127.0.0.1:8443 ssl;
@@ -283,8 +268,6 @@ foreach my $name ('rsa') {
$t->waitforsocket("127.0.0.1:" . port(8081));
$t->waitforsocket("127.0.0.1:" . port(8082));
-my $version = get_version();
-
###############################################################################
like(get('end'), qr/200 OK.*SUCCESS/s, 'ocsp leaf');
@@ -366,14 +349,17 @@ system("openssl ocsp -index $d/certindex
like(get('ec-end'), qr/200 OK.*SUCCESS/s, 'ocsp ecdsa');
-my ($s, $ssl) = get('ec-end');
-my $ses = Net::SSLeay::get_session($ssl);
+my $s = session('ec-end');
TODO: {
+local $TODO = 'no TLSv1.3 sessions, old Net::SSLeay'
+ if $Net::SSLeay::VERSION < 1.88 && test_tls13();
+local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
+ if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
local $TODO = 'no TLSv1.3 sessions in LibreSSL'
- if $t->has_module('LibreSSL') and $version > 0x303;
+ if $t->has_module('LibreSSL') && test_tls13();
-like(get('ec-end', ses => $ses),
+like(get('ec-end', ses => $s),
qr/200 OK.*SUCCESS:r/s, 'session reused');
}
@@ -398,10 +384,14 @@ system("openssl ocsp -index $d/certindex
# reusing session with revoked certificate
TODO: {
+local $TODO = 'no TLSv1.3 sessions, old Net::SSLeay'
+ if $Net::SSLeay::VERSION < 1.88 && test_tls13();
+local $TODO = 'no TLSv1.3 sessions, old IO::Socket::SSL'
+ if $IO::Socket::SSL::VERSION < 2.061 && test_tls13();
local $TODO = 'no TLSv1.3 sessions in LibreSSL'
- if $t->has_module('LibreSSL') and $version > 0x303;
+ if $t->has_module('LibreSSL') && test_tls13();
-like(get('ec-end', ses => $ses),
+like(get('ec-end', ses => $s),
qr/400 Bad.*FAILED:certificate revoked:r/s, 'session reused - revoked');
}
@@ -417,57 +407,38 @@ like(`grep -F '[crit]' ${\($t->testdir()
###############################################################################
sub get {
- my ($cert, %extra) = @_;
- my ($s, $ssl) = get_ssl_socket($cert, %extra);
- my $cipher = Net::SSLeay::get_cipher($ssl);
- Test::Nginx::log_core('||', "cipher: $cipher");
- my $host = $extra{sni} ? $extra{sni} : 'localhost';
- local $SIG{PIPE} = 'IGNORE';
- log_out("GET /serial HTTP/1.0\nHost: $host\n\n");
- Net::SSLeay::write($ssl, "GET /serial HTTP/1.0\nHost: $host\n\n");
- my $r = Net::SSLeay::read($ssl);
- log_in($r);
- $s->close();
- return $r unless wantarray();
- return ($s, $ssl);
+ my $s = get_socket(@_) || return;
+ return http_end($s);
}
-sub get_ssl_socket {
+sub session {
+ my $s = get_socket(@_) || return;
+ http_end($s);
+ return $s;
+}
+
+sub get_socket {
my ($cert, %extra) = @_;
my $ses = $extra{ses};
- my $sni = $extra{sni};
+ my $sni = $extra{sni} || 'localhost';
my $port = $extra{port} || 8443;
- my $s;
-
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- local $SIG{PIPE} = sub { die "sigpipe\n" };
- alarm(8);
- $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
- alarm(0);
- };
- alarm(0);
- if ($@) {
- log_in("died: $@");
- return undef;
- }
-
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
-
- Net::SSLeay::set_cert_and_key($ctx, "$d/$cert.crt", "$d/$cert.key")
- or die if $cert;
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_session($ssl, $ses) if defined $ses;
- Net::SSLeay::set_tlsext_host_name($ssl, $sni) if $sni;
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
- return ($s, $ssl);
+ return http(
+ "GET /serial HTTP/1.0\nHost: $sni\n\n",
+ start => 1, PeerAddr => '127.0.0.1:' . port($port),
+ SSL => 1,
+ SSL_hostname => $sni,
+ SSL_session_cache_size => 100,
+ SSL_reuse_ctx => $ses,
+ $cert ? (
+ SSL_cert_file => "$d/$cert.crt",
+ SSL_key_file => "$d/$cert.key"
+ ) : ()
+ );
}
-sub get_version {
- my ($s, $ssl) = get_ssl_socket();
- return Net::SSLeay::version($ssl);
+sub test_tls13 {
+ return http_get('/', SSL => 1) =~ /TLSv1.3/;
}
###############################################################################
diff --git a/ssl_session_ticket_key.t b/ssl_session_ticket_key.t
--- a/ssl_session_ticket_key.t
+++ b/ssl_session_ticket_key.t
@@ -15,23 +15,19 @@ use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay; die if $Net::SSLeay::VERSION < 1.86;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
+eval { require Net::SSLeay; die if $Net::SSLeay::VERSION < 1.86; };
plan(skip_all => 'Net::SSLeay version => 1.86 required') if $@;
-my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl')
- ->plan(2)->write_file_expand('nginx.conf', <<'EOF');
+my $t = Test::Nginx->new()->has(qw/http http_ssl socket_ssl/)
+ ->has_daemon('openssl')->plan(2)
+ ->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
@@ -47,8 +43,10 @@ http {
ssl_certificate_key localhost.key;
ssl_certificate localhost.crt;
+ add_header X-SSL-Protocol $ssl_protocol;
+
server {
- listen 127.0.0.1:8080 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name localhost;
ssl_session_cache shared:SSL:1m;
@@ -76,6 +74,8 @@ foreach my $name ('localhost') {
or die "Can't create certificate for $name: $!\n";
}
+$t->write_file('index.html', '');
+
$t->run();
###############################################################################
@@ -105,8 +105,7 @@ cmp_ok(get_ticket_key_name(), 'ne', $key
###############################################################################
sub get_ticket_key_name {
- my $ses = get_ssl_session();
- my $asn = Net::SSLeay::i2d_SSL_SESSION($ses);
+ my $asn = get_ssl_session();
my $any = qr/[\x00-\xff]/;
next:
# tag(10) | len{2} | OCTETSTRING(4) | len{2} | ticket(key_name|..)
@@ -119,29 +118,25 @@ next:
}
sub get_ssl_session {
- my ($s, $ssl) = get_ssl_socket();
+ my $cache = IO::Socket::SSL::Session_Cache->new(100);
- Net::SSLeay::write($ssl, <<EOF);
-GET / HTTP/1.0
-Host: localhost
+ my $s = http_get(
+ '/', start => 1,
+ SSL => 1,
+ SSL_session_cache => $cache,
+ SSL_session_key => 1
+ );
-EOF
- Net::SSLeay::read($ssl);
- Net::SSLeay::get_session($ssl);
+ return unless $s;
+ http_end($s);
+
+ my $sess = $cache->get_session(1);
+ return '' unless defined $sess;
+ return Net::SSLeay::i2d_SSL_SESSION($sess);
}
sub test_tls13 {
- my ($s, $ssl) = get_ssl_socket();
- return (Net::SSLeay::version($ssl) > 0x303);
-}
-
-sub get_ssl_socket {
- my $s = IO::Socket::INET->new('127.0.0.1:' . port(8080));
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
- return ($s, $ssl);
+ return http_get('/', SSL => 1) =~ /TLSv1.3/;
}
###############################################################################
diff --git a/ssl_sni_reneg.t b/ssl_sni_reneg.t
--- a/ssl_sni_reneg.t
+++ b/ssl_sni_reneg.t
@@ -17,29 +17,15 @@ use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
-plan(skip_all => 'Net::SSLeay not installed') if $@;
-
-eval {
- my $ctx = Net::SSLeay::CTX_new() or die;
- my $ssl = Net::SSLeay::new($ctx) or die;
- Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
-};
-plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl');
+my $t = Test::Nginx->new()->has(qw/http http_ssl socket_ssl_sni/)
+ ->has_daemon('openssl')->plan(8);
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -58,15 +44,15 @@ http {
ssl_protocols TLSv1.2;
server {
- listen 127.0.0.1:8080 ssl;
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
+ listen 127.0.0.1:8444 ssl;
server_name localhost;
location / { }
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8444 ssl;
server_name localhost2;
location / { }
@@ -94,11 +80,12 @@ foreach my $name ('localhost') {
}
$t->run();
-$t->plan(8);
###############################################################################
-my ($s, $ssl) = get_ssl_socket(8080);
+my ($s, $ssl);
+
+$s = http('', start => 1, SSL => 1);
ok($s, 'connection');
SKIP: {
@@ -106,20 +93,26 @@ skip 'connection failed', 3 unless $s;
local $SIG{PIPE} = 'IGNORE';
-Net::SSLeay::write($ssl, 'GET / HTTP/1.0' . CRLF);
+$s->print('GET / HTTP/1.0' . CRLF);
+# Note: this uses IO::Socket::SSL::_get_ssl_object() internal method.
+# While not exactly correct, it looks like there is no other way to
+# trigger renegotiation with IO::Socket::SSL, and this seems to be
+# good enough for tests.
+
+$ssl = $s->_get_ssl_object();
ok(Net::SSLeay::renegotiate($ssl), 'renegotiation');
ok(Net::SSLeay::set_tlsext_host_name($ssl, 'localhost'), 'SNI');
-Net::SSLeay::write($ssl, 'Host: localhost' . CRLF . CRLF);
+$s->print('Host: localhost' . CRLF . CRLF);
-ok(!Net::SSLeay::read($ssl), 'response');
+ok(!http_end($s), 'response');
}
# virtual servers
-($s, $ssl) = get_ssl_socket(8081);
+$s = http('', start => 1, PeerAddr => '127.0.0.1:' . port(8444), SSL => 1);
ok($s, 'connection 2');
SKIP: {
@@ -127,44 +120,21 @@ skip 'connection failed', 3 unless $s;
local $SIG{PIPE} = 'IGNORE';
-Net::SSLeay::write($ssl, 'GET / HTTP/1.0' . CRLF);
+$s->print('GET / HTTP/1.0' . CRLF);
+# Note: this uses IO::Socket::SSL::_get_ssl_object() internal method.
+# While not exactly correct, it looks like there is no other way to
+# trigger renegotiation with IO::Socket::SSL, and this seems to be
+# good enough for tests.
+
+$ssl = $s->_get_ssl_object();
ok(Net::SSLeay::renegotiate($ssl), 'renegotiation');
ok(Net::SSLeay::set_tlsext_host_name($ssl, 'localhost'), 'SNI');
-Net::SSLeay::write($ssl, 'Host: localhost' . CRLF . CRLF);
+$s->print('Host: localhost' . CRLF . CRLF);
-ok(!Net::SSLeay::read($ssl), 'virtual servers');
+ok(!http_end($s), 'virtual servers');
}
###############################################################################
-
-sub get_ssl_socket {
- my ($port) = @_;
- my $s;
-
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- local $SIG{PIPE} = sub { die "sigpipe\n" };
- alarm(8);
- $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
- alarm(0);
- };
- alarm(0);
-
- if ($@) {
- log_in("died: $@");
- return undef;
- }
-
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::set_tlsext_host_name($ssl, 'localhost');
- Net::SSLeay::connect($ssl) or die("ssl connect");
-
- return ($s, $ssl);
-}
-
-###############################################################################
diff --git a/ssl_stapling.t b/ssl_stapling.t
--- a/ssl_stapling.t
+++ b/ssl_stapling.t
@@ -24,17 +24,13 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
- Net::SSLeay::SSLeay();
- defined &Net::SSLeay::set_tlsext_status_type or die;
-};
-plan(skip_all => 'Net::SSLeay not installed or too old') if $@;
+my $t = Test::Nginx->new()->has(qw/http http_ssl socket_ssl/)
+ ->has_daemon('openssl');
-my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl');
+eval { defined &Net::SSLeay::set_tlsext_status_type or die; };
+plan(skip_all => 'Net::SSLeay too old') if $@;
+eval { defined &IO::Socket::SSL::SSL_OCSP_TRY_STAPLE or die; };
+plan(skip_all => 'IO::Socket::SSL too old') if $@;
plan(skip_all => 'no OCSP stapling') if $t->has_module('BoringSSL');
@@ -246,8 +242,6 @@ system("openssl ocsp -index $d/certindex
###############################################################################
-my $version = get_version();
-
staple(8443, 'RSA');
staple(8443, 'ECDSA');
staple(8444, 'RSA');
@@ -262,7 +256,7 @@ ok(!staple(8443, 'RSA'), 'staple revoked
TODO: {
local $TODO = 'broken TLSv1.3 sigalgs in LibreSSL'
- if $t->has_module('LibreSSL') && $version > 0x303;
+ if $t->has_module('LibreSSL') && test_tls13();
ok(staple(8443, 'ECDSA'), 'staple success');
@@ -272,7 +266,7 @@ ok(!staple(8444, 'RSA'), 'responder revo
TODO: {
local $TODO = 'broken TLSv1.3 sigalgs in LibreSSL'
- if $t->has_module('LibreSSL') && $version > 0x303;
+ if $t->has_module('LibreSSL') && test_tls13();
ok(staple(8444, 'ECDSA'), 'responder success');
@@ -289,7 +283,7 @@ ok(!staple(8449, 'ECDSA'), 'ocsp error')
TODO: {
local $TODO = 'broken TLSv1.3 sigalgs in LibreSSL'
- if $t->has_module('LibreSSL') && $version > 0x303;
+ if $t->has_module('LibreSSL') && test_tls13();
like(`grep -F '[crit]' ${\($t->testdir())}/error.log`, qr/^$/s, 'no crit');
@@ -302,9 +296,16 @@ sub staple {
my (@resp);
my $staple_cb = sub {
- my ($ssl, $resp) = @_;
+ my ($s, $resp) = @_;
push @resp, !!$resp;
return 1 unless $resp;
+
+ # Contrary to the documentation, IO::Socket::SSL calls the
+ # SSL_ocsp_staple_callback with the socket, and not the
+ # Net::SSLeay object.
+
+ my $ssl = $s->_get_ssl_object();
+
my $cert = Net::SSLeay::get_peer_certificate($ssl);
my $certid = eval { Net::SSLeay::OCSP_cert2ids($ssl, $cert) }
or do { die "no OCSP_CERTID for certificate: $@"; };
@@ -313,69 +314,34 @@ sub staple {
push @resp, $res[0][2]->{'statusType'};
};
- my $s;
-
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- local $SIG{PIPE} = sub { die "sigpipe\n" };
- alarm(8);
- $s = IO::Socket::INET->new('127.0.0.1:' . port($port));
- alarm(0);
+ my $ctx_cb = sub {
+ my $ctx = shift;
+ return unless defined $ciphers;
+ my $ssleay = Net::SSLeay::SSLeay();
+ return if ($ssleay < 0x1000200f || $ssleay == 0x20000000);
+ my $sigalgs = 'RSA+SHA256:PSS+SHA256';
+ $sigalgs = $ciphers . '+SHA256' unless $ciphers eq 'RSA';
+ # SSL_CTRL_SET_SIGALGS_LIST
+ Net::SSLeay::CTX_ctrl($ctx, 98, 0, $sigalgs)
+ or die("Failed to set sigalgs");
};
- alarm(0);
-
- if ($@) {
- log_in("died: $@");
- return undef;
- }
-
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssleay = Net::SSLeay::SSLeay();
- if ($ssleay < 0x1000200f || $ssleay == 0x20000000) {
- Net::SSLeay::CTX_set_cipher_list($ctx, $ciphers)
- or die("Failed to set cipher list");
- } else {
- # SSL_CTRL_SET_SIGALGS_LIST
- $ciphers = 'PSS' if $ciphers eq 'RSA' && $version > 0x0303;
- Net::SSLeay::CTX_ctrl($ctx, 98, 0, $ciphers . '+SHA256')
- or die("Failed to set sigalgs");
- }
+ my $s = http_get(
+ '/', start => 1, PeerAddr => '127.0.0.1:' . port($port),
+ SSL => 1,
+ SSL_cipher_list => $ciphers,
+ SSL_create_ctx_callback => $ctx_cb,
+ SSL_ocsp_staple_callback => $staple_cb,
+ SSL_ocsp_mode => IO::Socket::SSL::SSL_OCSP_TRY_STAPLE(),
+ SSL_ca_file => $ca
+ );
- Net::SSLeay::CTX_load_verify_locations($ctx, $ca || '', '');
- Net::SSLeay::CTX_set_tlsext_status_cb($ctx, $staple_cb);
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_tlsext_status_type($ssl,
- Net::SSLeay::TLSEXT_STATUSTYPE_ocsp());
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
-
+ return $s unless $s;
return join ' ', @resp;
}
-sub get_version {
- my $s;
-
- eval {
- local $SIG{ALRM} = sub { die "timeout\n" };
- local $SIG{PIPE} = sub { die "sigpipe\n" };
- alarm(8);
- $s = IO::Socket::INET->new('127.0.0.1:' . port(8443));
- alarm(0);
- };
- alarm(0);
-
- if ($@) {
- log_in("died: $@");
- return undef;
- }
-
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
-
- Net::SSLeay::version($ssl);
+sub test_tls13 {
+ return http_get('/', start => 1, SSL => 1) =~ /TLSv1.3/;
}
###############################################################################
diff --git a/ssl_verify_client.t b/ssl_verify_client.t
--- a/ssl_verify_client.t
+++ b/ssl_verify_client.t
@@ -17,29 +17,14 @@ use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
-use Test::Nginx;
+use Test::Nginx qw/ :DEFAULT http_end /;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
-eval {
- require Net::SSLeay;
- Net::SSLeay::load_error_strings();
- Net::SSLeay::SSLeay_add_ssl_algorithms();
- Net::SSLeay::randomize();
-};
-plan(skip_all => 'Net::SSLeay not installed') if $@;
-
-eval {
- my $ctx = Net::SSLeay::CTX_new() or die;
- my $ssl = Net::SSLeay::new($ctx) or die;
- Net::SSLeay::set_tlsext_host_name($ssl, 'example.org') == 1 or die;
-};
-plan(skip_all => 'Net::SSLeay with OpenSSL SNI support required') if $@;
-
-my $t = Test::Nginx->new()->has(qw/http http_ssl sni/)
+my $t = Test::Nginx->new()->has(qw/http http_ssl sni socket_ssl_sni/)
->has_daemon('openssl')->plan(13);
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -72,7 +57,7 @@ http {
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name on;
ssl_certificate_key 1.example.com.key;
@@ -83,7 +68,7 @@ http {
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name optional;
ssl_certificate_key 1.example.com.key;
@@ -95,7 +80,7 @@ http {
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name off;
ssl_certificate_key 1.example.com.key;
@@ -107,7 +92,7 @@ http {
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name optional.no.ca;
ssl_certificate_key 1.example.com.key;
@@ -118,7 +103,7 @@ http {
}
server {
- listen 127.0.0.1:8081 ssl;
+ listen 127.0.0.1:8443 ssl;
server_name no.context;
ssl_verify_client on;
@@ -191,25 +176,28 @@ sub test_tls13 {
sub get {
my ($sni, $cert, $host) = @_;
- local $SIG{PIPE} = 'IGNORE';
-
$host = $sni if !defined $host;
- my $s = IO::Socket::INET->new('127.0.0.1:' . port(8081));
- my $ctx = Net::SSLeay::CTX_new() or die("Failed to create SSL_CTX $!");
- Net::SSLeay::set_cert_and_key($ctx, "$d/$cert.crt", "$d/$cert.key")
- or die if $cert;
- my $ssl = Net::SSLeay::new($ctx) or die("Failed to create SSL $!");
- Net::SSLeay::set_tlsext_host_name($ssl, $sni) == 1 or die;
- Net::SSLeay::set_fd($ssl, fileno($s));
- Net::SSLeay::connect($ssl) or die("ssl connect");
+ my $s = http(
+ "GET /t HTTP/1.0" . CRLF .
+ "Host: $host" . CRLF . CRLF,
+ start => 1,
+ SSL => 1,
+ SSL_hostname => $sni,
+ $cert ? (
+ SSL_cert_file => "$d/$cert.crt",
+ SSL_key_file => "$d/$cert.key"
+ ) : ()
+ );
- Net::SSLeay::write($ssl, 'GET /t HTTP/1.0' . CRLF);
- Net::SSLeay::write($ssl, "Host: $host" . CRLF . CRLF);
- my $buf = Net::SSLeay::read($ssl);
- log_in($buf);
- return $buf unless wantarray();
+ return http_end($s) unless wantarray();
+ # Note: this uses IO::Socket::SSL::_get_ssl_object() internal method.
+ # While not exactly correct, it looks like there is no other way to
+ # obtain CA list with IO::Socket::SSL, and this seems to be good
+ # enough for tests.
+
+ my $ssl = $s->_get_ssl_object();
my $list = Net::SSLeay::get_client_CA_list($ssl);
my @names;
for my $i (0 .. Net::SSLeay::sk_X509_NAME_num($list) - 1) {
More information about the nginx-devel
mailing list