Skip to content

Tests: test for loading "store:..." keys. #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions ssl_engine_keys.t
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ plan(skip_all => 'may not work, leaves coredump')
unless $ENV{TEST_NGINX_UNSAFE};

my $t = Test::Nginx->new()->has(qw/http proxy http_ssl/)->has_daemon('openssl')
->has_daemon('softhsm2-util')->has_daemon('pkcs11-tool');
->has_daemon('softhsm2-util');

$t->write_file_expand('nginx.conf', <<'EOF');

Expand Down Expand Up @@ -151,9 +151,14 @@ foreach my $name ('localhost') {
. '--pin 1234 --so-pin 1234 '
. ">>$d/openssl.out 2>&1");

system("pkcs11-tool --module=$libsofthsm2_path "
. '-p 1234 -l -k -d 0 -a nx_key_0 --key-type rsa:2048 '
. ">>$d/openssl.out 2>&1");
system("openssl genrsa -out $d/$name.key 2048 "
. ">>$d/openssl.out 2>&1") == 0
or die "Can't create private key: $!\n";

system("softhsm2-util --import $d/$name.key --id 00 --label nx_key_0 "
. '--token NginxZero --pin 1234 '
. ">>$d/openssl.out 2>&1") == 0
or die "Can't import private key: $!\n";

