1e1051a39Sopenharmony_ci#! /usr/bin/env perl
2e1051a39Sopenharmony_ci# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci#
4e1051a39Sopenharmony_ci# Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci# this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci# in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci# https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci
9e1051a39Sopenharmony_ciuse strict;
10e1051a39Sopenharmony_ciuse OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
11e1051a39Sopenharmony_ciuse OpenSSL::Test::Utils;
12e1051a39Sopenharmony_ciuse TLSProxy::Proxy;
13e1051a39Sopenharmony_ci
14e1051a39Sopenharmony_cimy $test_name = "test_sslsignature";
15e1051a39Sopenharmony_cisetup($test_name);
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ciplan skip_all => "TLSProxy isn't usable on $^O"
18e1051a39Sopenharmony_ci    if $^O =~ /^(VMS)$/;
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ciplan skip_all => "$test_name needs the dynamic engine feature enabled"
21e1051a39Sopenharmony_ci    if disabled("engine") || disabled("dynamic-engine");
22e1051a39Sopenharmony_ci
23e1051a39Sopenharmony_ciplan skip_all => "$test_name needs the sock feature enabled"
24e1051a39Sopenharmony_ci    if disabled("sock");
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_ciplan skip_all => "$test_name needs TLS enabled"
27e1051a39Sopenharmony_ci    if alldisabled(available_protocols("tls"));
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
30e1051a39Sopenharmony_cimy $proxy = TLSProxy::Proxy->new(
31e1051a39Sopenharmony_ci    undef,
32e1051a39Sopenharmony_ci    cmdstr(app(["openssl"]), display => 1),
33e1051a39Sopenharmony_ci    srctop_file("apps", "server.pem"),
34e1051a39Sopenharmony_ci    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
35e1051a39Sopenharmony_ci);
36e1051a39Sopenharmony_ci
37e1051a39Sopenharmony_ciuse constant {
38e1051a39Sopenharmony_ci    NO_CORRUPTION => 0,
39e1051a39Sopenharmony_ci    CORRUPT_SERVER_CERT_VERIFY => 1,
40e1051a39Sopenharmony_ci    CORRUPT_CLIENT_CERT_VERIFY => 2,
41e1051a39Sopenharmony_ci    CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE => 3,
42e1051a39Sopenharmony_ci};
43e1051a39Sopenharmony_ci
44e1051a39Sopenharmony_ci$proxy->filter(\&signature_filter);
45e1051a39Sopenharmony_ci
46e1051a39Sopenharmony_ci#Test 1: No corruption should succeed
47e1051a39Sopenharmony_cimy $testtype = NO_CORRUPTION;
48e1051a39Sopenharmony_ci$proxy->clientflags("-no_tls1_3") if disabled("ec") && disabled("dh");
49e1051a39Sopenharmony_ci$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
50e1051a39Sopenharmony_ciplan tests => 4;
51e1051a39Sopenharmony_ciok(TLSProxy::Message->success, "No corruption");
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ciSKIP: {
54e1051a39Sopenharmony_ci    skip "TLSv1.3 disabled", 1
55e1051a39Sopenharmony_ci        if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
56e1051a39Sopenharmony_ci
57e1051a39Sopenharmony_ci    #Test 2: Corrupting a server CertVerify signature in TLSv1.3 should fail
58e1051a39Sopenharmony_ci    $proxy->clear();
59e1051a39Sopenharmony_ci    $testtype = CORRUPT_SERVER_CERT_VERIFY;
60e1051a39Sopenharmony_ci    $proxy->start();
61e1051a39Sopenharmony_ci    ok(TLSProxy::Message->fail, "Corrupt server TLSv1.3 CertVerify");
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_ci    #Test x: Corrupting a client CertVerify signature in TLSv1.3 should fail
64e1051a39Sopenharmony_ci    #$proxy->clear();
65e1051a39Sopenharmony_ci    #$testtype = CORRUPT_CLIENT_CERT_VERIFY;
66e1051a39Sopenharmony_ci    #$proxy->serverflags("-Verify 5");
67e1051a39Sopenharmony_ci    #$proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
68e1051a39Sopenharmony_ci    #$proxy->start();
69e1051a39Sopenharmony_ci    #ok(TLSProxy::Message->fail, "Corrupt client TLSv1.3 CertVerify");
70e1051a39Sopenharmony_ci    #TODO(TLS1.3): This test fails due to a problem in s_server/TLSProxy.
71e1051a39Sopenharmony_ci    #Currently a connection is counted as "successful" if the client ends it
72e1051a39Sopenharmony_ci    #with a close_notify. In TLSProxy the client initiates the closure of the
73e1051a39Sopenharmony_ci    #connection so really we should not count it as successful until s_server
74e1051a39Sopenharmony_ci    #has also responded with a close_notify. However s_server never sends a
75e1051a39Sopenharmony_ci    #close_notify - it just closes the connection. Fixing this would be a
76e1051a39Sopenharmony_ci    #significant change to the long established behaviour of s_server.
77e1051a39Sopenharmony_ci    #Unfortunately in this test, it is the server that notices the incorrect
78e1051a39Sopenharmony_ci    #signature and responds with an appropriate alert. However s_client never
79e1051a39Sopenharmony_ci    #sees that because it occurs after the server Finished has been sent.
80e1051a39Sopenharmony_ci    #Therefore s_client just continues to send its application data and sends
81e1051a39Sopenharmony_ci    #its close_notify regardless. TLSProxy sees this and thinks that the
82e1051a39Sopenharmony_ci    #connection was successful when in fact it was not. There isn't an easy fix
83e1051a39Sopenharmony_ci    #for this, so leaving this test commented out for now.
84e1051a39Sopenharmony_ci}
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ciSKIP: {
87e1051a39Sopenharmony_ci    skip "TLS <= 1.2 disabled", 2
88e1051a39Sopenharmony_ci        if alldisabled(("ssl3", "tls1", "tls1_1", "tls1_2"));
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_ci    #Test 3: Corrupting a CertVerify signature in <=TLSv1.2 should fail
91e1051a39Sopenharmony_ci    $proxy->clear();
92e1051a39Sopenharmony_ci    $testtype = CORRUPT_CLIENT_CERT_VERIFY;
93e1051a39Sopenharmony_ci    $proxy->serverflags("-Verify 5");
94e1051a39Sopenharmony_ci    $proxy->clientflags("-no_tls1_3 -cert ".srctop_file("apps", "server.pem"));
95e1051a39Sopenharmony_ci    $proxy->start();
96e1051a39Sopenharmony_ci    ok(TLSProxy::Message->fail, "Corrupt <=TLSv1.2 CertVerify");
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    SKIP: {
99e1051a39Sopenharmony_ci        skip "DH disabled", 1 if disabled("dh");
100e1051a39Sopenharmony_ci
101e1051a39Sopenharmony_ci        #Test 4: Corrupting a ServerKeyExchange signature in <=TLSv1.2 should
102e1051a39Sopenharmony_ci        #fail
103e1051a39Sopenharmony_ci        $proxy->clear();
104e1051a39Sopenharmony_ci        $testtype = CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE;
105e1051a39Sopenharmony_ci        $proxy->clientflags("-no_tls1_3");
106e1051a39Sopenharmony_ci        $proxy->cipherc('DHE-RSA-AES128-SHA');
107e1051a39Sopenharmony_ci        $proxy->ciphers('DHE-RSA-AES128-SHA');
108e1051a39Sopenharmony_ci        $proxy->start();
109e1051a39Sopenharmony_ci        ok(TLSProxy::Message->fail, "Corrupt <=TLSv1.2 ServerKeyExchange");
110e1051a39Sopenharmony_ci    }
111e1051a39Sopenharmony_ci}
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_cisub signature_filter
114e1051a39Sopenharmony_ci{
115e1051a39Sopenharmony_ci    my $proxy = shift;
116e1051a39Sopenharmony_ci    my $flight;
117e1051a39Sopenharmony_ci    my $mt = TLSProxy::Message::MT_CERTIFICATE_VERIFY;
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci    if ($testtype == CORRUPT_SERVER_CERT_VERIFY
120e1051a39Sopenharmony_ci            || $testtype == CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE
121e1051a39Sopenharmony_ci            || (!disabled("tls1_3") && $testtype == NO_CORRUPTION)) {
122e1051a39Sopenharmony_ci        $flight = 1;
123e1051a39Sopenharmony_ci    } else {
124e1051a39Sopenharmony_ci        $flight = 2;
125e1051a39Sopenharmony_ci    }
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ci    # We're only interested in the initial server flight
128e1051a39Sopenharmony_ci    return if ($proxy->flight != $flight);
129e1051a39Sopenharmony_ci
130e1051a39Sopenharmony_ci    $mt = TLSProxy::Message::MT_SERVER_KEY_EXCHANGE
131e1051a39Sopenharmony_ci        if ($testtype == CORRUPT_TLS1_2_SERVER_KEY_EXCHANGE);
132e1051a39Sopenharmony_ci
133e1051a39Sopenharmony_ci    foreach my $message (@{$proxy->message_list}) {
134e1051a39Sopenharmony_ci        if ($message->mt == $mt) {
135e1051a39Sopenharmony_ci            my $sig = $message->signature();
136e1051a39Sopenharmony_ci            my $sigbase = substr($sig, 0, -1);
137e1051a39Sopenharmony_ci            my $sigend = unpack("C", substr($sig, -1));
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ci            #Flip bits in final byte of signature to corrupt the sig
140e1051a39Sopenharmony_ci            $sigend ^= 0xff unless $testtype == NO_CORRUPTION;
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci            $message->signature($sigbase.pack("C", $sigend));
143e1051a39Sopenharmony_ci            $message->repack();
144e1051a39Sopenharmony_ci        }
145e1051a39Sopenharmony_ci    }
146e1051a39Sopenharmony_ci}
147