1 1.1 christos #! /usr/bin/env perl 2 1.1 christos # Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos # 4 1.1 christos # Licensed under the OpenSSL license (the "License"). You may not use 5 1.1 christos # this file except in compliance with the License. You can obtain a copy 6 1.1 christos # in the file LICENSE in the source distribution or at 7 1.1 christos # https://www.openssl.org/source/license.html 8 1.1 christos 9 1.1 christos use strict; 10 1.1 christos use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; 11 1.1 christos use OpenSSL::Test::Utils; 12 1.1 christos use TLSProxy::Proxy; 13 1.1 christos use File::Temp qw(tempfile); 14 1.1 christos 15 1.1 christos my $test_name = "test_sslsessiontick"; 16 1.1 christos setup($test_name); 17 1.1 christos 18 1.1 christos plan skip_all => "TLSProxy isn't usable on $^O" 19 1.1 christos if $^O =~ /^(VMS)$/; 20 1.1 christos 21 1.1 christos plan skip_all => "$test_name needs the dynamic engine feature enabled" 22 1.1 christos if disabled("engine") || disabled("dynamic-engine"); 23 1.1 christos 24 1.1 christos plan skip_all => "$test_name needs the sock feature enabled" 25 1.1 christos if disabled("sock"); 26 1.1 christos 27 1.1 christos plan skip_all => "$test_name needs SSLv3, TLSv1, TLSv1.1 or TLSv1.2 enabled" 28 1.1 christos if alldisabled(("ssl3", "tls1", "tls1_1", "tls1_2")); 29 1.1 christos 30 1.1 christos $ENV{OPENSSL_ia32cap} = '~0x200000200000000'; 31 1.1 christos 32 1.1 christos sub checkmessages($$$$$$); 33 1.1 christos sub clearclient(); 34 1.1 christos sub clearall(); 35 1.1 christos 36 1.1 christos my $chellotickext = 0; 37 1.1 christos my $shellotickext = 0; 38 1.1 christos my $fullhand = 0; 39 1.1 christos my $ticketseen = 0; 40 1.1 christos 41 1.1 christos my $proxy = TLSProxy::Proxy->new( 42 1.1 christos undef, 43 1.1 christos cmdstr(app(["openssl"]), display => 1), 44 1.1 christos srctop_file("apps", "server.pem"), 45 1.1 christos (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) 46 1.1 christos ); 47 1.1 christos 48 1.1 christos #Test 1: By default with no existing session we should get a session ticket 49 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension seen 50 1.1 christos # NewSessionTicket message seen; Full handshake 51 1.1 christos $proxy->clientflags("-no_tls1_3"); 52 1.1 christos $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; 53 1.1 christos plan tests => 10; 54 1.1 christos checkmessages(1, "Default session ticket test", 1, 1, 1, 1); 55 1.1 christos 56 1.1 christos #Test 2: If the server does not accept tickets we should get a normal handshake 57 1.1 christos #with no session tickets 58 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension not seen 59 1.1 christos # NewSessionTicket message not seen; Full handshake 60 1.1 christos clearall(); 61 1.1 christos $proxy->clientflags("-no_tls1_3"); 62 1.1 christos $proxy->serverflags("-no_ticket"); 63 1.1 christos $proxy->start(); 64 1.1 christos checkmessages(2, "No server support session ticket test", 1, 0, 0, 1); 65 1.1 christos 66 1.1 christos #Test 3: If the client does not accept tickets we should get a normal handshake 67 1.1 christos #with no session tickets 68 1.1 christos #Expected result: ClientHello extension not seen; ServerHello extension not seen 69 1.1 christos # NewSessionTicket message not seen; Full handshake 70 1.1 christos clearall(); 71 1.1 christos $proxy->clientflags("-no_tls1_3 -no_ticket"); 72 1.1 christos $proxy->start(); 73 1.1 christos checkmessages(3, "No client support session ticket test", 0, 0, 0, 1); 74 1.1 christos 75 1.1 christos #Test 4: Test session resumption with session ticket 76 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension not seen 77 1.1 christos # NewSessionTicket message not seen; Abbreviated handshake 78 1.1 christos clearall(); 79 1.1 christos (undef, my $session) = tempfile(); 80 1.1 christos $proxy->serverconnects(2); 81 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_out ".$session); 82 1.1 christos $proxy->start(); 83 1.1 christos $proxy->clearClient(); 84 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_in ".$session); 85 1.1 christos $proxy->clientstart(); 86 1.1 christos checkmessages(4, "Session resumption session ticket test", 1, 0, 0, 0); 87 1.1 christos unlink $session; 88 1.1 christos 89 1.1 christos #Test 5: Test session resumption with ticket capable client without a ticket 90 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension seen 91 1.1 christos # NewSessionTicket message seen; Abbreviated handshake 92 1.1 christos clearall(); 93 1.1 christos (undef, $session) = tempfile(); 94 1.1 christos $proxy->serverconnects(2); 95 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_out ".$session." -no_ticket"); 96 1.1 christos $proxy->start(); 97 1.1 christos $proxy->clearClient(); 98 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_in ".$session); 99 1.1 christos $proxy->clientstart(); 100 1.1 christos checkmessages(5, "Session resumption with ticket capable client without a " 101 1.1 christos ."ticket", 1, 1, 1, 0); 102 1.1 christos unlink $session; 103 1.1 christos 104 1.1 christos #Test 6: Client accepts empty ticket. 105 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension seen; 106 1.1 christos # NewSessionTicket message seen; Full handshake. 107 1.1 christos clearall(); 108 1.1 christos $proxy->filter(\&ticket_filter); 109 1.1 christos $proxy->clientflags("-no_tls1_3"); 110 1.1 christos $proxy->start(); 111 1.1 christos checkmessages(6, "Empty ticket test", 1, 1, 1, 1); 112 1.1 christos 113 1.1 christos #Test 7-8: Client keeps existing ticket on empty ticket. 114 1.1 christos clearall(); 115 1.1 christos (undef, $session) = tempfile(); 116 1.1 christos $proxy->serverconnects(3); 117 1.1 christos $proxy->filter(undef); 118 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_out ".$session); 119 1.1 christos $proxy->start(); 120 1.1 christos $proxy->clearClient(); 121 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_in ".$session." -sess_out ".$session); 122 1.1 christos $proxy->filter(\&inject_empty_ticket_filter); 123 1.1 christos $proxy->clientstart(); 124 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension seen; 125 1.1 christos # NewSessionTicket message seen; Abbreviated handshake. 126 1.1 christos checkmessages(7, "Empty ticket resumption test", 1, 1, 1, 0); 127 1.1 christos clearclient(); 128 1.1 christos $proxy->clientflags("-no_tls1_3 -sess_in ".$session); 129 1.1 christos $proxy->filter(undef); 130 1.1 christos $proxy->clientstart(); 131 1.1 christos #Expected result: ClientHello extension seen; ServerHello extension not seen; 132 1.1 christos # NewSessionTicket message not seen; Abbreviated handshake. 133 1.1 christos checkmessages(8, "Empty ticket resumption test", 1, 0, 0, 0); 134 1.1 christos unlink $session; 135 1.1 christos 136 1.1 christos #Test 9: Bad server sends the ServerHello extension but does not send a 137 1.1 christos #NewSessionTicket 138 1.1 christos #Expected result: Connection failure 139 1.1 christos clearall(); 140 1.1 christos $proxy->clientflags("-no_tls1_3"); 141 1.1 christos $proxy->serverflags("-no_ticket"); 142 1.1 christos $proxy->filter(\&inject_ticket_extension_filter); 143 1.1 christos $proxy->start(); 144 1.1 christos ok(TLSProxy::Message->fail, "Server sends ticket extension but no ticket test"); 145 1.1 christos 146 1.1 christos #Test10: Bad server does not send the ServerHello extension but does send a 147 1.1 christos #NewSessionTicket 148 1.1 christos #Expected result: Connection failure 149 1.1 christos clearall(); 150 1.1 christos $proxy->clientflags("-no_tls1_3"); 151 1.1 christos $proxy->serverflags("-no_ticket"); 152 1.1 christos $proxy->filter(\&inject_empty_ticket_filter); 153 1.1 christos $proxy->start(); 154 1.1 christos ok(TLSProxy::Message->fail, "No server ticket extension but ticket sent test"); 155 1.1 christos 156 1.1 christos sub ticket_filter 157 1.1 christos { 158 1.1 christos my $proxy = shift; 159 1.1 christos 160 1.1 christos foreach my $message (@{$proxy->message_list}) { 161 1.1 christos if ($message->mt == TLSProxy::Message::MT_NEW_SESSION_TICKET) { 162 1.1 christos $message->ticket(""); 163 1.1 christos $message->repack(); 164 1.1 christos } 165 1.1 christos } 166 1.1 christos } 167 1.1 christos 168 1.1 christos sub inject_empty_ticket_filter { 169 1.1 christos my $proxy = shift; 170 1.1 christos 171 1.1 christos foreach my $message (@{$proxy->message_list}) { 172 1.1 christos if ($message->mt == TLSProxy::Message::MT_NEW_SESSION_TICKET) { 173 1.1 christos # Only inject the message first time we're called. 174 1.1 christos return; 175 1.1 christos } 176 1.1 christos } 177 1.1 christos 178 1.1 christos my @new_message_list = (); 179 1.1 christos foreach my $message (@{$proxy->message_list}) { 180 1.1 christos push @new_message_list, $message; 181 1.1 christos if ($message->mt == TLSProxy::Message::MT_SERVER_HELLO) { 182 1.1 christos $message->set_extension(TLSProxy::Message::EXT_SESSION_TICKET, ""); 183 1.1 christos $message->repack(); 184 1.1 christos # Tack NewSessionTicket onto the ServerHello record. 185 1.1 christos # This only works if the ServerHello is exactly one record. 186 1.1 christos my $record = ${$message->records}[0]; 187 1.1 christos 188 1.1 christos my $offset = $message->startoffset + $message->encoded_length; 189 1.1 christos my $newsessionticket = TLSProxy::NewSessionTicket->new( 190 1.1 christos 1, "", [$record], $offset, []); 191 1.1 christos $newsessionticket->repack(); 192 1.1 christos push @new_message_list, $newsessionticket; 193 1.1 christos } 194 1.1 christos } 195 1.1 christos $proxy->message_list([@new_message_list]); 196 1.1 christos } 197 1.1 christos 198 1.1 christos sub inject_ticket_extension_filter 199 1.1 christos { 200 1.1 christos my $proxy = shift; 201 1.1 christos 202 1.1 christos # We're only interested in the initial ServerHello 203 1.1 christos if ($proxy->flight != 1) { 204 1.1 christos return; 205 1.1 christos } 206 1.1 christos 207 1.1 christos foreach my $message (@{$proxy->message_list}) { 208 1.1 christos if ($message->mt == TLSProxy::Message::MT_SERVER_HELLO) { 209 1.1 christos #Add the session ticket extension to the ServerHello even though 210 1.1 christos #we are not going to send a NewSessionTicket message 211 1.1 christos $message->set_extension(TLSProxy::Message::EXT_SESSION_TICKET, ""); 212 1.1 christos 213 1.1 christos $message->repack(); 214 1.1 christos } 215 1.1 christos } 216 1.1 christos } 217 1.1 christos 218 1.1 christos sub checkmessages($$$$$$) 219 1.1 christos { 220 1.1 christos my ($testno, $testname, $testch, $testsh, $testtickseen, $testhand) = @_; 221 1.1 christos 222 1.1 christos subtest $testname => sub { 223 1.1 christos 224 1.1 christos foreach my $message (@{$proxy->message_list}) { 225 1.1 christos if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO 226 1.1 christos || $message->mt == TLSProxy::Message::MT_SERVER_HELLO) { 227 1.1 christos #Get the extensions data 228 1.1 christos my %extensions = %{$message->extension_data}; 229 1.1 christos if (defined 230 1.1 christos $extensions{TLSProxy::Message::EXT_SESSION_TICKET}) { 231 1.1 christos if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) { 232 1.1 christos $chellotickext = 1; 233 1.1 christos } else { 234 1.1 christos $shellotickext = 1; 235 1.1 christos } 236 1.1 christos } 237 1.1 christos } elsif ($message->mt == TLSProxy::Message::MT_CERTIFICATE) { 238 1.1 christos #Must be doing a full handshake 239 1.1 christos $fullhand = 1; 240 1.1 christos } elsif ($message->mt == TLSProxy::Message::MT_NEW_SESSION_TICKET) { 241 1.1 christos $ticketseen = 1; 242 1.1 christos } 243 1.1 christos } 244 1.1 christos 245 1.1 christos plan tests => 5; 246 1.1 christos 247 1.1 christos ok(TLSProxy::Message->success, "Handshake"); 248 1.1 christos ok(($testch && $chellotickext) || (!$testch && !$chellotickext), 249 1.1 christos "ClientHello extension Session Ticket check"); 250 1.1 christos ok(($testsh && $shellotickext) || (!$testsh && !$shellotickext), 251 1.1 christos "ServerHello extension Session Ticket check"); 252 1.1 christos ok(($testtickseen && $ticketseen) || (!$testtickseen && !$ticketseen), 253 1.1 christos "Session Ticket message presence check"); 254 1.1 christos ok(($testhand && $fullhand) || (!$testhand && !$fullhand), 255 1.1 christos "Session Ticket full handshake check"); 256 1.1 christos } 257 1.1 christos } 258 1.1 christos 259 1.1 christos 260 1.1 christos sub clearclient() 261 1.1 christos { 262 1.1 christos $chellotickext = 0; 263 1.1 christos $shellotickext = 0; 264 1.1 christos $fullhand = 0; 265 1.1 christos $ticketseen = 0; 266 1.1 christos $proxy->clearClient(); 267 1.1 christos } 268 1.1 christos 269 1.1 christos sub clearall() 270 1.1 christos { 271 1.1 christos clearclient(); 272 1.1 christos $proxy->clear(); 273 1.1 christos } 274