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