1#! /usr/bin/env perl 2# Copyright 2016-2018 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_sslsignature"; 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 TLS enabled" 27 if alldisabled(available_protocols("tls")); 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_CORRUPTION => 0, 39 CORRUPT_SERVER_CERT_VERIFY => 1, 40 CORRUPT_CLIENT_CERT_VERIFY => 2, 41 CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE => 3, 42}; 43 44$proxy->filter(\&signature_filter); 45 46#Test 1: No corruption should succeed 47my $testtype = NO_CORRUPTION; 48$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; 49plan tests => 4; 50ok(TLSProxy::Message->success, "No corruption"); 51 52SKIP: { 53 skip "TLSv1.3 disabled", 1 if disabled("tls1_3"); 54 55 #Test 2: Corrupting a server CertVerify signature in TLSv1.3 should fail 56 $proxy->clear(); 57 $testtype = CORRUPT_SERVER_CERT_VERIFY; 58 $proxy->start(); 59 ok(TLSProxy::Message->fail, "Corrupt server TLSv1.3 CertVerify"); 60 61 #Test x: Corrupting a client CertVerify signature in TLSv1.3 should fail 62 #$proxy->clear(); 63 #$testtype = CORRUPT_CLIENT_CERT_VERIFY; 64 #$proxy->serverflags("-Verify 5"); 65 #$proxy->clientflags("-cert ".srctop_file("apps", "server.pem")); 66 #$proxy->start(); 67 #ok(TLSProxy::Message->fail, "Corrupt client TLSv1.3 CertVerify"); 68 #TODO(TLS1.3): This test fails due to a problem in s_server/TLSProxy. 69 #Currently a connection is counted as "successful" if the client ends it 70 #with a close_notify. In TLSProxy the client initiates the closure of the 71 #connection so really we should not count it as successful until s_server 72 #has also responded with a close_notify. However s_server never sends a 73 #close_notify - it just closes the connection. Fixing this would be a 74 #significant change to the long established behaviour of s_server. 75 #Unfortunately in this test, it is the server that notices the incorrect 76 #signature and responds with an appropriate alert. However s_client never 77 #sees that because it occurs after the server Finished has been sent. 78 #Therefore s_client just continues to send its application data and sends 79 #its close_notify regardless. TLSProxy sees this and thinks that the 80 #connection was successful when in fact it was not. There isn't an easy fix 81 #for this, so leaving this test commented out for now. 82} 83 84SKIP: { 85 skip "TLS <= 1.2 disabled", 2 86 if alldisabled(("ssl3", "tls1", "tls1_1", "tls1_2")); 87 88 #Test 3: Corrupting a CertVerify signature in <=TLSv1.2 should fail 89 $proxy->clear(); 90 $testtype = CORRUPT_CLIENT_CERT_VERIFY; 91 $proxy->serverflags("-Verify 5"); 92 $proxy->clientflags("-no_tls1_3 -cert ".srctop_file("apps", "server.pem")); 93 $proxy->start(); 94 ok(TLSProxy::Message->fail, "Corrupt <=TLSv1.2 CertVerify"); 95 96 SKIP: { 97 skip "DH disabled", 1 if disabled("dh"); 98 99 #Test 4: Corrupting a ServerKeyExchange signature in <=TLSv1.2 should 100 #fail 101 $proxy->clear(); 102 $testtype = CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE; 103 $proxy->clientflags("-no_tls1_3"); 104 $proxy->cipherc('DHE-RSA-AES128-SHA'); 105 $proxy->ciphers('DHE-RSA-AES128-SHA'); 106 $proxy->start(); 107 ok(TLSProxy::Message->fail, "Corrupt <=TLSv1.2 ServerKeyExchange"); 108 } 109} 110 111sub signature_filter 112{ 113 my $proxy = shift; 114 my $flight; 115 my $mt = TLSProxy::Message::MT_CERTIFICATE_VERIFY; 116 117 if ($testtype == CORRUPT_SERVER_CERT_VERIFY 118 || $testtype == CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE 119 || (!disabled("tls1_3") && $testtype == NO_CORRUPTION)) { 120 $flight = 1; 121 } else { 122 $flight = 2; 123 } 124 125 # We're only interested in the initial server flight 126 return if ($proxy->flight != $flight); 127 128 $mt = TLSProxy::Message::MT_SERVER_KEY_EXCHANGE 129 if ($testtype == CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE); 130 131 foreach my $message (@{$proxy->message_list}) { 132 if ($message->mt == $mt) { 133 my $sig = $message->signature(); 134 my $sigbase = substr($sig, 0, -1); 135 my $sigend = unpack("C", substr($sig, -1)); 136 137 #Flip bits in final byte of signature to corrupt the sig 138 $sigend ^= 0xff unless $testtype == NO_CORRUPTION; 139 140 $message->signature($sigbase.pack("C", $sigend)); 141 $message->repack(); 142 } 143 } 144} 145