1e1051a39Sopenharmony_ci#! /usr/bin/env perl
2e1051a39Sopenharmony_ci# Copyright 2015-2018 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_cipackage checkhandshake;
10e1051a39Sopenharmony_ci
11e1051a39Sopenharmony_ciuse OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
12e1051a39Sopenharmony_ciuse OpenSSL::Test::Utils;
13e1051a39Sopenharmony_ciuse TLSProxy::Proxy;
14e1051a39Sopenharmony_ci
15e1051a39Sopenharmony_ciuse Exporter;
16e1051a39Sopenharmony_ciour @ISA = 'Exporter';
17e1051a39Sopenharmony_ciour @EXPORT = qw(@handmessages @extensions checkhandshake);
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_ciuse constant {
20e1051a39Sopenharmony_ci    DEFAULT_HANDSHAKE => 1,
21e1051a39Sopenharmony_ci    OCSP_HANDSHAKE => 2,
22e1051a39Sopenharmony_ci    RESUME_HANDSHAKE => 4,
23e1051a39Sopenharmony_ci    CLIENT_AUTH_HANDSHAKE => 8,
24e1051a39Sopenharmony_ci    RENEG_HANDSHAKE => 16,
25e1051a39Sopenharmony_ci    NPN_HANDSHAKE => 32,
26e1051a39Sopenharmony_ci    EC_HANDSHAKE => 64,
27e1051a39Sopenharmony_ci    HRR_HANDSHAKE => 128,
28e1051a39Sopenharmony_ci    HRR_RESUME_HANDSHAKE => 256,
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_ci    ALL_HANDSHAKES => 511
31e1051a39Sopenharmony_ci};
32e1051a39Sopenharmony_ci
33e1051a39Sopenharmony_ciuse constant {
34e1051a39Sopenharmony_ci    #DEFAULT also includes SESSION_TICKET_SRV_EXTENSION and SERVER_NAME_CLI
35e1051a39Sopenharmony_ci    DEFAULT_EXTENSIONS => 0x00000007,
36e1051a39Sopenharmony_ci    SESSION_TICKET_SRV_EXTENSION => 0x00000002,
37e1051a39Sopenharmony_ci    SERVER_NAME_CLI_EXTENSION => 0x00000004,
38e1051a39Sopenharmony_ci    SERVER_NAME_SRV_EXTENSION => 0x00000008,
39e1051a39Sopenharmony_ci    STATUS_REQUEST_CLI_EXTENSION => 0x00000010,
40e1051a39Sopenharmony_ci    STATUS_REQUEST_SRV_EXTENSION => 0x00000020,
41e1051a39Sopenharmony_ci    ALPN_CLI_EXTENSION => 0x00000040,
42e1051a39Sopenharmony_ci    ALPN_SRV_EXTENSION => 0x00000080,
43e1051a39Sopenharmony_ci    SCT_CLI_EXTENSION => 0x00000100,
44e1051a39Sopenharmony_ci    SCT_SRV_EXTENSION => 0x00000200,
45e1051a39Sopenharmony_ci    RENEGOTIATE_CLI_EXTENSION => 0x00000400,
46e1051a39Sopenharmony_ci    NPN_CLI_EXTENSION => 0x00000800,
47e1051a39Sopenharmony_ci    NPN_SRV_EXTENSION => 0x00001000,
48e1051a39Sopenharmony_ci    SRP_CLI_EXTENSION => 0x00002000,
49e1051a39Sopenharmony_ci    #Client side for ec point formats is a default extension
50e1051a39Sopenharmony_ci    EC_POINT_FORMAT_SRV_EXTENSION => 0x00004000,
51e1051a39Sopenharmony_ci    PSK_CLI_EXTENSION => 0x00008000,
52e1051a39Sopenharmony_ci    PSK_SRV_EXTENSION => 0x00010000,
53e1051a39Sopenharmony_ci    KEY_SHARE_SRV_EXTENSION => 0x00020000,
54e1051a39Sopenharmony_ci    PSK_KEX_MODES_EXTENSION => 0x00040000,
55e1051a39Sopenharmony_ci    KEY_SHARE_HRR_EXTENSION => 0x00080000,
56e1051a39Sopenharmony_ci    SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000,
57e1051a39Sopenharmony_ci    POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000
58e1051a39Sopenharmony_ci};
59e1051a39Sopenharmony_ci
60e1051a39Sopenharmony_ciour @handmessages = ();
61e1051a39Sopenharmony_ciour @extensions = ();
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_cisub checkhandshake($$$$)
64e1051a39Sopenharmony_ci{
65e1051a39Sopenharmony_ci    my ($proxy, $handtype, $exttype, $testname) = @_;
66e1051a39Sopenharmony_ci
67e1051a39Sopenharmony_ci    subtest $testname => sub {
68e1051a39Sopenharmony_ci        my $loop = 0;
69e1051a39Sopenharmony_ci        my $numtests;
70e1051a39Sopenharmony_ci        my $extcount;
71e1051a39Sopenharmony_ci        my $clienthelloseen = 0;
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_ci        my $lastmt = 0;
74e1051a39Sopenharmony_ci        my $numsh = 0;
75e1051a39Sopenharmony_ci        if (TLSProxy::Proxy::is_tls13()) {
76e1051a39Sopenharmony_ci            #How many ServerHellos are we expecting?
77e1051a39Sopenharmony_ci            for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
78e1051a39Sopenharmony_ci                next if (($handmessages[$loop][1] & $handtype) == 0);
79e1051a39Sopenharmony_ci                $numsh++ if ($lastmt != TLSProxy::Message::MT_SERVER_HELLO
80e1051a39Sopenharmony_ci                             && $handmessages[$loop][0] == TLSProxy::Message::MT_SERVER_HELLO);
81e1051a39Sopenharmony_ci                $lastmt = $handmessages[$loop][0];
82e1051a39Sopenharmony_ci            }
83e1051a39Sopenharmony_ci        }
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_ci        #First count the number of tests
86e1051a39Sopenharmony_ci        my $nextmess = 0;
87e1051a39Sopenharmony_ci        my $message = undef;
88e1051a39Sopenharmony_ci        my $chnum = 0;
89e1051a39Sopenharmony_ci        my $shnum = 0;
90e1051a39Sopenharmony_ci        if (!TLSProxy::Proxy::is_tls13()) {
91e1051a39Sopenharmony_ci            # In non-TLSv1.3 we always treat reneg CH and SH like the first CH
92e1051a39Sopenharmony_ci            # and SH
93e1051a39Sopenharmony_ci            $chnum = 1;
94e1051a39Sopenharmony_ci            $shnum = 1;
95e1051a39Sopenharmony_ci        }
96e1051a39Sopenharmony_ci        #If we're only expecting one ServerHello out of two then we skip the
97e1051a39Sopenharmony_ci        #first ServerHello in the list completely
98e1051a39Sopenharmony_ci        $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13());
99e1051a39Sopenharmony_ci        $loop = 0;
100e1051a39Sopenharmony_ci        for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
101e1051a39Sopenharmony_ci            next if (($handmessages[$loop][1] & $handtype) == 0);
102e1051a39Sopenharmony_ci            if (scalar @{$proxy->message_list} > $nextmess) {
103e1051a39Sopenharmony_ci                $message = ${$proxy->message_list}[$nextmess];
104e1051a39Sopenharmony_ci                $nextmess++;
105e1051a39Sopenharmony_ci            } else {
106e1051a39Sopenharmony_ci                $message = undef;
107e1051a39Sopenharmony_ci            }
108e1051a39Sopenharmony_ci            $numtests++;
109e1051a39Sopenharmony_ci
110e1051a39Sopenharmony_ci            next if (!defined $message);
111e1051a39Sopenharmony_ci            if (TLSProxy::Proxy::is_tls13()) {
112e1051a39Sopenharmony_ci                $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
113e1051a39Sopenharmony_ci                $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO;
114e1051a39Sopenharmony_ci            }
115e1051a39Sopenharmony_ci            next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
116e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
117e1051a39Sopenharmony_ci                    && $message->mt() !=
118e1051a39Sopenharmony_ci                       TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
119e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_CERTIFICATE
120e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_CERTIFICATE_REQUEST);
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_ci            next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE
123e1051a39Sopenharmony_ci                    && !TLSProxy::Proxy::is_tls13();
124e1051a39Sopenharmony_ci
125e1051a39Sopenharmony_ci            my $extchnum = 1;
126e1051a39Sopenharmony_ci            my $extshnum = 1;
127e1051a39Sopenharmony_ci            for (my $extloop = 0;
128e1051a39Sopenharmony_ci                    $extensions[$extloop][3] != 0;
129e1051a39Sopenharmony_ci                    $extloop++) {
130e1051a39Sopenharmony_ci                $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
131e1051a39Sopenharmony_ci                                 && TLSProxy::Proxy::is_tls13();
132e1051a39Sopenharmony_ci                $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO
133e1051a39Sopenharmony_ci                                 && $extchnum == 2;
134e1051a39Sopenharmony_ci                next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
135e1051a39Sopenharmony_ci                                 && $extchnum != $chnum;
136e1051a39Sopenharmony_ci                next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO
137e1051a39Sopenharmony_ci                                 && $extshnum != $shnum;
138e1051a39Sopenharmony_ci                next if ($message->mt() != $extensions[$extloop][0]);
139e1051a39Sopenharmony_ci                next if ($message->server() != $extensions[$extloop][2]);
140e1051a39Sopenharmony_ci                $numtests++;
141e1051a39Sopenharmony_ci            }
142e1051a39Sopenharmony_ci            $numtests++;
143e1051a39Sopenharmony_ci        }
144e1051a39Sopenharmony_ci
145e1051a39Sopenharmony_ci        plan tests => $numtests;
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci        $nextmess = 0;
148e1051a39Sopenharmony_ci        $message = undef;
149e1051a39Sopenharmony_ci        if (TLSProxy::Proxy::is_tls13()) {
150e1051a39Sopenharmony_ci            $chnum = 0;
151e1051a39Sopenharmony_ci            $shnum = 0;
152e1051a39Sopenharmony_ci        } else {
153e1051a39Sopenharmony_ci            # In non-TLSv1.3 we always treat reneg CH and SH like the first CH
154e1051a39Sopenharmony_ci            # and SH
155e1051a39Sopenharmony_ci            $chnum = 1;
156e1051a39Sopenharmony_ci            $shnum = 1;
157e1051a39Sopenharmony_ci        }
158e1051a39Sopenharmony_ci        #If we're only expecting one ServerHello out of two then we skip the
159e1051a39Sopenharmony_ci        #first ServerHello in the list completely
160e1051a39Sopenharmony_ci        $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13());
161e1051a39Sopenharmony_ci        for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) {
162e1051a39Sopenharmony_ci            next if (($handmessages[$loop][1] & $handtype) == 0);
163e1051a39Sopenharmony_ci            if (scalar @{$proxy->message_list} > $nextmess) {
164e1051a39Sopenharmony_ci                $message = ${$proxy->message_list}[$nextmess];
165e1051a39Sopenharmony_ci                $nextmess++;
166e1051a39Sopenharmony_ci            } else {
167e1051a39Sopenharmony_ci                $message = undef;
168e1051a39Sopenharmony_ci            }
169e1051a39Sopenharmony_ci            if (!defined $message) {
170e1051a39Sopenharmony_ci                fail("Message type check. Got nothing, expected "
171e1051a39Sopenharmony_ci                     .$handmessages[$loop][0]);
172e1051a39Sopenharmony_ci                next;
173e1051a39Sopenharmony_ci            } else {
174e1051a39Sopenharmony_ci                ok($message->mt == $handmessages[$loop][0],
175e1051a39Sopenharmony_ci                   "Message type check. Got ".$message->mt
176e1051a39Sopenharmony_ci                   .", expected ".$handmessages[$loop][0]);
177e1051a39Sopenharmony_ci            }
178e1051a39Sopenharmony_ci            if (TLSProxy::Proxy::is_tls13()) {
179e1051a39Sopenharmony_ci                $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
180e1051a39Sopenharmony_ci                $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO;
181e1051a39Sopenharmony_ci            }
182e1051a39Sopenharmony_ci
183e1051a39Sopenharmony_ci            next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
184e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
185e1051a39Sopenharmony_ci                    && $message->mt() !=
186e1051a39Sopenharmony_ci                       TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
187e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_CERTIFICATE
188e1051a39Sopenharmony_ci                    && $message->mt() != TLSProxy::Message::MT_CERTIFICATE_REQUEST);
189e1051a39Sopenharmony_ci
190e1051a39Sopenharmony_ci            next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE
191e1051a39Sopenharmony_ci                    && !TLSProxy::Proxy::is_tls13();
192e1051a39Sopenharmony_ci
193e1051a39Sopenharmony_ci            if ($message->mt() == TLSProxy::Message::MT_CLIENT_HELLO) {
194e1051a39Sopenharmony_ci                #Add renegotiate extension we will expect if renegotiating
195e1051a39Sopenharmony_ci                $exttype |= RENEGOTIATE_CLI_EXTENSION
196e1051a39Sopenharmony_ci                    if ($clienthelloseen && !TLSProxy::Proxy::is_tls13());
197e1051a39Sopenharmony_ci                $clienthelloseen = 1;
198e1051a39Sopenharmony_ci            }
199e1051a39Sopenharmony_ci            #Now check that we saw the extensions we expected
200e1051a39Sopenharmony_ci            my $msgexts = $message->extension_data();
201e1051a39Sopenharmony_ci            my $extchnum = 1;
202e1051a39Sopenharmony_ci            my $extshnum = 1;
203e1051a39Sopenharmony_ci            for (my $extloop = 0, $extcount = 0; $extensions[$extloop][3] != 0;
204e1051a39Sopenharmony_ci                                $extloop++) {
205e1051a39Sopenharmony_ci                #In TLSv1.3 we can have two ClientHellos if there has been a
206e1051a39Sopenharmony_ci                #HelloRetryRequest, and they may have different extensions. Skip
207e1051a39Sopenharmony_ci                #if these are extensions for a different ClientHello
208e1051a39Sopenharmony_ci                $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
209e1051a39Sopenharmony_ci                                 && TLSProxy::Proxy::is_tls13();
210e1051a39Sopenharmony_ci                $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO
211e1051a39Sopenharmony_ci                                 && $extchnum == 2;
212e1051a39Sopenharmony_ci                next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
213e1051a39Sopenharmony_ci                                 && $extchnum != $chnum;
214e1051a39Sopenharmony_ci                next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO
215e1051a39Sopenharmony_ci                                 && $extshnum != $shnum;
216e1051a39Sopenharmony_ci                next if ($message->mt() != $extensions[$extloop][0]);
217e1051a39Sopenharmony_ci                next if ($message->server() != $extensions[$extloop][2]);
218e1051a39Sopenharmony_ci                ok (($extensions[$extloop][3] & $exttype) == 0
219e1051a39Sopenharmony_ci                      || defined ($msgexts->{$extensions[$extloop][1]}),
220e1051a39Sopenharmony_ci                    "Extension presence check (Message: ".$message->mt()
221e1051a39Sopenharmony_ci                    ." Extension: ".($extensions[$extloop][3] & $exttype).", "
222e1051a39Sopenharmony_ci                    .$extloop.")");
223e1051a39Sopenharmony_ci                $extcount++ if (($extensions[$extloop][3] & $exttype) != 0);
224e1051a39Sopenharmony_ci            }
225e1051a39Sopenharmony_ci            ok($extcount == keys %$msgexts, "Extensions count mismatch ("
226e1051a39Sopenharmony_ci                                            .$extcount.", ".(keys %$msgexts)
227e1051a39Sopenharmony_ci                                            .")");
228e1051a39Sopenharmony_ci        }
229e1051a39Sopenharmony_ci    }
230e1051a39Sopenharmony_ci}
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ci1;
233