comparison ssl_stapling.t @ 1330:b82ed2061f65

Tests: OCSP stapling tests.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 31 May 2018 00:29:22 +0300
parents
children 73a9504ae6fd
comparison
equal deleted inserted replaced
1329:0f2dd1f239ba 1330:b82ed2061f65
1 #!/usr/bin/perl
2
3 # (C) Sergey Kandaurov
4 # (C) Nginx, Inc.
5
6 # Tests for OCSP stapling.
7
8 ###############################################################################
9
10 use warnings;
11 use strict;
12
13 use Test::More;
14
15 use MIME::Base64 qw/ decode_base64 /;
16
17 BEGIN { use FindBin; chdir($FindBin::Bin); }
18
19 use lib 'lib';
20 use Test::Nginx;
21
22 ###############################################################################
23
24 select STDERR; $| = 1;
25 select STDOUT; $| = 1;
26
27 eval { require IO::Socket::SSL; };
28 plan(skip_all => 'IO::Socket::SSL not installed') if $@;
29 eval { IO::Socket::SSL->can_ocsp() or die; };
30 plan(skip_all => 'IO::Socket::SSL with OCSP support required') if $@;
31
32 my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl')
33 ->plan(9)->write_file_expand('nginx.conf', <<'EOF');
34
35 %%TEST_GLOBALS%%
36
37 daemon off;
38
39 events {
40 }
41
42 http {
43 %%TEST_GLOBALS_HTTP%%
44
45 ssl_stapling on;
46 ssl_trusted_certificate trusted.crt;
47
48 ssl_certificate ec-end-int.crt;
49 ssl_certificate_key ec-end.key;
50
51 ssl_certificate end-int.crt;
52 ssl_certificate_key end.key;
53
54 server {
55 listen 127.0.0.1:8443 ssl;
56 listen 127.0.0.1:8080;
57 server_name localhost;
58 }
59
60 server {
61 listen 127.0.0.1:8444 ssl;
62 server_name localhost;
63
64 ssl_stapling_responder http://127.0.0.1:8081/;
65 }
66
67 server {
68 listen 127.0.0.1:8445 ssl;
69 server_name localhost;
70
71 ssl_stapling_verify on;
72 }
73
74 server {
75 listen 127.0.0.1:8446 ssl;
76 server_name localhost;
77
78 ssl_certificate ec-end.crt;
79 ssl_certificate_key ec-end.key;
80 }
81
82 server {
83 listen 127.0.0.1:8447 ssl;
84 server_name localhost;
85
86 ssl_certificate end-int.crt;
87 ssl_certificate_key end.key;
88
89 ssl_stapling_file %%TESTDIR%%/resp.der;
90 }
91
92 server {
93 listen 127.0.0.1:8448 ssl;
94 server_name localhost;
95
96 ssl_certificate ec-end-int.crt;
97 ssl_certificate_key ec-end.key;
98
99 ssl_stapling_file %%TESTDIR%%/ec-resp.der;
100 }
101
102 server {
103 listen 127.0.0.1:8449 ssl;
104 server_name localhost;
105
106 ssl_stapling_responder http://127.0.0.1:8080/;
107 }
108 }
109
110 EOF
111
112 my $d = $t->testdir();
113 my $p = port(8081);
114
115 $t->write_file('openssl.conf', <<EOF);
116 [ req ]
117 default_bits = 1024
118 encrypt_key = no
119 distinguished_name = req_distinguished_name
120 [ req_distinguished_name ]
121 EOF
122
123 $t->write_file('ca.conf', <<EOF);
124 [ ca ]
125 default_ca = myca
126
127 [ myca ]
128 new_certs_dir = $d
129 database = $d/certindex
130 default_md = sha1
131 policy = myca_policy
132 serial = $d/certserial
133 default_days = 1
134 x509_extensions = myca_extensions
135
136 [ myca_policy ]
137 commonName = supplied
138
139 [ myca_extensions ]
140 basicConstraints = critical,CA:TRUE
141 authorityInfoAccess = OCSP;URI:http://127.0.0.1:$p
142 EOF
143
144 foreach my $name ('root') {
145 system('openssl req -x509 -new '
146 . "-config $d/openssl.conf -subj /CN=$name/ "
147 . "-out $d/$name.crt -keyout $d/$name.key "
148 . ">>$d/openssl.out 2>&1") == 0
149 or die "Can't create certificate for $name: $!\n";
150 }
151
152 foreach my $name ('int', 'end') {
153 system("openssl req -new "
154 . "-config $d/openssl.conf -subj /CN=$name/ "
155 . "-out $d/$name.csr -keyout $d/$name.key "
156 . ">>$d/openssl.out 2>&1") == 0
157 or die "Can't create certificate for $name: $!\n";
158 }
159
160 foreach my $name ('ec-end') {
161 system("openssl ecparam -genkey -out $d/$name.key -name prime256v1 "
162 . ">>$d/openssl.out 2>&1") == 0
163 or die "Can't create EC param: $!\n";
164 system("openssl req -new -key $d/$name.key "
165 . "-config $d/openssl.conf -subj /CN=$name/ "
166 . "-out $d/$name.csr "
167 . ">>$d/openssl.out 2>&1") == 0
168 or die "Can't create certificate for $name: $!\n";
169 }
170
171 $t->write_file('certserial', '1000');
172 $t->write_file('certindex', '');
173
174 system("openssl ca -batch -config $d/ca.conf "
175 . "-keyfile $d/root.key -cert $d/root.crt "
176 . "-subj /CN=int/ -in $d/int.csr -out $d/int.crt "
177 . ">>$d/openssl.out 2>&1") == 0
178 or die "Can't sign certificate for int: $!\n";
179
180 system("openssl ca -batch -config $d/ca.conf "
181 . "-keyfile $d/int.key -cert $d/int.crt "
182 . "-subj /CN=ec-end/ -in $d/ec-end.csr -out $d/ec-end.crt "
183 . ">>$d/openssl.out 2>&1") == 0
184 or die "Can't sign certificate for ec-end: $!\n";
185
186 system("openssl ca -batch -config $d/ca.conf "
187 . "-keyfile $d/int.key -cert $d/int.crt "
188 . "-subj /CN=end/ -in $d/end.csr -out $d/end.crt "
189 . ">>$d/openssl.out 2>&1") == 0
190 or die "Can't sign certificate for end: $!\n";
191
192 # RFC 6960, serialNumber
193
194 system("openssl x509 -in $d/end.crt -serial -noout "
195 . ">>$d/serial 2>>$d/openssl.out") == 0
196 or die "Can't obtain serial for end: $!\n";
197
198 my $serial = pack("n2", 0x0202, hex $1) if $t->read_file('serial') =~ /(\d+)/;
199
200 system("openssl ca -config $d/ca.conf -revoke $d/end.crt "
201 . "-keyfile $d/root.key -cert $d/root.crt "
202 . ">>$d/openssl.out 2>&1") == 0
203 or die "Can't revoke end.crt: $!\n";
204
205 system("openssl ocsp -issuer $d/int.crt -cert $d/end.crt "
206 . "-reqout $d/req.der >>$d/openssl.out 2>&1") == 0
207 or die "Can't create OCSP request: $!\n";
208
209 system("openssl ocsp -index $d/certindex -CA $d/int.crt "
210 . "-rsigner $d/root.crt -rkey $d/root.key "
211 . "-reqin $d/req.der -respout $d/resp.der -ndays 1 "
212 . ">>$d/openssl.out 2>&1") == 0
213 or die "Can't create OCSP response: $!\n";
214
215 system("openssl ocsp -issuer $d/int.crt -cert $d/ec-end.crt "
216 . "-reqout $d/ec-req.der >>$d/openssl.out 2>&1") == 0
217 or die "Can't create EC OCSP request: $!\n";
218
219 system("openssl ocsp -index $d/certindex -CA $d/int.crt "
220 . "-rsigner $d/root.crt -rkey $d/root.key "
221 . "-reqin $d/ec-req.der -respout $d/ec-resp.der -ndays 1 "
222 . ">>$d/openssl.out 2>&1") == 0
223 or die "Can't create EC OCSP response: $!\n";
224
225 $t->write_file('trusted.crt',
226 $t->read_file('int.crt') . $t->read_file('root.crt'));
227 $t->write_file('end-int.crt',
228 $t->read_file('end.crt') . $t->read_file('int.crt'));
229 $t->write_file('ec-end-int.crt',
230 $t->read_file('ec-end.crt') . $t->read_file('int.crt'));
231
232 $t->run_daemon(\&http_daemon, $t);
233 $t->run();
234
235 $t->waitforsocket("127.0.0.1:" . port(8081));
236
237 ###############################################################################
238
239 staple(8443, 'RSA');
240 staple(8443, 'ECDSA');
241 staple(8444, 'RSA');
242 staple(8444, 'ECDSA');
243 staple(8445, 'ECDSA');
244 staple(8446, 'ECDSA');
245 staple(8449, 'ECDSA');
246
247 sleep 1;
248
249 ok(!staple(8443, 'RSA'), 'staple revoked');
250 ok(staple(8443, 'ECDSA'), 'staple success');
251
252 ok(!staple(8444, 'RSA'), 'responder revoked');
253 ok(staple(8444, 'ECDSA'), 'responder success');
254
255 ok(!staple(8445, 'ECDSA'), 'verify - root not trusted');
256
257 ok(staple(8446, 'ECDSA', "$d/int.crt"), 'cert store');
258
259 is(staple(8447, 'RSA'), '1 1', 'file revoked');
260 is(staple(8448, 'ECDSA'), '1 0', 'file success');
261
262 ok(!staple(8449, 'ECDSA'), 'ocsp error');
263
264 ###############################################################################
265
266 sub staple {
267 my ($port, $ciphers, $ca) = @_;
268 my (@resp);
269
270 my $staple_cb = sub {
271 my ($ssl, $resp) = @_;
272 push @resp, !!$resp;
273 return 1 unless $resp;
274 my $obj = $ssl->_get_ssl_object;
275 my $cert = Net::SSLeay::get_peer_certificate($obj);
276 my $certid = eval { Net::SSLeay::OCSP_cert2ids($obj, $cert) }
277 or do { die "no OCSP_CERTID for certificate: $@"; };
278
279 my @res = Net::SSLeay::OCSP_response_results($resp, $certid);
280 push @resp, $res[0][2]->{'statusType'};
281 };
282
283 eval {
284 local $SIG{ALRM} = sub { die "timeout\n" };
285 local $SIG{PIPE} = sub { die "sigpipe\n" };
286 alarm(2);
287 IO::Socket::SSL->new(
288 Proto => 'tcp',
289 PeerAddr => '127.0.0.1',
290 PeerPort => port($port),
291 SSL_cipher_list => $ciphers,
292 SSL_ca_file => $ca,
293 SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(),
294 SSL_ocsp_mode => IO::Socket::SSL::SSL_OCSP_TRY_STAPLE(),
295 SSL_ocsp_staple_callback => $staple_cb,
296 SSL_error_trap => sub { die $_[1] }
297 );
298 alarm(0);
299 };
300 alarm(0);
301
302 if ($@) {
303 log_in("died: $@");
304 return undef;
305 }
306
307 return join ' ', @resp;
308 }
309
310 ###############################################################################
311
312 sub http_daemon {
313 my ($t) = shift;
314 my $server = IO::Socket::INET->new(
315 Proto => 'tcp',
316 LocalHost => "127.0.0.1:" . port(8081),
317 Listen => 5,
318 Reuse => 1
319 )
320 or die "Can't create listening socket: $!\n";
321
322 local $SIG{PIPE} = 'IGNORE';
323
324 while (my $client = $server->accept()) {
325 $client->autoflush(1);
326
327 my $headers = '';
328 my $uri = '';
329
330 while (<$client>) {
331 $headers .= $_;
332 last if (/^\x0d?\x0a?$/);
333 }
334
335 $uri = $1 if $headers =~ /^\S+\s+\/([^ ]+)\s+HTTP/i;
336 next unless $uri;
337
338 $uri =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
339 my $req = decode_base64($uri);
340 my $resp = index($req, $serial) > 0 ? 'resp' : 'ec-resp';
341
342 # ocsp dummy handler
343
344 select undef, undef, undef, 0.02;
345
346 $headers = <<"EOF";
347 HTTP/1.1 200 OK
348 Connection: close
349 Content-Type: application/ocsp-response
350
351 EOF
352
353 print $client $headers . $t->read_file("$resp.der");
354 }
355 }
356
357 ###############################################################################