|  | #! /usr/bin/env perl | 
|  | # Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. | 
|  | # | 
|  | # Licensed under the Apache License 2.0 (the "License").  You may not use | 
|  | # this file except in compliance with the License.  You can obtain a copy | 
|  | # in the file LICENSE in the source distribution or at | 
|  | # https://www.openssl.org/source/license.html | 
|  |  | 
|  | package checkhandshake; | 
|  |  | 
|  | use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/; | 
|  | use OpenSSL::Test::Utils; | 
|  | use TLSProxy::Proxy; | 
|  |  | 
|  | use Exporter; | 
|  | our @ISA = 'Exporter'; | 
|  | our @EXPORT = qw(@handmessages @extensions checkhandshake); | 
|  |  | 
|  | use constant { | 
|  | DEFAULT_HANDSHAKE => 1, | 
|  | OCSP_HANDSHAKE => 2, | 
|  | RESUME_HANDSHAKE => 4, | 
|  | CLIENT_AUTH_HANDSHAKE => 8, | 
|  | RENEG_HANDSHAKE => 16, | 
|  | NPN_HANDSHAKE => 32, | 
|  | EC_HANDSHAKE => 64, | 
|  | HRR_HANDSHAKE => 128, | 
|  | HRR_RESUME_HANDSHAKE => 256, | 
|  |  | 
|  | ALL_HANDSHAKES => 511 | 
|  | }; | 
|  |  | 
|  | use constant { | 
|  | #DEFAULT also includes SESSION_TICKET_SRV_EXTENSION and SERVER_NAME_CLI | 
|  | DEFAULT_EXTENSIONS => 0x00000007, | 
|  | SESSION_TICKET_SRV_EXTENSION => 0x00000002, | 
|  | SERVER_NAME_CLI_EXTENSION => 0x00000004, | 
|  | SERVER_NAME_SRV_EXTENSION => 0x00000008, | 
|  | STATUS_REQUEST_CLI_EXTENSION => 0x00000010, | 
|  | STATUS_REQUEST_SRV_EXTENSION => 0x00000020, | 
|  | ALPN_CLI_EXTENSION => 0x00000040, | 
|  | ALPN_SRV_EXTENSION => 0x00000080, | 
|  | SCT_CLI_EXTENSION => 0x00000100, | 
|  | SCT_SRV_EXTENSION => 0x00000200, | 
|  | RENEGOTIATE_CLI_EXTENSION => 0x00000400, | 
|  | NPN_CLI_EXTENSION => 0x00000800, | 
|  | NPN_SRV_EXTENSION => 0x00001000, | 
|  | SRP_CLI_EXTENSION => 0x00002000, | 
|  | #Client side for ec point formats is a default extension | 
|  | EC_POINT_FORMAT_SRV_EXTENSION => 0x00004000, | 
|  | PSK_CLI_EXTENSION => 0x00008000, | 
|  | PSK_SRV_EXTENSION => 0x00010000, | 
|  | KEY_SHARE_SRV_EXTENSION => 0x00020000, | 
|  | PSK_KEX_MODES_EXTENSION => 0x00040000, | 
|  | KEY_SHARE_HRR_EXTENSION => 0x00080000, | 
|  | SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000, | 
|  | POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000 | 
|  | }; | 
|  |  | 
|  | our @handmessages = (); | 
|  | our @extensions = (); | 
|  |  | 
|  | sub checkhandshake($$$$) | 
|  | { | 
|  | my ($proxy, $handtype, $exttype, $testname) = @_; | 
|  |  | 
|  | subtest $testname => sub { | 
|  | my $loop = 0; | 
|  | my $numtests; | 
|  | my $extcount; | 
|  | my $clienthelloseen = 0; | 
|  |  | 
|  | my $lastmt = 0; | 
|  | my $numsh = 0; | 
|  | if (TLSProxy::Proxy::is_tls13()) { | 
|  | #How many ServerHellos are we expecting? | 
|  | for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) { | 
|  | next if (($handmessages[$loop][1] & $handtype) == 0); | 
|  | $numsh++ if ($lastmt != TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $handmessages[$loop][0] == TLSProxy::Message::MT_SERVER_HELLO); | 
|  | $lastmt = $handmessages[$loop][0]; | 
|  | } | 
|  | } | 
|  |  | 
|  | #First count the number of tests | 
|  | my $nextmess = 0; | 
|  | my $message = undef; | 
|  | my $chnum = 0; | 
|  | my $shnum = 0; | 
|  | if (!TLSProxy::Proxy::is_tls13()) { | 
|  | # In non-TLSv1.3 we always treat reneg CH and SH like the first CH | 
|  | # and SH | 
|  | $chnum = 1; | 
|  | $shnum = 1; | 
|  | } | 
|  | #If we're only expecting one ServerHello out of two then we skip the | 
|  | #first ServerHello in the list completely | 
|  | $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13()); | 
|  | $loop = 0; | 
|  | for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) { | 
|  | next if (($handmessages[$loop][1] & $handtype) == 0); | 
|  | if (scalar @{$proxy->message_list} > $nextmess) { | 
|  | $message = ${$proxy->message_list}[$nextmess]; | 
|  | $nextmess++; | 
|  | } else { | 
|  | $message = undef; | 
|  | } | 
|  | $numtests++; | 
|  |  | 
|  | next if (!defined $message); | 
|  | if (TLSProxy::Proxy::is_tls13()) { | 
|  | $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO; | 
|  | $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO; | 
|  | } | 
|  | next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $message->mt() != | 
|  | TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS | 
|  | && $message->mt() != TLSProxy::Message::MT_CERTIFICATE); | 
|  |  | 
|  | next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE | 
|  | && !TLSProxy::Proxy::is_tls13(); | 
|  |  | 
|  | my $extchnum = 1; | 
|  | my $extshnum = 1; | 
|  | for (my $extloop = 0; | 
|  | $extensions[$extloop][2] != 0; | 
|  | $extloop++) { | 
|  | $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && TLSProxy::Proxy::is_tls13(); | 
|  | $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $extchnum == 2; | 
|  | next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && $extchnum != $chnum; | 
|  | next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $extshnum != $shnum; | 
|  | next if ($message->mt() != $extensions[$extloop][0]); | 
|  | $numtests++; | 
|  | } | 
|  | $numtests++; | 
|  | } | 
|  |  | 
|  | plan tests => $numtests; | 
|  |  | 
|  | $nextmess = 0; | 
|  | $message = undef; | 
|  | if (TLSProxy::Proxy::is_tls13()) { | 
|  | $chnum = 0; | 
|  | $shnum = 0; | 
|  | } else { | 
|  | # In non-TLSv1.3 we always treat reneg CH and SH like the first CH | 
|  | # and SH | 
|  | $chnum = 1; | 
|  | $shnum = 1; | 
|  | } | 
|  | #If we're only expecting one ServerHello out of two then we skip the | 
|  | #first ServerHello in the list completely | 
|  | $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13()); | 
|  | for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) { | 
|  | next if (($handmessages[$loop][1] & $handtype) == 0); | 
|  | if (scalar @{$proxy->message_list} > $nextmess) { | 
|  | $message = ${$proxy->message_list}[$nextmess]; | 
|  | $nextmess++; | 
|  | } else { | 
|  | $message = undef; | 
|  | } | 
|  | if (!defined $message) { | 
|  | fail("Message type check. Got nothing, expected " | 
|  | .$handmessages[$loop][0]); | 
|  | next; | 
|  | } else { | 
|  | ok($message->mt == $handmessages[$loop][0], | 
|  | "Message type check. Got ".$message->mt | 
|  | .", expected ".$handmessages[$loop][0]); | 
|  | } | 
|  | if (TLSProxy::Proxy::is_tls13()) { | 
|  | $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO; | 
|  | $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO; | 
|  | } | 
|  |  | 
|  | next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $message->mt() != | 
|  | TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS | 
|  | && $message->mt() != TLSProxy::Message::MT_CERTIFICATE); | 
|  |  | 
|  | next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE | 
|  | && !TLSProxy::Proxy::is_tls13(); | 
|  |  | 
|  | if ($message->mt() == TLSProxy::Message::MT_CLIENT_HELLO) { | 
|  | #Add renegotiate extension we will expect if renegotiating | 
|  | $exttype |= RENEGOTIATE_CLI_EXTENSION | 
|  | if ($clienthelloseen && !TLSProxy::Proxy::is_tls13()); | 
|  | $clienthelloseen = 1; | 
|  | } | 
|  | #Now check that we saw the extensions we expected | 
|  | my $msgexts = $message->extension_data(); | 
|  | my $extchnum = 1; | 
|  | my $extshnum = 1; | 
|  | for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0; | 
|  | $extloop++) { | 
|  | #In TLSv1.3 we can have two ClientHellos if there has been a | 
|  | #HelloRetryRequest, and they may have different extensions. Skip | 
|  | #if these are extensions for a different ClientHello | 
|  | $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && TLSProxy::Proxy::is_tls13(); | 
|  | $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $extchnum == 2; | 
|  | next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO | 
|  | && $extchnum != $chnum; | 
|  | next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO | 
|  | && $extshnum != $shnum; | 
|  | next if ($message->mt() != $extensions[$extloop][0]); | 
|  | ok (($extensions[$extloop][2] & $exttype) == 0 | 
|  | || defined ($msgexts->{$extensions[$extloop][1]}), | 
|  | "Extension presence check (Message: ".$message->mt() | 
|  | ." Extension: ".($extensions[$extloop][2] & $exttype).", " | 
|  | .$extloop.")"); | 
|  | $extcount++ if (($extensions[$extloop][2] & $exttype) != 0); | 
|  | } | 
|  | ok($extcount == keys %$msgexts, "Extensions count mismatch (" | 
|  | .$extcount.", ".(keys %$msgexts) | 
|  | .")"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 1; |