8000 SSL: allow configuring providers with "ssl_provider ...". by bavshin-f5 · Pull Request #710 · nginx/nginx · GitHub
[go: up one dir, main page]

Skip to content

SSL: allow configuring providers with "ssl_provider ...". #710

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

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
86 changes: 86 additions & 0 deletions src/event/ngx_event_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static time_t ngx_ssl_parse_time(

static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_openssl_provider(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);


Expand All @@ -94,6 +95,13 @@ static ngx_command_t ngx_openssl_commands[] = {
0,
NULL },

{ ngx_string("ssl_provider"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE,
ngx_openssl_provider,
0,
0,
NULL },

ngx_null_command
};

Expand Down Expand Up @@ -5982,6 +5990,84 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}


static char *
ngx_openssl_provider(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)

u_char *p;
ngx_uint_t i;
ngx_str_t *value;
OSSL_PARAM *param;
ngx_array_t params;

if (cf->cycle->modules_used) {
return "is specified too late";
}

value = cf->args->elts;

if (OSSL_PROVIDER_available(NULL, (char *) value[1].data)) {
ngx_conf_log_error(NGX_LOG_INFO, cf, 0,
"ssl_provider \"%V\" is already loaded", &value[1]);
return NGX_CONF_OK;
}

if (ngx_array_init(&params, cf->pool, cf->args->nelts - 1,
sizeof(OSSL_PARAM))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}

ngx_memzero(params.elts, (cf->args->nelts - 1) * sizeof(OSSL_PARAM));

for (i = 2; i < cf->args->nelts; i++) {
p = (u_char *) ngx_strchr(value[i].data, '=');

if (p == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}

param = ngx_array_push(&params);
if (param == NULL) {
return NGX_CONF_ERROR;
}

*p++ = '\0';

param->key = (char *) value[i].data;
param->data_type = OSSL_PARAM_UTF8_STRING;
param->data = p;
param->data_size = value[i].data + value[i].len - p;
}

param = ngx_array_push(&params);
if (param == NULL) {
return NGX_CONF_ERROR;
}

if (OSSL_PROVIDER_load_ex(NULL, (char* ) value[1].data,
(params.nelts > 1) ? params.elts : NULL)
== NULL)
{
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
"OSSL_PROVIDER_load_ex(\"%V\") failed", &value[1]);
return NGX_CONF_ERROR;
}

return NGX_CONF_OK;

#else

return "is not supported";

#endif
}


static void
ngx_openssl_exit(ngx_cycle_t *cycle)
{
Expand Down
3 changes: 3 additions & 0 deletions src/event/ngx_event_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#ifndef OPENSSL_NO_OCSP
#include <openssl/ocsp.h>
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
#include <openssl/provider.h>
#endif
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
Expand Down
188 changes: 188 additions & 0 deletions t/ssl_provider.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#!/usr/bin/perl

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

# Tests for "ssl_provider" directive.

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

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.2.0/)
->has_daemon('openssl')->has_daemon('softhsm2-util');

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;

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

%%TEST_GLOBALS%%

daemon off;

env SOFTHSM2_CONF;

ssl_provider default;
ssl_provider pkcs11
pkcs11-module-path=$libsofthsm2_path
pkcs11-module-cache-pins=cache
"pkcs11-module-quirks=no-deinit no-operation-state";

events {
}

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

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";

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 "
. ' 6751 --token NginxZero --pin 1234 '
. ">>$d/openssl.out 2>&1") == 0
or die "Can't import private key: $!\n";

system("openssl req -x509 -new -config $d/openssl.conf "
. "-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');

###############################################################################
0