Fix syntax of cipher string
[oweals/openssl.git] / test / recipes / 70-test_sslsigalgs.t
1 #! /usr/bin/env perl
2 # Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 use strict;
10 use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
11 use OpenSSL::Test::Utils;
12 use TLSProxy::Proxy;
13
14 my $test_name = "test_sslsigalgs";
15 setup($test_name);
16
17 plan skip_all => "TLSProxy isn't usable on $^O"
18     if $^O =~ /^(VMS)$/;
19
20 plan skip_all => "$test_name needs the dynamic engine feature enabled"
21     if disabled("engine") || disabled("dynamic-engine");
22
23 plan skip_all => "$test_name needs the sock feature enabled"
24     if disabled("sock");
25
26 plan skip_all => "$test_name needs TLS1.2 or TLS1.3 enabled"
27     if disabled("tls1_2") && disabled("tls1_3");
28
29 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
30 my $proxy = TLSProxy::Proxy->new(
31     undef,
32     cmdstr(app(["openssl"]), display => 1),
33     srctop_file("apps", "server.pem"),
34     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
35 );
36
37 use constant {
38     NO_SIG_ALGS_EXT => 0,
39     EMPTY_SIG_ALGS_EXT => 1,
40     NO_KNOWN_SIG_ALGS => 2,
41     NO_PSS_SIG_ALGS => 3,
42     PSS_ONLY_SIG_ALGS => 4,
43     PURE_SIGALGS => 5,
44     COMPAT_SIGALGS => 6,
45     SIGALGS_CERT_ALL => 7,
46     SIGALGS_CERT_PKCS => 8,
47     SIGALGS_CERT_INVALID => 9,
48     UNRECOGNIZED_SIGALGS_CERT => 10,
49     UNRECOGNIZED_SIGALG => 11
50 };
51
52 #Note: Throughout this test we override the default ciphersuites where TLSv1.2
53 #      is expected to ensure that a ServerKeyExchange message is sent that uses
54 #      the sigalgs
55
56 #Test 1: Default sig algs should succeed
57 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
58 plan tests => 26;
59 ok(TLSProxy::Message->success, "Default sigalgs");
60 my $testtype;
61
62 SKIP: {
63     skip "TLSv1.3 disabled", 6 if disabled("tls1_3");
64
65     $proxy->filter(\&sigalgs_filter);
66
67     #Test 2: Sending no sig algs extension in TLSv1.3 should fail
68     $proxy->clear();
69     $testtype = NO_SIG_ALGS_EXT;
70     $proxy->start();
71     ok(TLSProxy::Message->fail, "No TLSv1.3 sigalgs");
72
73     #Test 3: Sending an empty sig algs extension in TLSv1.3 should fail
74     $proxy->clear();
75     $testtype = EMPTY_SIG_ALGS_EXT;
76     $proxy->start();
77     ok(TLSProxy::Message->fail, "Empty TLSv1.3 sigalgs");
78
79     #Test 4: Sending a list with no recognised sig algs in TLSv1.3 should fail
80     $proxy->clear();
81     $testtype = NO_KNOWN_SIG_ALGS;
82     $proxy->start();
83     ok(TLSProxy::Message->fail, "No known TLSv1.3 sigalgs");
84
85     #Test 5: Sending a sig algs list without pss for an RSA cert in TLSv1.3
86     #        should fail
87     $proxy->clear();
88     $testtype = NO_PSS_SIG_ALGS;
89     $proxy->start();
90     ok(TLSProxy::Message->fail, "No PSS TLSv1.3 sigalgs");
91
92     #Test 6: Sending only TLSv1.3 PSS sig algs in TLSv1.3 should succeed
93     #TODO(TLS1.3): Do we need to verify the cert to make sure its a PSS only
94     #cert in this case?
95     $proxy->clear();
96     $testtype = PSS_ONLY_SIG_ALGS;
97     $proxy->start();
98     ok(TLSProxy::Message->success, "PSS only sigalgs in TLSv1.3");
99
100     #Test 7: Modify the CertificateVerify sigalg from rsa_pss_rsae_sha256 to
101     #        rsa_pss_pss_sha256. This should fail because the public key OID
102     #        in the certificate is rsaEncryption and not rsassaPss
103     $proxy->filter(\&modify_cert_verify_sigalg);
104     $proxy->clear();
105     $proxy->start();
106     ok(TLSProxy::Message->fail,
107        "Mismatch between CertVerify sigalg and public key OID");
108 }
109
110 SKIP: {
111     skip "EC or TLSv1.3 disabled", 1
112         if disabled("tls1_3") || disabled("ec");
113     #Test 8: Sending a valid sig algs list but not including a sig type that
114     #        matches the certificate should fail in TLSv1.3.
115     $proxy->clear();
116     $proxy->clientflags("-sigalgs ECDSA+SHA256");
117     $proxy->filter(undef);
118     $proxy->start();
119     ok(TLSProxy::Message->fail, "No matching TLSv1.3 sigalgs");
120 }
121
122 SKIP: {
123     skip "EC, TLSv1.3 or TLSv1.2 disabled", 1
124         if disabled("tls1_2") || disabled("tls1_3") || disabled("ec");
125
126     #Test 9: Sending a full list of TLSv1.3 sig algs but negotiating TLSv1.2
127     #        should succeed
128     $proxy->clear();
129     $proxy->serverflags("-no_tls1_3");
130     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
131     $proxy->filter(undef);
132     $proxy->start();
133     ok(TLSProxy::Message->success, "TLSv1.3 client TLSv1.2 server");
134 }
135
136 SKIP: {
137     skip "EC or TLSv1.2 disabled", 10 if disabled("tls1_2") || disabled("ec");
138
139     $proxy->filter(\&sigalgs_filter);
140
141     #Test 10: Sending no sig algs extension in TLSv1.2 should succeed at
142     #         security level 1
143     $proxy->clear();
144     $testtype = NO_SIG_ALGS_EXT;
145     $proxy->clientflags("-no_tls1_3 -cipher DEFAULT:\@SECLEVEL=1");
146     $proxy->ciphers("ECDHE-RSA-AES128-SHA:\@SECLEVEL=1");
147     $proxy->start();
148     ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs seclevel 1");
149
150     #Test 11: Sending no sig algs extension in TLSv1.2 should fail at security
151     #         level 2 since it will try to use SHA1. Testing client at level 1,
152     #         server level 2.
153     $proxy->clear();
154     $testtype = NO_SIG_ALGS_EXT;
155     $proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=1");
156     $proxy->ciphers("DEFAULT:\@SECLEVEL=2");
157     $proxy->start();
158     ok(TLSProxy::Message->fail, "No TLSv1.2 sigalgs server seclevel 2");
159
160     #Test 12: Sending no sig algs extension in TLSv1.2 should fail at security
161     #         level 2 since it will try to use SHA1. Testing client at level 2,
162     #         server level 1.
163     $proxy->clear();
164     $testtype = NO_SIG_ALGS_EXT;
165     $proxy->clientflags("-tls1_2 -cipher DEFAULT:\@SECLEVEL=2");
166     $proxy->ciphers("DEFAULT:\@SECLEVEL=1");
167     $proxy->start();
168     ok(TLSProxy::Message->fail, "No TLSv1.2 sigalgs client seclevel 2");
169
170     #Test 13: Sending an empty sig algs extension in TLSv1.2 should fail
171     $proxy->clear();
172     $testtype = EMPTY_SIG_ALGS_EXT;
173     $proxy->clientflags("-no_tls1_3");
174     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
175     $proxy->start();
176     ok(TLSProxy::Message->fail, "Empty TLSv1.2 sigalgs");
177
178     #Test 14: Sending a list with no recognised sig algs in TLSv1.2 should fail
179     $proxy->clear();
180     $testtype = NO_KNOWN_SIG_ALGS;
181     $proxy->clientflags("-no_tls1_3");
182     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
183     $proxy->start();
184     ok(TLSProxy::Message->fail, "No known TLSv1.3 sigalgs");
185
186     #Test 15: Sending a sig algs list without pss for an RSA cert in TLSv1.2
187     #         should succeed
188     $proxy->clear();
189     $testtype = NO_PSS_SIG_ALGS;
190     $proxy->clientflags("-no_tls1_3");
191     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
192     $proxy->start();
193     ok(TLSProxy::Message->success, "No PSS TLSv1.2 sigalgs");
194
195     #Test 16: Sending only TLSv1.3 PSS sig algs in TLSv1.2 should succeed
196     $proxy->clear();
197     $testtype = PSS_ONLY_SIG_ALGS;
198     $proxy->serverflags("-no_tls1_3");
199     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
200     $proxy->start();
201     ok(TLSProxy::Message->success, "PSS only sigalgs in TLSv1.2");
202
203     #Test 17: Responding with a sig alg we did not send in TLSv1.2 should fail
204     #         We send rsa_pkcs1_sha256 and respond with rsa_pss_rsae_sha256
205     #         TODO(TLS1.3): Add a similar test to the TLSv1.3 section above
206     #         when we have an API capable of configuring the TLSv1.3 sig algs
207     $proxy->clear();
208     $testtype = PSS_ONLY_SIG_ALGS;
209     $proxy->clientflags("-no_tls1_3 -sigalgs RSA+SHA256");
210     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
211     $proxy->start();
212     ok(TLSProxy::Message->fail, "Sigalg we did not send in TLSv1.2");
213
214     #Test 18: Sending a valid sig algs list but not including a sig type that
215     #         matches the certificate should fail in TLSv1.2
216     $proxy->clear();
217     $proxy->clientflags("-no_tls1_3 -sigalgs ECDSA+SHA256");
218     $proxy->ciphers("ECDHE-RSA-AES128-SHA");
219     $proxy->filter(undef);
220     $proxy->start();
221     ok(TLSProxy::Message->fail, "No matching TLSv1.2 sigalgs");
222     $proxy->filter(\&sigalgs_filter);
223
224     #Test 19: No sig algs extension, ECDSA cert, TLSv1.2 should succeed
225     $proxy->clear();
226     $testtype = NO_SIG_ALGS_EXT;
227     $proxy->clientflags("-no_tls1_3");
228     $proxy->serverflags("-cert " . srctop_file("test", "certs",
229                                                "server-ecdsa-cert.pem") .
230                         " -key " . srctop_file("test", "certs",
231                                                "server-ecdsa-key.pem")),
232     $proxy->ciphers("ECDHE-ECDSA-AES128-SHA");
233     $proxy->start();
234     ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs, ECDSA");
235 }
236
237 my ($dsa_status, $sha1_status, $sha224_status);
238 SKIP: {
239     skip "TLSv1.3 disabled", 2 if disabled("tls1_3") || disabled("dsa");
240     #Test 20: signature_algorithms with 1.3-only ClientHello
241     $testtype = PURE_SIGALGS;
242     $dsa_status = $sha1_status = $sha224_status = 0;
243     $proxy->clear();
244     $proxy->clientflags("-tls1_3");
245     $proxy->filter(\&modify_sigalgs_filter);
246     $proxy->start();
247     ok($dsa_status && $sha1_status && $sha224_status,
248        "DSA/SHA2 sigalg sent for 1.3-only ClientHello");
249
250     #Test 21: signature_algorithms with backwards compatible ClientHello
251     SKIP: {
252         skip "TLSv1.2 disabled", 1 if disabled("tls1_2");
253         $testtype = COMPAT_SIGALGS;
254         $dsa_status = $sha1_status = $sha224_status = 0;
255         $proxy->clear();
256         $proxy->filter(\&modify_sigalgs_filter);
257         $proxy->start();
258         ok($dsa_status && $sha1_status && $sha224_status,
259            "DSA sigalg not sent for compat ClientHello");
260    }
261 }
262
263 SKIP: {
264     skip "TLSv1.3 disabled", 3 if disabled("tls1_3");
265     #Test 22: Insert signature_algorithms_cert that match normal sigalgs
266     $testtype = SIGALGS_CERT_ALL;
267     $proxy->clear();
268     $proxy->filter(\&modify_sigalgs_cert_filter);
269     $proxy->start();
270     ok(TLSProxy::Message->success, "sigalgs_cert in TLSv1.3");
271
272     #Test 23: Insert signature_algorithms_cert that forces PKCS#1 cert
273     $testtype = SIGALGS_CERT_PKCS;
274     $proxy->clear();
275     $proxy->filter(\&modify_sigalgs_cert_filter);
276     $proxy->start();
277     ok(TLSProxy::Message->success, "sigalgs_cert in TLSv1.3 with PKCS#1 cert");
278
279     #Test 24: Insert signature_algorithms_cert that fails
280     $testtype = SIGALGS_CERT_INVALID;
281     $proxy->clear();
282     $proxy->filter(\&modify_sigalgs_cert_filter);
283     $proxy->start();
284     ok(TLSProxy::Message->fail, "No matching certificate for sigalgs_cert");
285 }
286
287 SKIP: {
288     skip "TLS 1.3 disabled", 2 if disabled("tls1_3");
289     #Test 25: Send an unrecognized signature_algorithms_cert
290     #        We should be able to skip over the unrecognized value and use a
291     #        valid one that appears later in the list.
292     $proxy->clear();
293     $proxy->filter(\&inject_unrecognized_sigalg);
294     $proxy->clientflags("-tls1_3");
295     # Use -xcert to get SSL_check_chain() to run in the cert_cb.  This is
296     # needed to trigger (e.g.) CVE-2020-1967
297     $proxy->serverflags("" .
298             " -xcert " . srctop_file("test", "certs", "servercert.pem") .
299             " -xkey " . srctop_file("test", "certs", "serverkey.pem") .
300             " -xchain " . srctop_file("test", "certs", "rootcert.pem"));
301     $testtype = UNRECOGNIZED_SIGALGS_CERT;
302     $proxy->start();
303     ok(TLSProxy::Message->success(), "Unrecognized sigalg_cert in ClientHello");
304
305     #Test 26: Send an unrecognized signature_algorithms
306     #        We should be able to skip over the unrecognized value and use a
307     #        valid one that appears later in the list.
308     $proxy->clear();
309     $proxy->filter(\&inject_unrecognized_sigalg);
310     $proxy->clientflags("-tls1_3");
311     $proxy->serverflags("" .
312             " -xcert " . srctop_file("test", "certs", "servercert.pem") .
313             " -xkey " . srctop_file("test", "certs", "serverkey.pem") .
314             " -xchain " . srctop_file("test", "certs", "rootcert.pem"));
315     $testtype = UNRECOGNIZED_SIGALG;
316     $proxy->start();
317     ok(TLSProxy::Message->success(), "Unrecognized sigalg in ClientHello");
318 }
319
320
321
322 sub sigalgs_filter
323 {
324     my $proxy = shift;
325
326     # We're only interested in the initial ClientHello
327     if ($proxy->flight != 0) {
328         return;
329     }
330
331     foreach my $message (@{$proxy->message_list}) {
332         if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
333             if ($testtype == NO_SIG_ALGS_EXT) {
334                 $message->delete_extension(TLSProxy::Message::EXT_SIG_ALGS);
335             } else {
336                 my $sigalg;
337                 if ($testtype == EMPTY_SIG_ALGS_EXT) {
338                     $sigalg = pack "C2", 0x00, 0x00;
339                 } elsif ($testtype == NO_KNOWN_SIG_ALGS) {
340                     $sigalg = pack "C4", 0x00, 0x02, 0xff, 0xff;
341                 } elsif ($testtype == NO_PSS_SIG_ALGS) {
342                     #No PSS sig algs - just send rsa_pkcs1_sha256
343                     $sigalg = pack "C4", 0x00, 0x02, 0x04, 0x01;
344                 } else {
345                     #PSS sig algs only - just send rsa_pss_rsae_sha256
346                     $sigalg = pack "C4", 0x00, 0x02, 0x08, 0x04;
347                 }
348                 $message->set_extension(TLSProxy::Message::EXT_SIG_ALGS, $sigalg);
349             }
350
351             $message->repack();
352         }
353     }
354 }
355
356 sub modify_sigalgs_filter
357 {
358     my $proxy = shift;
359
360     # We're only interested in the initial ClientHello
361     return if ($proxy->flight != 0);
362
363     foreach my $message (@{$proxy->message_list}) {
364         my $ext;
365         my @algs;
366
367         if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
368             if ($testtype == PURE_SIGALGS) {
369                 my $ok = 1;
370                 $ext = $message->extension_data->{TLSProxy::Message::EXT_SIG_ALGS};
371                 @algs = unpack('S>*', $ext);
372                 # unpack will unpack the length as well
373                 shift @algs;
374                 foreach (@algs) {
375                     if ($_ == TLSProxy::Message::SIG_ALG_DSA_SHA256
376                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA384
377                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA512
378                         || $_ == TLSProxy::Message::OSSL_SIG_ALG_DSA_SHA224
379                         || $_ == TLSProxy::Message::SIG_ALG_RSA_PKCS1_SHA1
380                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA1
381                         || $_ == TLSProxy::Message::SIG_ALG_ECDSA_SHA1) {
382                         $ok = 0;
383                     }
384                 }
385                 $sha1_status = $dsa_status = $sha224_status = 1 if ($ok);
386             } elsif ($testtype == COMPAT_SIGALGS) {
387                 $ext = $message->extension_data->{TLSProxy::Message::EXT_SIG_ALGS};
388                 @algs = unpack('S>*', $ext);
389                 # unpack will unpack the length as well
390                 shift @algs;
391                 foreach (@algs) {
392                     if ($_ == TLSProxy::Message::SIG_ALG_DSA_SHA256
393                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA384
394                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA512) {
395                         $dsa_status = 1;
396                     }
397                     if ($_ == TLSProxy::Message::SIG_ALG_RSA_PKCS1_SHA1
398                         || $_ == TLSProxy::Message::SIG_ALG_DSA_SHA1
399                         || $_ == TLSProxy::Message::SIG_ALG_ECDSA_SHA1) {
400                         $sha1_status = 1;
401                     }
402                     if ($_ == TLSProxy::Message::OSSL_SIG_ALG_RSA_PKCS1_SHA224
403                         || $_ == TLSProxy::Message::OSSL_SIG_ALG_DSA_SHA224
404                         || $_ == TLSProxy::Message::OSSL_SIG_ALG_ECDSA_SHA224) {
405                         $sha224_status = 1;
406                     }
407                 }
408             }
409         }
410     }
411 }
412
413 sub modify_sigalgs_cert_filter
414 {
415     my $proxy = shift;
416
417     # We're only interested in the initial ClientHello
418     if ($proxy->flight != 0) {
419         return;
420     }
421
422     foreach my $message (@{$proxy->message_list}) {
423         if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
424             my $sigs;
425             # two byte length at front of sigs, then two-byte sigschemes
426             if ($testtype == SIGALGS_CERT_ALL) {
427                 $sigs = pack "C26", 0x00, 0x18,
428                              # rsa_pkcs_sha{256,512}  rsa_pss_rsae_sha{256,512}
429                              0x04, 0x01,  0x06, 0x01,  0x08, 0x04,  0x08, 0x06,
430                              # ed25518    ed448        rsa_pss_pss_sha{256,512}
431                              0x08, 0x07,  0x08, 0x08,  0x08, 0x09,  0x08, 0x0b,
432                              # ecdsa_secp{256,512}     rsa+sha1     ecdsa+sha1
433                              0x04, 0x03,  0x06, 0x03,  0x02, 0x01,  0x02, 0x03;
434             } elsif ($testtype == SIGALGS_CERT_PKCS) {
435                 $sigs = pack "C10", 0x00, 0x08,
436                              # rsa_pkcs_sha{256,384,512,1}
437                              0x04, 0x01,  0x05, 0x01,  0x06, 0x01,  0x02, 0x01;
438             } elsif ($testtype == SIGALGS_CERT_INVALID) {
439                 $sigs = pack "C4", 0x00, 0x02,
440                              # unregistered codepoint
441                              0xb2, 0x6f;
442             }
443             $message->set_extension(TLSProxy::Message::EXT_SIG_ALGS_CERT, $sigs);
444             $message->repack();
445         }
446     }
447 }
448
449 sub modify_cert_verify_sigalg
450 {
451     my $proxy = shift;
452
453     # We're only interested in the CertificateVerify
454     if ($proxy->flight != 1) {
455         return;
456     }
457
458     foreach my $message (@{$proxy->message_list}) {
459         if ($message->mt == TLSProxy::Message::MT_CERTIFICATE_VERIFY) {
460             $message->sigalg(TLSProxy::Message::SIG_ALG_RSA_PSS_PSS_SHA256);
461             $message->repack();
462         }
463     }
464 }
465
466 sub inject_unrecognized_sigalg
467 {
468     my $proxy = shift;
469     my $type;
470
471     # We're only interested in the initial ClientHello
472     if ($proxy->flight != 0) {
473         return;
474     }
475     if ($testtype == UNRECOGNIZED_SIGALGS_CERT) {
476         $type = TLSProxy::Message::EXT_SIG_ALGS_CERT;
477     } elsif ($testtype == UNRECOGNIZED_SIGALG) {
478         $type = TLSProxy::Message::EXT_SIG_ALGS;
479     } else {
480         return;
481     }
482
483     my $ext = pack "C8",
484         0x00, 0x06, #Extension length
485         0xfe, 0x18, #private use
486         0x04, 0x01, #rsa_pkcs1_sha256
487         0x08, 0x04; #rsa_pss_rsae_sha256;
488     my $message = ${$proxy->message_list}[0];
489     $message->set_extension($type, $ext);
490     $message->repack;
491 }