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