| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | #! /usr/bin/env perl | 
 | 2 | # Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved. | 
 | 3 | # | 
 | 4 | # Licensed under the OpenSSL license (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; |