Teach TLSProxy how to parse CertificateRequest messages
[openssl.git] / util / perl / checkhandshake.pm
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
9 package checkhandshake;
10
11 use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
12 use OpenSSL::Test::Utils;
13 use TLSProxy::Proxy;
14
15 use Exporter;
16 our @ISA = 'Exporter';
17 our @EXPORT = qw(@handmessages @extensions checkhandshake);
18
19 use 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
33 use 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
60 our @handmessages = ();
61 our @extensions = ();
62
63 sub 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
232 1;