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