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