system('openssl req -x509 -new '
. "-subj /CN=$name/ -out $d/$name.crt -text "
Expand Down
191 changes: 191 additions & 0 deletions ssl_provider_keys.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/perl

# (C) Sergey Kandaurov
# (C) Aleksei Bavshin
# (C) Nginx, Inc.

# Tests for http ssl module, loading "store:..." keys from OpenSSL providers.

###############################################################################

use warnings;
use strict;

use Test::More;

BEGIN { use FindBin; chdir($FindBin::Bin); }

use lib 'lib';
use Test::Nginx;

###############################################################################

select STDERR; $| = 1;
select STDOUT; $| = 1;

plan(skip_all => 'win32') if $^O eq 'MSWin32';

plan(skip_all => 'may not work, incompatible with sanitizers')
unless $ENV{TEST_NGINX_UNSAFE};

my $t = Test::Nginx->new()->has(qw/http proxy http_ssl openssl:3/)
->has_daemon('openssl')->has_daemon('softhsm2-util');

plan(skip_all => 'not yet') unless $t->has_version('1.29.0');

$t->write_file_expand('nginx.conf', <<'EOF');

%%TEST_GLOBALS%%

daemon off;

events {
}

env SOFTHSM2_CONF;

http {
%%TEST_GLOBALS_HTTP%%

server {
listen 127.0.0.1:8081 ssl;
listen 127.0.0.1:8080;
server_name localhost;

ssl_certificate localhost.crt;
ssl_certificate_key "store:pkcs11:token=NginxZero;object=nx_key_0";

ssl_password_file pin.txt;

location / {
# index index.html by default
}

location /proxy {
proxy_pass https://127.0.0.1:8081/;
}

location /var {
proxy_pass https://127.0.0.1:8082/;
proxy_ssl_name localhost;
proxy_ssl_server_name on;
}
}

server {
listen 127.0.0.1:8082 ssl;
server_name localhost;

ssl_certificate $ssl_server_name.crt;
ssl_certificate_key "store:pkcs11:token=NginxZero;object=nx_key_0";

ssl_password_file pin.txt;

location / {
# index index.html by default
}
}
}

EOF

# Create a SoftHSM token with a secret key, and configure OpenSSL to access it
# using the pkcs11 provider (https://github.com/latchset/pkcs11-provider).
#
# Note that library paths vary on different systems,
# and may need to be adjusted.

my $libsofthsm2_path;
my @so_paths = (
'/usr/lib/softhsm', # Debian-based
'/usr/local/lib/softhsm', # FreeBSD
'/opt/local/lib/softhsm', # MacPorts
'/lib64', # RHEL-based
split /:/, $ENV{TEST_NGINX_SOFTHSM} || ''
);

for my $so_path (@so_paths) {
$so_path .= '/libsofthsm2.so';
if (-e $so_path) {
$libsofthsm2_path = $so_path;
last;
}
};

plan(skip_all => "libsofthsm2.so not found") unless $libsofthsm2_path;

my $openssl_conf = <<EOF;
openssl_conf = openssl_def

[openssl_def]
providers = provider_sect

[provider_sect]
default = default_sect
pkcs11 = pkcs11_sect

[default_sect]
activate = 1

[pkcs11_sect]
pkcs11-module-path = $libsofthsm2_path
pkcs11-module-cache-pins = cache
# https://github.com/latchset/pkcs11-provider/commit/ab6370fd
pkcs11-module-quirks = no-deinit no-operation-state
module = /usr/local/lib/ossl-modules/pkcs11.so
activate = 1

[ req ]
default_bits = 2048
encrypt_key = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
EOF

$openssl_conf =~ s|^(?=module)|# |m if $^O ne 'freebsd';
$t->write_file('openssl.conf', $openssl_conf);

my $d = $t->testdir();

$t->write_file('softhsm2.conf', <<EOF);
directories.tokendir = $d/tokens/
objectstore.backend = file
EOF

mkdir($d . '/tokens');

$ENV{SOFTHSM2_CONF} = "$d/softhsm2.conf";
$ENV{OPENSSL_CONF} = "$d/openssl.conf";

foreach my $name ('localhost') {
system('softhsm2-util --init-token --slot 0 --label NginxZero '
. '--pin 1234 --so-pin 1234 '
. ">>$d/openssl.out 2>&1");

system("openssl genrsa -out $d/$name.key 2048 "
. ">>$d/openssl.out 2>&1") == 0
or die "Can't create private key: $!\n";

system("softhsm2-util --import $d/$name.key --id 00 --label nx_key_0 "
. '--token NginxZero --pin 1234 '
. ">>$d/openssl.out 2>&1") == 0
or die "Can't import private key: $!\n";

system('openssl req -x509 -new '
. "-subj /CN=$name/ -out $d/$name.crt -text -passin pass:1234 "
. '-key "pkcs11:token=NginxZero;object=nx_key_0" '
. ">>$d/openssl.out 2>&1") == 0
or plan(skip_all => "missing pkcs11-provider");
}

$t->write_file('pin.txt', '1234');
$t->write_file('index.html', '');

$t->run()->plan(2);

###############################################################################

like(http_get('/proxy'), qr/200 OK/, 'ssl provider keys');
like(http_get('/var'), qr/200 OK/, 'ssl_certificate with variable');

###############################################################################
174 changes: 174 additions & 0 deletions ssl_store_keys.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/perl

# (C) Aleksei Bavshin
# (C) Nginx, Inc.

# Tests for http ssl module, loading "store:..." keys.

###############################################################################

use warnings;
use strict;

use Test::More;

BEGIN { use FindBin; chdir($FindBin::Bin); }

use lib 'lib';
use Test::Nginx qw/ :DEFAULT http_end /;

###############################################################################

select STDERR; $| = 1;
select STDOUT; $| = 1;

my $t = Test::Nginx->new()
->has(qw/http http_ssl geo openssl:1.1.1 socket_ssl_sni/)
->has_daemon('openssl');

plan(skip_all => 'BoringSSL') if $t->has_module('BoringSSL|AWS-LC');
plan(skip_all => 'not yet') unless $t->has_version('1.29.0');

$t->write_file_expand('nginx.conf', <<'EOF');

%%TEST_GLOBALS%%

daemon off;

events {
}

http {
%%TEST_GLOBALS_HTTP%%

geo $localhost {
default localhost;
}

geo $pass {
default pass;
}

add_header X-SSL $ssl_server_name;

server {
listen 127.0.0.1:8080 ssl;
server_name default;

ssl_certificate localhost.crt;
ssl_certificate_key store:file:%%TESTDIR%%/localhost.key;
}

server {
listen 127.0.0.1:8080 ssl;
server_name variable;

ssl_certificate localhost.crt;
ssl_certificate_key store:file:%%TESTDIR%%/$localhost.key;
}

server {
listen 127.0.0.1:8080 ssl;
server_name pass;

ssl_certificate pass.crt;
ssl_certificate_key store:file:%%TESTDIR%%/pass.key;

ssl_password_file password;
}

server {
listen 127.0.0.1:8080 ssl;
server_name variable-pass;

ssl_certificate pass.crt;
ssl_certificate_key store:file:%%TESTDIR%%/$pass.key;

ssl_password_file password;
}

server {
listen 127.0.0.1:8080 ssl;
server_name variable-no-pass;

ssl_certificate pass.crt;
ssl_certificate_key store:file:%%TESTDIR%%/$pass.key;
}
}

EOF

$t->write_file('openssl.conf', <<EOF);
[ req ]
default_bits = 2048
encrypt_key = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
EOF

my $d = $t->testdir();

foreach my $name ('localhost') {
system('openssl req -x509 -new '
. "-config $d/openssl.conf -subj /CN=$name/ "
. "-out $d/$name.crt -keyout $d/$name.key "
. ">>$d/openssl.out 2>&1") == 0
or die "Can't create certificate for $name: $!\n";
}

foreach my $name ('pass') {
system("openssl genrsa -out $d/$name.key -passout pass:$name "
. "-aes128 2048 >>$d/openssl.out 2>&1") == 0
or die "Can't create private key: $!\n";
system('openssl req -x509 -new '
. "-config $d/openssl.conf -subj /CN=$name/ "
. "-out $d/$name.crt "
. "-key $d/$name.key -passin pass:$name"
. ">>$d/openssl.out 2>&1") == 0
or die "Can't create certificate for $name: $!\n";
}


$t->write_file('password', 'pass');
$t->write_file('index.html', '');

$t->run()->plan(9);

###############################################################################

like(cert('default'), qr/CN=localhost/, 'default key');
like(get('default'), qr/default/, 'default context');

like(cert('variable'), qr/CN=localhost/, 'key with vars');
like(get('variable'), qr/variable/, 'context with vars');

like(cert('pass'), qr/CN=pass/, 'encrypted key');
like(get('pass'), qr/pass/, 'encrypted context');

like(cert('variable-pass'), qr/CN=pass/, 'encrypted key - vars');
like(get('variable-pass'), qr/variable-pass/, 'encrypted context - vars');

is(cert('variable-no-pass'), undef, 'encrypted key - no pass');

###############################################################################

sub get {
my $s = get_socket(@_) || return;
return http_end($s);
}

sub cert {
my $s = get_socket(@_) || return;
return $s->dump_peer_certificate();
}

sub get_socket {
my ($host) = @_;
return http_get(
'/', start => 1, PeerAddr => '127.0.0.1:' . port(8080),
SSL => 1,
SSL_hostname => $host,
);
}

###############################################################################