|
Packit |
b893dc |
#!/usr/bin/perl
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
use strict;
|
|
Packit |
b893dc |
use warnings;
|
|
Packit |
b893dc |
use Test::More;
|
|
Packit |
b893dc |
use Socket;
|
|
Packit |
b893dc |
use File::Spec;
|
|
Packit |
b893dc |
use Net::SSLeay;
|
|
Packit |
b893dc |
use Config;
|
|
Packit |
b893dc |
use IO::Socket::INET;
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
BEGIN {
|
|
Packit |
b893dc |
plan skip_all => "fork() not supported on $^O" unless $Config{d_fork};
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $tests = 34;
|
|
Packit |
b893dc |
plan tests => $tests;
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $pid;
|
|
Packit |
b893dc |
alarm(30);
|
|
Packit |
b893dc |
END { kill 9,$pid if $pid }
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Values that were previously looked up for get_keyblock_size test
|
|
Packit |
b893dc |
# Revisit: currently the only known user for get_keyblock_size is
|
|
Packit |
b893dc |
# EAP-FAST. How it works with AEAD ciphers is for future study.
|
|
Packit |
b893dc |
our %non_aead_cipher_to_keyblock_size =
|
|
Packit |
b893dc |
(
|
|
Packit |
b893dc |
'RC4-MD5' => 64,
|
|
Packit |
b893dc |
'RC4-SHA' => 72,
|
|
Packit |
b893dc |
'AES256-SHA256' => 160,
|
|
Packit |
b893dc |
'AES128-SHA256' => 128,
|
|
Packit |
b893dc |
'AES128-SHA' => 104,
|
|
Packit |
b893dc |
'AES256-SHA' => 136,
|
|
Packit |
b893dc |
);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
our %tls_1_2_aead_cipher_to_keyblock_size = (
|
|
Packit |
b893dc |
'AES128-GCM-SHA256' => 56,
|
|
Packit |
b893dc |
'AES256-GCM-SHA384' => 88,
|
|
Packit |
b893dc |
);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
our %tls_1_3_aead_cipher_to_keyblock_size = (
|
|
Packit |
b893dc |
# Only in TLS 1.3
|
|
Packit |
b893dc |
'TLS_AES_128_GCM_SHA256' => 56,
|
|
Packit |
b893dc |
'TLS_AES_256_GCM_SHA384' => 88,
|
|
Packit |
b893dc |
'TLS_CHACHA20_POLY1305_SHA256' => 88,
|
|
Packit |
b893dc |
);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Combine the AEAD hashes
|
|
Packit |
b893dc |
our %aead_cipher_to_keyblock_size = (%tls_1_2_aead_cipher_to_keyblock_size, %tls_1_3_aead_cipher_to_keyblock_size);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Combine the hashes
|
|
Packit |
b893dc |
our %cipher_to_keyblock_size = (%non_aead_cipher_to_keyblock_size, %aead_cipher_to_keyblock_size);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
our %version_str2int =
|
|
Packit |
b893dc |
(
|
|
Packit |
b893dc |
'SSLv3' => sub {return eval {Net::SSLeay::SSL3_VERSION();}},
|
|
Packit |
b893dc |
'TLSv1' => sub {return eval {Net::SSLeay::TLS1_VERSION();}},
|
|
Packit |
b893dc |
'TLSv1.1' => sub {return eval {Net::SSLeay::TLS1_1_VERSION();}},
|
|
Packit |
b893dc |
'TLSv1.2' => sub {return eval {Net::SSLeay::TLS1_2_VERSION();}},
|
|
Packit |
b893dc |
'TLSv1.3' => sub {return eval {Net::SSLeay::TLS1_3_VERSION();}},
|
|
Packit |
b893dc |
);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $server;
|
|
Packit |
b893dc |
Net::SSLeay::initialize();
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
# SSL server - just handle single connect, send information to
|
|
Packit |
b893dc |
# client and exit
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $cert_pem = File::Spec->catfile('t', 'data', 'testcert_wildcard.crt.pem');
|
|
Packit |
b893dc |
my $key_pem = File::Spec->catfile('t', 'data', 'testcert_key_2048.pem');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$server = IO::Socket::INET->new( LocalAddr => '127.0.0.1', Listen => 3)
|
|
Packit |
b893dc |
or BAIL_OUT("failed to create server socket: $!");
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
defined($pid = fork()) or BAIL_OUT("failed to fork: $!");
|
|
Packit |
b893dc |
if ($pid == 0) {
|
|
Packit |
b893dc |
my $cl = $server->accept or BAIL_OUT("accept failed: $!");
|
|
Packit |
b893dc |
my $ctx = Net::SSLeay::CTX_new();
|
|
Packit |
b893dc |
Net::SSLeay::set_cert_and_key($ctx, $cert_pem, $key_pem);
|
|
Packit |
b893dc |
# my $get_keyblock_size_ciphers = join(':', keys(%cipher_to_keyblock_size));
|
|
Packit |
b893dc |
my $get_keyblock_size_ciphers = join(':', keys(%non_aead_cipher_to_keyblock_size));
|
|
Packit |
b893dc |
Net::SSLeay::CTX_set_cipher_list($ctx, $get_keyblock_size_ciphers);
|
|
Packit |
b893dc |
my $ssl = Net::SSLeay::new($ctx);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
Net::SSLeay::set_fd($ssl, fileno($cl));
|
|
Packit |
b893dc |
Net::SSLeay::accept($ssl);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Send our idea of Finished messages to the client.
|
|
Packit |
b893dc |
my ($f_len, $finished_s, $finished_c);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_finished($ssl, $finished_s);
|
|
Packit |
b893dc |
Net::SSLeay::write($ssl, "server: $f_len ". unpack('H*', $finished_s));
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_peer_finished($ssl, $finished_c);
|
|
Packit |
b893dc |
Net::SSLeay::write($ssl, "client: $f_len ". unpack('H*', $finished_c));
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Echo back the termination request from client
|
|
Packit |
b893dc |
my $end = Net::SSLeay::read($ssl);
|
|
Packit |
b893dc |
Net::SSLeay::write($ssl, $end);
|
|
Packit |
b893dc |
exit(0);
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
sub client {
|
|
Packit |
b893dc |
# SSL client - connect to server and receive information that we
|
|
Packit |
b893dc |
# compare to our expected values
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my ($f_len, $f_len_trunc, $finished_s, $finished_c, $msg, $expected);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $saddr = $server->sockhost.':'.$server->sockport;
|
|
Packit |
b893dc |
my $cl = IO::Socket::INET->new($saddr)
|
|
Packit |
b893dc |
or BAIL_OUT("failed to connect to server: $!");
|
|
Packit |
b893dc |
my $ctx = Net::SSLeay::CTX_new();
|
|
Packit |
b893dc |
Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL);
|
|
Packit |
b893dc |
my $ssl = Net::SSLeay::new($ctx);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
Net::SSLeay::set_fd($ssl, $cl);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
client_test_finished($ssl);
|
|
Packit |
b893dc |
client_test_keyblock_size($ssl);
|
|
Packit |
b893dc |
client_test_version_funcs($ssl);
|
|
Packit |
b893dc |
client_test_ciphersuites();
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Tell the server to quit and see that our connection is still up
|
|
Packit |
b893dc |
my $end = "end";
|
|
Packit |
b893dc |
Net::SSLeay::write($ssl, $end);
|
|
Packit |
b893dc |
ok($end eq Net::SSLeay::read($ssl), 'Successful termination');
|
|
Packit |
b893dc |
return;
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
client();
|
|
Packit |
b893dc |
waitpid $pid, 0;
|
|
Packit |
b893dc |
exit(0);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Test get_finished() and get_peer_finished() with server.
|
|
Packit |
b893dc |
sub client_test_finished
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
my ($ssl) = @_;
|
|
Packit |
b893dc |
my ($f_len, $f_len_trunc, $finished_s, $finished_c, $msg, $expected);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Finished messages have not been sent yet
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_peer_finished($ssl, $finished_s);
|
|
Packit |
b893dc |
ok($f_len == 0, 'Return value for get_peer_finished is empty before connect for server');
|
|
Packit |
b893dc |
ok(defined $finished_s && $finished_s eq '', 'Server Finished is empty');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_finished($ssl, $finished_c);
|
|
Packit |
b893dc |
ok($f_len == 0, 'Finished is empty before connect for client');
|
|
Packit |
b893dc |
ok(defined $finished_c && $finished_c eq '', 'Client Finished is empty');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Complete connection. After this we have Finished messages from both peers.
|
|
Packit |
b893dc |
Net::SSLeay::connect($ssl);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_peer_finished($ssl, $finished_s);
|
|
Packit |
b893dc |
ok($f_len, 'Server Finished is not empty');
|
|
Packit |
b893dc |
ok($f_len == length($finished_s), 'Return value for get_peer_finished equals to Finished length');
|
|
Packit |
b893dc |
$expected = "server: $f_len " . unpack('H*', $finished_s);
|
|
Packit |
b893dc |
$msg = Net::SSLeay::read($ssl);
|
|
Packit |
b893dc |
ok($msg eq $expected, 'Server Finished is equal');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$f_len = Net::SSLeay::get_finished($ssl, $finished_c);
|
|
Packit |
b893dc |
ok($f_len, 'Client Finished is not empty');
|
|
Packit |
b893dc |
ok($f_len == length($finished_c), 'Return value for get_finished equals to Finished length');
|
|
Packit |
b893dc |
$expected = "client: $f_len " . unpack('H*', $finished_c);
|
|
Packit |
b893dc |
$msg = Net::SSLeay::read($ssl);
|
|
Packit |
b893dc |
ok($msg eq $expected, 'Client Finished is equal');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
ok($finished_s ne $finished_c, 'Server and Client Finished are not equal');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Finished should still be the same. See that we can fetch truncated values.
|
|
Packit |
b893dc |
my $trunc8_s = substr($finished_s, 0, 8);
|
|
Packit |
b893dc |
$f_len_trunc = Net::SSLeay::get_peer_finished($ssl, $finished_s, 8);
|
|
Packit |
b893dc |
ok($f_len_trunc == $f_len, 'Return value for get_peer_finished is unchanged when count is set');
|
|
Packit |
b893dc |
ok($trunc8_s eq $finished_s, 'Count works for get_peer_finished');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $trunc8_c = substr($finished_c, 0, 8);
|
|
Packit |
b893dc |
$f_len_trunc = Net::SSLeay::get_finished($ssl, $finished_c, 8);
|
|
Packit |
b893dc |
ok($f_len_trunc == $f_len, 'Return value for get_finished is unchanged when count is set');
|
|
Packit |
b893dc |
ok($trunc8_c eq $finished_c, 'Count works for get_finished');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Test get_keyblock_size
|
|
Packit |
b893dc |
# Notes: With TLS 1.3 the cipher is always an AEAD cipher. If AEAD
|
|
Packit |
b893dc |
# ciphers are enabled for TLS 1.2 and earlier, with LibreSSL
|
|
Packit |
b893dc |
# get_keyblock_size returns -1 when AEAD cipher is chosen.
|
|
Packit |
b893dc |
sub client_test_keyblock_size
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
my ($ssl) = @_;
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $cipher = Net::SSLeay::get_cipher($ssl);
|
|
Packit |
b893dc |
ok($cipher, "get_cipher returns a value: $cipher");
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $keyblock_size = &Net::SSLeay::get_keyblock_size($ssl);
|
|
Packit |
b893dc |
ok(defined $keyblock_size, 'get_keyblock_size return value is defined');
|
|
Packit |
b893dc |
if ($keyblock_size == -1)
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
# Accept -1 with AEAD ciphers with LibreSSL
|
|
Packit |
b893dc |
like(Net::SSLeay::SSLeay_version(Net::SSLeay::SSLEAY_VERSION()), qr/^LibreSSL/, 'get_keyblock_size returns -1 with LibreSSL');
|
|
Packit |
b893dc |
ok(defined $aead_cipher_to_keyblock_size{$cipher}, 'keyblock size is -1 for an AEAD cipher');
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
else
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
ok($keyblock_size >= 0, 'get_keyblock_size return value is not negative');
|
|
Packit |
b893dc |
ok($cipher_to_keyblock_size{$cipher} == $keyblock_size, "keyblock size $keyblock_size is the expected value $cipher_to_keyblock_size{$cipher}");
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
# Test SSL_get_version and related functions
|
|
Packit |
b893dc |
sub client_test_version_funcs
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
my ($ssl) = @_;
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $version_str = Net::SSLeay::get_version($ssl);
|
|
Packit |
b893dc |
my $version_const = $version_str2int{$version_str};
|
|
Packit |
b893dc |
my $version = Net::SSLeay::version($ssl);
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
ok(defined $version_const, "Net::SSLeay::get_version return value $version_str is known");
|
|
Packit |
b893dc |
is(&$version_const, $version, "Net:SSLeay::version return value $version matches get_version string");
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
if (defined &Net::SSLeay::client_version) {
|
|
Packit |
b893dc |
if ($version_str eq 'TLSv1.3') {
|
|
Packit |
b893dc |
# Noticed that client_version and version are equal for all SSL/TLS versions except of TLSv1.3
|
|
Packit |
b893dc |
# For more, see https://github.com/openssl/openssl/issues/7079
|
|
Packit |
b893dc |
is(Net::SSLeay::client_version($ssl), &{$version_str2int{'TLSv1.2'}},
|
|
Packit |
b893dc |
'Net::SSLeay::client_version TLSv1.2 is expected when Net::SSLeay::version indicates TLSv1.3');
|
|
Packit |
b893dc |
} else {
|
|
Packit |
b893dc |
is(Net::SSLeay::client_version($ssl), $version, 'Net::SSLeay::client_version equals to Net::SSLeay::version');
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
is(Net::SSLeay::is_dtls($ssl), 0, 'Net::SSLeay::is_dtls returns 0');
|
|
Packit |
b893dc |
} else
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
SKIP: {
|
|
Packit |
b893dc |
skip('Do not have Net::SSLeay::client_version nor Net::SSLeay::is_dtls', 2);
|
|
Packit |
b893dc |
};
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
return;
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
sub client_test_ciphersuites
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
unless (defined &Net::SSLeay::CTX_set_ciphersuites)
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
SKIP: {
|
|
Packit |
b893dc |
skip('Do not have Net::SSLeay::CTX_set_ciphersuites', 10);
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
return;
|
|
Packit |
b893dc |
}
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my $ciphersuites = join(':', keys(%tls_1_3_aead_cipher_to_keyblock_size));
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
my ($ctx, $rv, $ssl);
|
|
Packit |
b893dc |
$ctx = Net::SSLeay::CTX_new();
|
|
Packit |
b893dc |
$rv = Net::SSLeay::CTX_set_ciphersuites($ctx, $ciphersuites);
|
|
Packit |
b893dc |
is($rv, 1, 'CTX set good ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::CTX_set_ciphersuites($ctx, '');
|
|
Packit |
b893dc |
is($rv, 1, 'CTX set empty ciphersuites');
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
no warnings 'uninitialized';
|
|
Packit |
b893dc |
$rv = Net::SSLeay::CTX_set_ciphersuites($ctx, undef);
|
|
Packit |
b893dc |
};
|
|
Packit |
b893dc |
is($rv, 1, 'CTX set undef ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::CTX_set_ciphersuites($ctx, 'nosuchthing:' . $ciphersuites);
|
|
Packit |
b893dc |
is($rv, 0, 'CTX set partially bad ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::CTX_set_ciphersuites($ctx, 'nosuchthing:');
|
|
Packit |
b893dc |
is($rv, 0, 'CTX set bad ciphersuites');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
$ssl = Net::SSLeay::new($ctx);
|
|
Packit |
b893dc |
$rv = Net::SSLeay::set_ciphersuites($ssl, $ciphersuites);
|
|
Packit |
b893dc |
is($rv, 1, 'SSL set good ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::set_ciphersuites($ssl, '');
|
|
Packit |
b893dc |
is($rv, 1, 'SSL set empty ciphersuites');
|
|
Packit |
b893dc |
{
|
|
Packit |
b893dc |
no warnings 'uninitialized';
|
|
Packit |
b893dc |
$rv = Net::SSLeay::set_ciphersuites($ssl, undef);
|
|
Packit |
b893dc |
};
|
|
Packit |
b893dc |
is($rv, 1, 'SSL set undef ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::set_ciphersuites($ssl, 'nosuchthing:' . $ciphersuites);
|
|
Packit |
b893dc |
is($rv, 0, 'SSL set partially bad ciphersuites');
|
|
Packit |
b893dc |
$rv = Net::SSLeay::set_ciphersuites($ssl, 'nosuchthing:');
|
|
Packit |
b893dc |
is($rv, 0, 'SSL set bad ciphersuites');
|
|
Packit |
b893dc |
|
|
Packit |
b893dc |
return;
|
|
Packit |
b893dc |
}
|