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