comparison ssl_verify_depth.t @ 1610:bad6aa24ec10

Tests: reworked ssl_verify_depth tests. Full matrix of various verify depths and chains is now tested. Incompatible behaviour of OpenSSL 1.1.0+, which now limits the total length of a chain instead of maximum number of signatures checked, is explained in the comments. Attempts to incorrectly use client-provided intermediate certificates, introduced in aa5a61d1254b, are removed.
author Maxim Dounin <mdounin@mdounin.ru>
date Tue, 17 Nov 2020 06:53:45 +0300
parents aa5a61d1254b
children b28f88e352dd
comparison
equal deleted inserted replaced
1609:f3ba4c74de31 1610:bad6aa24ec10
26 plan(skip_all => 'IO::Socket::SSL not installed') if $@; 26 plan(skip_all => 'IO::Socket::SSL not installed') if $@;
27 eval { IO::Socket::SSL::SSL_VERIFY_NONE(); }; 27 eval { IO::Socket::SSL::SSL_VERIFY_NONE(); };
28 plan(skip_all => 'IO::Socket::SSL too old') if $@; 28 plan(skip_all => 'IO::Socket::SSL too old') if $@;
29 29
30 my $t = Test::Nginx->new()->has(qw/http http_ssl/) 30 my $t = Test::Nginx->new()->has(qw/http http_ssl/)
31 ->has_daemon('openssl')->plan(2); 31 ->has_daemon('openssl')->plan(9);
32 32
33 $t->write_file_expand('nginx.conf', <<'EOF'); 33 $t->write_file_expand('nginx.conf', <<'EOF');
34 34
35 %%TEST_GLOBALS%% 35 %%TEST_GLOBALS%%
36 36
40 } 40 }
41 41
42 http { 42 http {
43 %%TEST_GLOBALS_HTTP%% 43 %%TEST_GLOBALS_HTTP%%
44 44
45 ssl_certificate_key localhost.key;
46 ssl_certificate localhost.crt; 45 ssl_certificate localhost.crt;
46 ssl_certificate_key localhost.key;
47 47
48 ssl_verify_client on; 48 ssl_verify_client on;
49 ssl_client_certificate root.crt; 49 ssl_client_certificate root-int.crt;
50 50
51 add_header X-Client $ssl_client_s_dn always;
51 add_header X-Verify $ssl_client_verify always; 52 add_header X-Verify $ssl_client_verify always;
52 53
53 server { 54 server {
54 listen 127.0.0.1:8080 ssl; 55 listen 127.0.0.1:8080 ssl;
55 server_name localhost; 56 server_name localhost;
56 ssl_verify_depth 3; 57 ssl_verify_depth 0;
57 } 58 }
58 59
59 server { 60 server {
60 listen 127.0.0.1:8081 ssl; 61 listen 127.0.0.1:8081 ssl;
61 server_name localhost; 62 server_name localhost;
63 ssl_verify_depth 1;
64 }
65
66 server {
67 listen 127.0.0.1:8082 ssl;
68 server_name localhost;
69 ssl_verify_depth 2;
62 } 70 }
63 } 71 }
64 72
65 EOF 73 EOF
66 74
100 . "-out $d/$name.crt -keyout $d/$name.key " 108 . "-out $d/$name.crt -keyout $d/$name.key "
101 . ">>$d/openssl.out 2>&1") == 0 109 . ">>$d/openssl.out 2>&1") == 0
102 or die "Can't create certificate for $name: $!\n"; 110 or die "Can't create certificate for $name: $!\n";
103 } 111 }
104 112
105 foreach my $name ('int', 'int2', 'end') { 113 foreach my $name ('int', 'end') {
106 system("openssl req -new " 114 system("openssl req -new "
107 . "-config $d/openssl.conf -subj /CN=$name/ " 115 . "-config $d/openssl.conf -subj /CN=$name/ "
108 . "-out $d/$name.csr -keyout $d/$name.key " 116 . "-out $d/$name.csr -keyout $d/$name.key "
109 . ">>$d/openssl.out 2>&1") == 0 117 . ">>$d/openssl.out 2>&1") == 0
110 or die "Can't create certificate for $name: $!\n"; 118 or die "Can't create certificate for $name: $!\n";
119 . ">>$d/openssl.out 2>&1") == 0 127 . ">>$d/openssl.out 2>&1") == 0
120 or die "Can't sign certificate for int: $!\n"; 128 or die "Can't sign certificate for int: $!\n";
121 129
122 system("openssl ca -batch -config $d/ca.conf " 130 system("openssl ca -batch -config $d/ca.conf "
123 . "-keyfile $d/int.key -cert $d/int.crt " 131 . "-keyfile $d/int.key -cert $d/int.crt "
124 . "-subj /CN=int2/ -in $d/int2.csr -out $d/int2.crt "
125 . ">>$d/openssl.out 2>&1") == 0
126 or die "Can't sign certificate for int2: $!\n";
127
128 system("openssl ca -batch -config $d/ca.conf "
129 . "-keyfile $d/int2.key -cert $d/int2.crt "
130 . "-subj /CN=end/ -in $d/end.csr -out $d/end.crt " 132 . "-subj /CN=end/ -in $d/end.csr -out $d/end.crt "
131 . ">>$d/openssl.out 2>&1") == 0 133 . ">>$d/openssl.out 2>&1") == 0
132 or die "Can't sign certificate for end: $!\n"; 134 or die "Can't sign certificate for end: $!\n";
133 135
134 $t->write_file('client.key', $t->read_file('end.key') . 136 $t->write_file('root-int.crt', $t->read_file('root.crt')
135 $t->read_file('int.key') . $t->read_file('int2.key')); 137 . $t->read_file('int.crt'));
136 $t->write_file('client.crt', $t->read_file('end.crt') .
137 $t->read_file('int.crt') . $t->read_file('int2.crt'));
138 138
139 $t->write_file('t', ''); 139 $t->write_file('t', '');
140 $t->run(); 140 $t->run();
141 141
142 ############################################################################### 142 ###############################################################################
143 143
144 like(get(8080, 'client'), qr/SUCCESS/, 'verify depth'); 144 # with verify depth 0, only self-signed certificates should
145 like(get(8081, 'client'), qr/FAILED/, 'verify depth limited'); 145 # be allowed
146
147 # OpenSSL 1.1.0+ instead limits the number of intermediate certs allowed;
148 # as a result, it is not possible to limit certificate checking
149 # to self-signed certificates only when using OpenSSL 1.1.0+
150
151 like(get(8080, 'root'), qr/SUCCESS/, 'verify depth 0 - root');
152 like(get(8080, 'int'), qr/FAI|SUC/, 'verify depth 0 - no int');
153 like(get(8080, 'end'), qr/FAILED/, 'verify depth 0 - no end');
154
155 # with verify depth 1 (the default), one signature is
156 # expected to be checked, so certificates directly signed
157 # by the root cert are allowed, but nothing more
158
159 # OpenSSL 1.1.0+ instead limits the number of intermediate certs allowed;
160 # so with depth 1 it is possible to validate not only directly signed
161 # certificates, but also chains with one intermediate certificate
162
163 like(get(8081, 'root'), qr/SUCCESS/, 'verify depth 1 - root');
164 like(get(8081, 'int'), qr/SUCCESS/, 'verify depth 1 - int');
165 like(get(8081, 'end'), qr/FAI|SUC/, 'verify depth 1 - no end');
166
167 # with verify depth 2 it is also possible to validate up to two signatures,
168 # so chains with one intermediate certificate are allowed
169
170 like(get(8082, 'root'), qr/SUCCESS/, 'verify depth 2 - root');
171 like(get(8082, 'int'), qr/SUCCESS/, 'verify depth 2 - int');
172 like(get(8082, 'end'), qr/SUCCESS/, 'verify depth 2 - end');
146 173
147 ############################################################################### 174 ###############################################################################
148 175
149 sub get { 176 sub get {
150 my ($port, $cert) = @_; 177 my ($port, $cert) = @_;
151 my $s = get_ssl_socket($port, $cert) or return; 178 my $s = get_ssl_socket($port, $cert) or return;
152 http_get('/t', socket => $s); 179 http_get("/t?$cert", socket => $s);
153 } 180 }
154 181
155 sub get_ssl_socket { 182 sub get_ssl_socket {
156 my ($port, $cert) = @_; 183 my ($port, $cert) = @_;
157 my ($s); 184 my ($s);