view ssl_verify_client.t @ 1260:eadd24ccfda1

Tests: postponed startup in certain ssl certificate tests on win32. At least, some win32 hosts exhibit a round-off error or some such in the notBefore field of the certificate generated before starting nginx, such that it can be set to the value one second ahead of the current time. This manifests in spurious test failures due to certificate verify error with a failure reason "certificate is not yet valid".
author Sergey Kandaurov <pluknet@nginx.com>
date Tue, 12 Dec 2017 12:53:53 +0300
parents 0af58b78df35
children 1d7c87dba788
line wrap: on
line source

#!/usr/bin/perl

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

# Tests for http ssl module, ssl_verify_client.

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

use warnings;
use strict;

use Test::More;

use Socket qw/ :DEFAULT CRLF /;

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();
};
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/)
	->has_daemon('openssl')->plan(10);

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

%%TEST_GLOBALS%%

daemon off;

events {
}

http {
    %%TEST_GLOBALS_HTTP%%

    add_header X-Verify x$ssl_client_verify:${ssl_client_cert}x;

    ssl_certificate_key 1.example.com.key;
    ssl_certificate 1.example.com.crt;

    server {
        listen       127.0.0.1:8080;
        server_name  localhost;

        ssl_verify_client on;
        ssl_client_certificate 2.example.com.crt;
    }

    server {
        listen       127.0.0.1:8081 ssl;
        server_name  on;

        ssl_verify_client on;
        ssl_client_certificate 2.example.com.crt;
    }

    server {
        listen       127.0.0.1:8081 ssl;
        server_name  optional;

        ssl_verify_client optional;
        ssl_client_certificate 2.example.com.crt;
        ssl_trusted_certificate 3.example.com.crt;
    }

    server {
        listen       127.0.0.1:8081 ssl;
        server_name  optional_no_ca;

        ssl_verify_client optional_no_ca;
        ssl_client_certificate 2.example.com.crt;
    }
}

EOF

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

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

foreach my $name ('1.example.com', '2.example.com', '3.example.com') {
	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";
}

sleep 1 if $^O eq 'MSWin32';

$t->write_file('t', 'SEE-THIS');

$t->run();

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

like(http_get('/t'), qr/x:x/, 'plain connection');
like(get('on'), qr/400 Bad Request/, 'no cert');
like(get('optional'), qr/NONE:x/, 'no optional cert');
like(get('optional', '1.example.com'), qr/400 Bad/, 'bad optional cert');
like(get('optional_no_ca', '1.example.com'), qr/FAILED.*BEGIN/,
	'bad optional_no_ca cert');

like(get('localhost', '2.example.com'), qr/SUCCESS.*BEGIN/, 'good cert');
like(get('optional', '2.example.com'), qr/SUCCESS.*BEGI/, 'good cert optional');
like(get('optional', '3.example.com'), qr/SUCCESS.*BEGIN/, 'good cert trusted');

SKIP: {
skip 'Net::SSLeay version >= 1.36 required', 1 if $Net::SSLeay::VERSION < 1.36;

my $ca = join ' ', get('optional', '3.example.com');
is($ca, '/CN=2.example.com', 'no trusted sent');

}

like(get('optional', undef, 'localhost'), qr/421 Misdirected/, 'misdirected');

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

sub get {
	my ($sni, $cert, $host) = @_;

	local $SIG{PIPE} = 'IGNORE';

	$host = $sni if !defined $host;

	my $dest_ip = inet_aton('127.0.0.1');
	my $dest_serv_params = sockaddr_in(port(8081), $dest_ip);

	socket(my $s, &AF_INET, &SOCK_STREAM, 0) or die "socket: $!";
	connect($s, $dest_serv_params) or die "connect: $!";

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

	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();

	my $list = Net::SSLeay::get_client_CA_list($ssl);
	my @names;
	for my $i (0 .. Net::SSLeay::sk_X509_NAME_num($list) - 1) {
		my $name = Net::SSLeay::sk_X509_NAME_value($list, $i);
		push @names, Net::SSLeay::X509_NAME_oneline($name);
	}
	return @names;
}

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