diff --git a/README.md b/README.md index c65db70..5c657bf 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,10 @@ There will be failures of SSL tests for the following reasons: Note: the file ssl_ecc.t in wolfssl-nginx can be used with the Nginx test system. - +Note: the file ssl_stapling.t.patch can be used to patch the ssl_stapling.t +file in nginx-tests to work with wolfSSL. The version available in the testing +repository uses different certs on the same server. This is not supported +by wolfSSL so this patch moves the certs to separate server instances. There are additional tests available in wolfssl-nginx. These are in addition to the Nginx tests. The OpenSSL's superapp is required for OCSP Stapling diff --git a/nginx-1.7.7-wolfssl.patch b/nginx-1.7.7-wolfssl.patch index 3f905ed..46c6e2b 100644 --- a/nginx-1.7.7-wolfssl.patch +++ b/nginx-1.7.7-wolfssl.patch @@ -1,5 +1,56 @@ +From 9a58b2ddaa713b312a9d14d6dd563d1df14c8231 Mon Sep 17 00:00:00 2001 +From: Juliusz Sosinowicz +Date: Tue, 1 Dec 2020 13:41:20 +0100 +Subject: [PATCH] wolfSSL Patch for Nginx 1.7.7 + +Build instructions: +- Build wolfSSL (run in wolfSSL directory): +`./configure --enable-nginx` +`make` +`make install` +The default installation directory is `/usr/local`. +- Build Nginx (run in Nginx directory): + - Apply patch: +`patch -p1 < nginx-1.7.7-wolfssl.patch` + - Compile Nginx (some warnings need to be disabled): +`./configure --with-wolfssl=/usr/local --with-http_ssl_module --with-cc-opt='-Wimplicit-fallthrough=0 -Wno-cast-function-type'` +`make` + +Port nginx 1.7.7 to wolfSSL: +- `auto/lib/openssl/conf`: Detect wolfSSL library and setup compilation options +- `auto/options`: Add wolfSSL configure option +- `src/core/nginx.c`: Enable debugging if wolfSSL is compiled with `--enable-debug` +- `src/event/ngx_event_openssl.c`: + - Nginx wants the SSL library to not do any certificate verification by default + - No need to disble renegotiation since wolfSSL has it disabled by default + - Fix TLS tickets callback to return correct values + - Ignore undefined handshake failure codes +- `src/event/ngx_event_openssl.h`: Include wolfSSL options file +- `src/event/ngx_event_openssl_stapling.c`: Use `wolfSSL_X509_up_ref` to increment issuer certificate reference counter +- `src/http/modules/ngx_http_ssl_module.c`: wolfSSL "ALL" provides adequate default ciphers +- `src/http/ngx_http_upstream.c`: Correct type mismatch +- `src/mail/ngx_mail_ssl_module.c`: wolfSSL "ALL" provides adequate default ciphers +- `src/os/unix/ngx_user.c`: `current_salt` not part of `struct crypt_data` in recent glibc version + +nginx-tests remarks: +- All tests in nginx-tests should pass. Some tests test reusing a session but fail on my machine. Manually setting up the server and connecting through Firefox correctly re-uses the session suggesting that the issue is on the client side not the server. I assume that this is an error in my version of Perl (which is the client in the nginx-tests). +- When running nginx-tests with TLS 1.3 then session resumption tests will fail since the tests are not configured for SSL tickets. I tested session reuse manually with Firefox and confirmed that they work. +- nginx 1.7.7 does not do session reuse with TLS 1.3 (when acting as a proxy) because it calls SSL_get1_session too soon. +--- + auto/lib/openssl/conf | 35 ++++++++++++++++++++++---- + auto/options | 3 +++ + src/core/nginx.c | 5 ++++ + src/event/ngx_event_openssl.c | 17 +++++++++++-- + src/event/ngx_event_openssl.h | 3 +++ + src/event/ngx_event_openssl_stapling.c | 8 ++++++ + src/http/modules/ngx_http_ssl_module.c | 4 +++ + src/http/ngx_http_upstream.c | 7 +++++- + src/mail/ngx_mail_ssl_module.c | 4 +++ + src/os/unix/ngx_user.c | 2 ++ + 10 files changed, 80 insertions(+), 8 deletions(-) + diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf -index a65815f6..82c39a46 100644 +index a65815f6..0796e3ab 100644 --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -49,11 +49,38 @@ else @@ -23,7 +74,7 @@ index a65815f6..82c39a46 100644 + ngx_feature_libs="-L$WOLFSSL/lib -lwolfssl -lm $NGX_LIBDL" + fi + -+ CORE_INCS="$CORE_INCS $WOLFSSL/include/wolfssl" ++ CORE_INCS="$CORE_INCS $ngx_feature_path" + CFLAGS="$CFLAGS -DWOLFSSL_NGINX" + fi + @@ -83,6 +134,22 @@ index 0d296ac6..7688cad7 100644 --with-debug enable debug logging +diff --git a/src/core/nginx.c b/src/core/nginx.c +index c75ee4fd..e7b49f0b 100644 +--- a/src/core/nginx.c ++++ b/src/core/nginx.c +@@ -206,6 +206,11 @@ main(int argc, char *const *argv) + ngx_cycle_t *cycle, init_cycle; + ngx_core_conf_t *ccf; + ++ ++#ifdef WOLFSSL_NGINX ++ (void)wolfSSL_Debugging_ON(); ++#endif ++ + ngx_debug_init(); + + if (ngx_strerror_init() != NGX_OK) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index f3456527..065ec5af 100644 --- a/src/event/ngx_event_openssl.c diff --git a/ssl_stapling.t b/ssl_stapling.t deleted file mode 100644 index ee57012..0000000 --- a/ssl_stapling.t +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/perl - -# (C) Sergey Kandaurov -# (C) Nginx, Inc. - -# Tests for OCSP stapling. - -############################################################################### - -use warnings; -use strict; - -use Test::More; - -use MIME::Base64 qw/ decode_base64 /; - -BEGIN { use FindBin; chdir($FindBin::Bin); } - -use lib 'lib'; -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/)->has_daemon('openssl'); - -plan(skip_all => 'no OCSP stapling') if $t->has_module('BoringSSL'); - -$t->plan(9)->write_file_expand('nginx.conf', <<'EOF'); - -%%TEST_GLOBALS%% - -daemon off; - -events { -} - -http { - %%TEST_GLOBALS_HTTP%% - - ssl_stapling on; - ssl_trusted_certificate trusted.crt; - - ssl_ciphers DEFAULT:ECCdraft; - - server { - listen 127.0.0.1:8443 ssl; - listen 127.0.0.1:8080; - server_name localhost; - ssl_certificate end-int.crt; - ssl_certificate_key end.key; - } - server { - listen 127.0.0.1:8453 ssl; - listen 127.0.0.1:8090; - server_name localhost; - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - } - - server { - listen 127.0.0.1:8444 ssl; - server_name localhost; - - ssl_stapling_responder http://127.0.0.1:8081/; - ssl_certificate end-int.crt; - ssl_certificate_key end.key; - } - - server { - listen 127.0.0.1:8454 ssl; - server_name localhost; - - ssl_stapling_responder http://127.0.0.1:8081/; - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - } - - server { - listen 127.0.0.1:8445 ssl; - server_name localhost; - - ssl_stapling_verify on; - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - } - - server { - listen 127.0.0.1:8446 ssl; - server_name localhost; - - ssl_certificate ec-end.crt; - ssl_certificate_key ec-end.key; - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - } - - server { - listen 127.0.0.1:8447 ssl; - server_name localhost; - - ssl_certificate end-int.crt; - ssl_certificate_key end.key; - - ssl_stapling_file %%TESTDIR%%/resp.der; - ssl_certificate end-int.crt; - ssl_certificate_key end.key; - } - - server { - listen 127.0.0.1:8448 ssl; - server_name localhost; - - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - - ssl_stapling_file %%TESTDIR%%/ec-resp.der; - } - - server { - listen 127.0.0.1:8449 ssl; - server_name localhost; - - ssl_stapling_responder http://127.0.0.1:8080/; - ssl_certificate ec-end-int.crt; - ssl_certificate_key ec-end.key; - } -} - -EOF - -my $d = $t->testdir(); -my $p = port(8081); - -$t->write_file('openssl.conf', <write_file('ca.conf', <>$d/openssl.out 2>&1") == 0 - or die "Can't create certificate for $name: $!\n"; -} - -foreach my $name ('int', 'end') { - system("openssl req -new " - . "-config $d/openssl.conf -subj /CN=$name/ " - . "-out $d/$name.csr -keyout $d/$name.key " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create certificate for $name: $!\n"; -} - -foreach my $name ('ec-end') { - system("openssl ecparam -genkey -out $d/$name.key -name prime256v1 " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create EC param: $!\n"; - system("openssl req -new -key $d/$name.key " - . "-config $d/openssl.conf -subj /CN=$name/ " - . "-out $d/$name.csr " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create certificate for $name: $!\n"; -} - -$t->write_file('certserial', '1000'); -$t->write_file('certindex', ''); - -system("openssl ca -batch -config $d/ca.conf " - . "-keyfile $d/root.key -cert $d/root.crt " - . "-subj /CN=int/ -in $d/int.csr -out $d/int.crt " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't sign certificate for int: $!\n"; - -system("openssl ca -batch -config $d/ca.conf " - . "-keyfile $d/int.key -cert $d/int.crt " - . "-subj /CN=ec-end/ -in $d/ec-end.csr -out $d/ec-end.crt " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't sign certificate for ec-end: $!\n"; - -system("openssl ca -batch -config $d/ca.conf " - . "-keyfile $d/int.key -cert $d/int.crt " - . "-subj /CN=end/ -in $d/end.csr -out $d/end.crt " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't sign certificate for end: $!\n"; - -# RFC 6960, serialNumber - -system("openssl x509 -in $d/end.crt -serial -noout " - . ">>$d/serial 2>>$d/openssl.out") == 0 - or die "Can't obtain serial for end: $!\n"; - -my $serial = pack("n2", 0x0202, hex $1) if $t->read_file('serial') =~ /(\d+)/; - -system("openssl ca -config $d/ca.conf -revoke $d/end.crt " - . "-keyfile $d/root.key -cert $d/root.crt " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't revoke end.crt: $!\n"; - -system("openssl ocsp -issuer $d/int.crt -cert $d/end.crt " - . "-reqout $d/req.der >>$d/openssl.out 2>&1") == 0 - or die "Can't create OCSP request: $!\n"; - -system("openssl ocsp -index $d/certindex -CA $d/int.crt " - . "-rsigner $d/root.crt -rkey $d/root.key " - . "-reqin $d/req.der -respout $d/resp.der -ndays 1 " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create OCSP response: $!\n"; - -system("openssl ocsp -issuer $d/int.crt -cert $d/ec-end.crt " - . "-reqout $d/ec-req.der >>$d/openssl.out 2>&1") == 0 - or die "Can't create EC OCSP request: $!\n"; - -system("openssl ocsp -index $d/certindex -CA $d/int.crt " - . "-rsigner $d/root.crt -rkey $d/root.key " - . "-reqin $d/ec-req.der -respout $d/ec-resp.der -ndays 1 " - . ">>$d/openssl.out 2>&1") == 0 - or die "Can't create EC OCSP response: $!\n"; - -$t->write_file('trusted.crt', - $t->read_file('int.crt') . $t->read_file('root.crt')); -$t->write_file('end-int.crt', - $t->read_file('end.crt') . $t->read_file('int.crt')); -$t->write_file('ec-end-int.crt', - $t->read_file('ec-end.crt') . $t->read_file('int.crt')); - -$t->run_daemon(\&http_daemon, $t); -$t->run(); - -$t->waitforsocket("127.0.0.1:" . port(8081)); - -############################################################################### - -my $version = get_version(); - -staple(8443, 'RSA'); -staple(8453, 'ECDSA'); -staple(8444, 'RSA'); -staple(8454, 'ECDSA'); -staple(8445, 'ECDSA'); -staple(8446, 'ECDSA'); -staple(8449, 'ECDSA'); - -sleep 1; - -ok(!staple(8443, 'RSA'), 'staple revoked'); -ok(staple(8453, 'ECDSA'), 'staple success'); - -ok(!staple(8444, 'RSA'), 'responder revoked'); -ok(staple(8454, 'ECDSA'), 'responder success'); - -ok(!staple(8445, 'ECDSA'), 'verify - root not trusted'); - -ok(staple(8446, 'ECDSA', "$d/int.crt"), 'cert store'); - -is(staple(8447, 'RSA'), '1 1', 'file revoked'); -is(staple(8448, 'ECDSA'), '1 0', 'file success'); - -ok(!staple(8449, 'ECDSA'), 'ocsp error'); - -############################################################################### - -sub staple { - my ($port, $ciphers, $ca) = @_; - my (@resp); - - my $staple_cb = sub { - my ($ssl, $resp) = @_; - push @resp, !!$resp; - return 1 unless $resp; - 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: $@"; }; - - my @res = Net::SSLeay::OCSP_response_results($resp, $certid); - 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); - }; - 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"); - } - - 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 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 http_daemon { - my ($t) = shift; - my $server = IO::Socket::INET->new( - Proto => 'tcp', - LocalHost => "127.0.0.1:" . port(8081), - Listen => 5, - Reuse => 1 - ) - or die "Can't create listening socket: $!\n"; - - local $SIG{PIPE} = 'IGNORE'; - - while (my $client = $server->accept()) { - $client->autoflush(1); - - my $headers = ''; - my $uri = ''; - - while (<$client>) { - $headers .= $_; - last if (/^\x0d?\x0a?$/); - } - - $uri = $1 if $headers =~ /^\S+\s+\/([^ ]+)\s+HTTP/i; - next unless $uri; - - $uri =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; - my $req = decode_base64($uri); - my $resp = index($req, $serial) > 0 ? 'resp' : 'ec-resp'; - - # ocsp dummy handler - - select undef, undef, undef, 0.02; - - $headers = <<"EOF"; -HTTP/1.1 200 OK -Connection: close -Content-Type: application/ocsp-response - -EOF - - print $client $headers . $t->read_file("$resp.der"); - } -} - -############################################################################### diff --git a/ssl_stapling.t.patch b/ssl_stapling.t.patch new file mode 100644 index 0000000..debbe14 --- /dev/null +++ b/ssl_stapling.t.patch @@ -0,0 +1,117 @@ +commit 76a0d0fe158ba0bc2d9a71ef3bd8ff52949a10a1 +Author: Juliusz Sosinowicz +Date: Thu Oct 24 11:45:49 2019 +0200 + + different ports for different certs + +diff --git a/ssl_stapling.t b/ssl_stapling.t +index d5b8ff3..ee57012 100644 +--- a/ssl_stapling.t ++++ b/ssl_stapling.t +@@ -53,18 +53,21 @@ http { + ssl_stapling on; + ssl_trusted_certificate trusted.crt; + +- ssl_certificate ec-end-int.crt; +- ssl_certificate_key ec-end.key; +- +- ssl_certificate end-int.crt; +- ssl_certificate_key end.key; +- + ssl_ciphers DEFAULT:ECCdraft; + + server { + listen 127.0.0.1:8443 ssl; + listen 127.0.0.1:8080; + server_name localhost; ++ ssl_certificate end-int.crt; ++ ssl_certificate_key end.key; ++ } ++ server { ++ listen 127.0.0.1:8453 ssl; ++ listen 127.0.0.1:8090; ++ server_name localhost; ++ ssl_certificate ec-end-int.crt; ++ ssl_certificate_key ec-end.key; + } + + server { +@@ -72,6 +75,17 @@ http { + server_name localhost; + + ssl_stapling_responder http://127.0.0.1:8081/; ++ ssl_certificate end-int.crt; ++ ssl_certificate_key end.key; ++ } ++ ++ server { ++ listen 127.0.0.1:8454 ssl; ++ server_name localhost; ++ ++ ssl_stapling_responder http://127.0.0.1:8081/; ++ ssl_certificate ec-end-int.crt; ++ ssl_certificate_key ec-end.key; + } + + server { +@@ -79,6 +93,8 @@ http { + server_name localhost; + + ssl_stapling_verify on; ++ ssl_certificate ec-end-int.crt; ++ ssl_certificate_key ec-end.key; + } + + server { +@@ -87,6 +103,8 @@ http { + + ssl_certificate ec-end.crt; + ssl_certificate_key ec-end.key; ++ ssl_certificate ec-end-int.crt; ++ ssl_certificate_key ec-end.key; + } + + server { +@@ -97,6 +115,8 @@ http { + ssl_certificate_key end.key; + + ssl_stapling_file %%TESTDIR%%/resp.der; ++ ssl_certificate end-int.crt; ++ ssl_certificate_key end.key; + } + + server { +@@ -114,6 +134,8 @@ http { + server_name localhost; + + ssl_stapling_responder http://127.0.0.1:8080/; ++ ssl_certificate ec-end-int.crt; ++ ssl_certificate_key ec-end.key; + } + } + +@@ -249,9 +271,9 @@ $t->waitforsocket("127.0.0.1:" . port(8081)); + my $version = get_version(); + + staple(8443, 'RSA'); +-staple(8443, 'ECDSA'); ++staple(8453, 'ECDSA'); + staple(8444, 'RSA'); +-staple(8444, 'ECDSA'); ++staple(8454, 'ECDSA'); + staple(8445, 'ECDSA'); + staple(8446, 'ECDSA'); + staple(8449, 'ECDSA'); +@@ -259,10 +281,10 @@ staple(8449, 'ECDSA'); + sleep 1; + + ok(!staple(8443, 'RSA'), 'staple revoked'); +-ok(staple(8443, 'ECDSA'), 'staple success'); ++ok(staple(8453, 'ECDSA'), 'staple success'); + + ok(!staple(8444, 'RSA'), 'responder revoked'); +-ok(staple(8444, 'ECDSA'), 'responder success'); ++ok(staple(8454, 'ECDSA'), 'responder success'); + + ok(!staple(8445, 'ECDSA'), 'verify - root not trusted'); +