1*4724848cSchristos# Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. 2*4724848cSchristos# 3*4724848cSchristos# Licensed under the OpenSSL license (the "License"). You may not use 4*4724848cSchristos# this file except in compliance with the License. You can obtain a copy 5*4724848cSchristos# in the file LICENSE in the source distribution or at 6*4724848cSchristos# https://www.openssl.org/source/license.html 7*4724848cSchristos 8*4724848cSchristosuse strict; 9*4724848cSchristosuse POSIX ":sys_wait_h"; 10*4724848cSchristos 11*4724848cSchristospackage TLSProxy::Proxy; 12*4724848cSchristos 13*4724848cSchristosuse File::Spec; 14*4724848cSchristosuse IO::Socket; 15*4724848cSchristosuse IO::Select; 16*4724848cSchristosuse TLSProxy::Record; 17*4724848cSchristosuse TLSProxy::Message; 18*4724848cSchristosuse TLSProxy::ClientHello; 19*4724848cSchristosuse TLSProxy::ServerHello; 20*4724848cSchristosuse TLSProxy::EncryptedExtensions; 21*4724848cSchristosuse TLSProxy::Certificate; 22*4724848cSchristosuse TLSProxy::CertificateRequest; 23*4724848cSchristosuse TLSProxy::CertificateVerify; 24*4724848cSchristosuse TLSProxy::ServerKeyExchange; 25*4724848cSchristosuse TLSProxy::NewSessionTicket; 26*4724848cSchristos 27*4724848cSchristosmy $have_IPv6; 28*4724848cSchristosmy $IP_factory; 29*4724848cSchristos 30*4724848cSchristosBEGIN 31*4724848cSchristos{ 32*4724848cSchristos # IO::Socket::IP is on the core module list, IO::Socket::INET6 isn't. 33*4724848cSchristos # However, IO::Socket::INET6 is older and is said to be more widely 34*4724848cSchristos # deployed for the moment, and may have less bugs, so we try the latter 35*4724848cSchristos # first, then fall back on the core modules. Worst case scenario, we 36*4724848cSchristos # fall back to IO::Socket::INET, only supports IPv4. 37*4724848cSchristos eval { 38*4724848cSchristos require IO::Socket::INET6; 39*4724848cSchristos my $s = IO::Socket::INET6->new( 40*4724848cSchristos LocalAddr => "::1", 41*4724848cSchristos LocalPort => 0, 42*4724848cSchristos Listen=>1, 43*4724848cSchristos ); 44*4724848cSchristos $s or die "\n"; 45*4724848cSchristos $s->close(); 46*4724848cSchristos }; 47*4724848cSchristos if ($@ eq "") { 48*4724848cSchristos $IP_factory = sub { IO::Socket::INET6->new(Domain => AF_INET6, @_); }; 49*4724848cSchristos $have_IPv6 = 1; 50*4724848cSchristos } else { 51*4724848cSchristos eval { 52*4724848cSchristos require IO::Socket::IP; 53*4724848cSchristos my $s = IO::Socket::IP->new( 54*4724848cSchristos LocalAddr => "::1", 55*4724848cSchristos LocalPort => 0, 56*4724848cSchristos Listen=>1, 57*4724848cSchristos ); 58*4724848cSchristos $s or die "\n"; 59*4724848cSchristos $s->close(); 60*4724848cSchristos }; 61*4724848cSchristos if ($@ eq "") { 62*4724848cSchristos $IP_factory = sub { IO::Socket::IP->new(@_); }; 63*4724848cSchristos $have_IPv6 = 1; 64*4724848cSchristos } else { 65*4724848cSchristos $IP_factory = sub { IO::Socket::INET->new(@_); }; 66*4724848cSchristos $have_IPv6 = 0; 67*4724848cSchristos } 68*4724848cSchristos } 69*4724848cSchristos} 70*4724848cSchristos 71*4724848cSchristosmy $is_tls13 = 0; 72*4724848cSchristosmy $ciphersuite = undef; 73*4724848cSchristos 74*4724848cSchristossub new 75*4724848cSchristos{ 76*4724848cSchristos my $class = shift; 77*4724848cSchristos my ($filter, 78*4724848cSchristos $execute, 79*4724848cSchristos $cert, 80*4724848cSchristos $debug) = @_; 81*4724848cSchristos 82*4724848cSchristos my $self = { 83*4724848cSchristos #Public read/write 84*4724848cSchristos proxy_addr => $have_IPv6 ? "[::1]" : "127.0.0.1", 85*4724848cSchristos filter => $filter, 86*4724848cSchristos serverflags => "", 87*4724848cSchristos clientflags => "", 88*4724848cSchristos serverconnects => 1, 89*4724848cSchristos reneg => 0, 90*4724848cSchristos sessionfile => undef, 91*4724848cSchristos 92*4724848cSchristos #Public read 93*4724848cSchristos proxy_port => 0, 94*4724848cSchristos server_port => 0, 95*4724848cSchristos serverpid => 0, 96*4724848cSchristos clientpid => 0, 97*4724848cSchristos execute => $execute, 98*4724848cSchristos cert => $cert, 99*4724848cSchristos debug => $debug, 100*4724848cSchristos cipherc => "", 101*4724848cSchristos ciphersuitesc => "", 102*4724848cSchristos ciphers => "AES128-SHA", 103*4724848cSchristos ciphersuitess => "TLS_AES_128_GCM_SHA256", 104*4724848cSchristos flight => -1, 105*4724848cSchristos direction => -1, 106*4724848cSchristos partial => ["", ""], 107*4724848cSchristos record_list => [], 108*4724848cSchristos message_list => [], 109*4724848cSchristos }; 110*4724848cSchristos 111*4724848cSchristos # Create the Proxy socket 112*4724848cSchristos my $proxaddr = $self->{proxy_addr}; 113*4724848cSchristos $proxaddr =~ s/[\[\]]//g; # Remove [ and ] 114*4724848cSchristos my @proxyargs = ( 115*4724848cSchristos LocalHost => $proxaddr, 116*4724848cSchristos LocalPort => 0, 117*4724848cSchristos Proto => "tcp", 118*4724848cSchristos Listen => SOMAXCONN, 119*4724848cSchristos ); 120*4724848cSchristos 121*4724848cSchristos if (my $sock = $IP_factory->(@proxyargs)) { 122*4724848cSchristos $self->{proxy_sock} = $sock; 123*4724848cSchristos $self->{proxy_port} = $sock->sockport(); 124*4724848cSchristos $self->{proxy_addr} = $sock->sockhost(); 125*4724848cSchristos $self->{proxy_addr} =~ s/(.*:.*)/[$1]/; 126*4724848cSchristos print "Proxy started on port ", 127*4724848cSchristos "$self->{proxy_addr}:$self->{proxy_port}\n"; 128*4724848cSchristos # use same address for s_server 129*4724848cSchristos $self->{server_addr} = $self->{proxy_addr}; 130*4724848cSchristos } else { 131*4724848cSchristos warn "Failed creating proxy socket (".$proxaddr.",0): $!\n"; 132*4724848cSchristos } 133*4724848cSchristos 134*4724848cSchristos return bless $self, $class; 135*4724848cSchristos} 136*4724848cSchristos 137*4724848cSchristossub DESTROY 138*4724848cSchristos{ 139*4724848cSchristos my $self = shift; 140*4724848cSchristos 141*4724848cSchristos $self->{proxy_sock}->close() if $self->{proxy_sock}; 142*4724848cSchristos} 143*4724848cSchristos 144*4724848cSchristossub clearClient 145*4724848cSchristos{ 146*4724848cSchristos my $self = shift; 147*4724848cSchristos 148*4724848cSchristos $self->{cipherc} = ""; 149*4724848cSchristos $self->{ciphersuitec} = ""; 150*4724848cSchristos $self->{flight} = -1; 151*4724848cSchristos $self->{direction} = -1; 152*4724848cSchristos $self->{partial} = ["", ""]; 153*4724848cSchristos $self->{record_list} = []; 154*4724848cSchristos $self->{message_list} = []; 155*4724848cSchristos $self->{clientflags} = ""; 156*4724848cSchristos $self->{sessionfile} = undef; 157*4724848cSchristos $self->{clientpid} = 0; 158*4724848cSchristos $is_tls13 = 0; 159*4724848cSchristos $ciphersuite = undef; 160*4724848cSchristos 161*4724848cSchristos TLSProxy::Message->clear(); 162*4724848cSchristos TLSProxy::Record->clear(); 163*4724848cSchristos} 164*4724848cSchristos 165*4724848cSchristossub clear 166*4724848cSchristos{ 167*4724848cSchristos my $self = shift; 168*4724848cSchristos 169*4724848cSchristos $self->clearClient; 170*4724848cSchristos $self->{ciphers} = "AES128-SHA"; 171*4724848cSchristos $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256"; 172*4724848cSchristos $self->{serverflags} = ""; 173*4724848cSchristos $self->{serverconnects} = 1; 174*4724848cSchristos $self->{serverpid} = 0; 175*4724848cSchristos $self->{reneg} = 0; 176*4724848cSchristos} 177*4724848cSchristos 178*4724848cSchristossub restart 179*4724848cSchristos{ 180*4724848cSchristos my $self = shift; 181*4724848cSchristos 182*4724848cSchristos $self->clear; 183*4724848cSchristos $self->start; 184*4724848cSchristos} 185*4724848cSchristos 186*4724848cSchristossub clientrestart 187*4724848cSchristos{ 188*4724848cSchristos my $self = shift; 189*4724848cSchristos 190*4724848cSchristos $self->clear; 191*4724848cSchristos $self->clientstart; 192*4724848cSchristos} 193*4724848cSchristos 194*4724848cSchristossub connect_to_server 195*4724848cSchristos{ 196*4724848cSchristos my $self = shift; 197*4724848cSchristos my $servaddr = $self->{server_addr}; 198*4724848cSchristos 199*4724848cSchristos $servaddr =~ s/[\[\]]//g; # Remove [ and ] 200*4724848cSchristos 201*4724848cSchristos my $sock = $IP_factory->(PeerAddr => $servaddr, 202*4724848cSchristos PeerPort => $self->{server_port}, 203*4724848cSchristos Proto => 'tcp'); 204*4724848cSchristos if (!defined($sock)) { 205*4724848cSchristos my $err = $!; 206*4724848cSchristos kill(3, $self->{real_serverpid}); 207*4724848cSchristos die "unable to connect: $err\n"; 208*4724848cSchristos } 209*4724848cSchristos 210*4724848cSchristos $self->{server_sock} = $sock; 211*4724848cSchristos} 212*4724848cSchristos 213*4724848cSchristossub start 214*4724848cSchristos{ 215*4724848cSchristos my ($self) = shift; 216*4724848cSchristos my $pid; 217*4724848cSchristos 218*4724848cSchristos if ($self->{proxy_sock} == 0) { 219*4724848cSchristos return 0; 220*4724848cSchristos } 221*4724848cSchristos 222*4724848cSchristos my $execcmd = $self->execute 223*4724848cSchristos ." s_server -max_protocol TLSv1.3 -no_comp -rev -engine ossltest" 224*4724848cSchristos #In TLSv1.3 we issue two session tickets. The default session id 225*4724848cSchristos #callback gets confused because the ossltest engine causes the same 226*4724848cSchristos #session id to be created twice due to the changed random number 227*4724848cSchristos #generation. Using "-ext_cache" replaces the default callback with a 228*4724848cSchristos #different one that doesn't get confused. 229*4724848cSchristos ." -ext_cache" 230*4724848cSchristos ." -accept $self->{server_addr}:0" 231*4724848cSchristos ." -cert ".$self->cert." -cert2 ".$self->cert 232*4724848cSchristos ." -naccept ".$self->serverconnects; 233*4724848cSchristos if ($self->ciphers ne "") { 234*4724848cSchristos $execcmd .= " -cipher ".$self->ciphers; 235*4724848cSchristos } 236*4724848cSchristos if ($self->ciphersuitess ne "") { 237*4724848cSchristos $execcmd .= " -ciphersuites ".$self->ciphersuitess; 238*4724848cSchristos } 239*4724848cSchristos if ($self->serverflags ne "") { 240*4724848cSchristos $execcmd .= " ".$self->serverflags; 241*4724848cSchristos } 242*4724848cSchristos if ($self->debug) { 243*4724848cSchristos print STDERR "Server command: $execcmd\n"; 244*4724848cSchristos } 245*4724848cSchristos 246*4724848cSchristos open(my $savedin, "<&STDIN"); 247*4724848cSchristos 248*4724848cSchristos # Temporarily replace STDIN so that sink process can inherit it... 249*4724848cSchristos $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n"; 250*4724848cSchristos $self->{real_serverpid} = $pid; 251*4724848cSchristos 252*4724848cSchristos # Process the output from s_server until we find the ACCEPT line, which 253*4724848cSchristos # tells us what the accepting address and port are. 254*4724848cSchristos while (<>) { 255*4724848cSchristos print; 256*4724848cSchristos s/\R$//; # Better chomp 257*4724848cSchristos next unless (/^ACCEPT\s.*:(\d+)$/); 258*4724848cSchristos $self->{server_port} = $1; 259*4724848cSchristos last; 260*4724848cSchristos } 261*4724848cSchristos 262*4724848cSchristos if ($self->{server_port} == 0) { 263*4724848cSchristos # This actually means that s_server exited, because otherwise 264*4724848cSchristos # we would still searching for ACCEPT... 265*4724848cSchristos waitpid($pid, 0); 266*4724848cSchristos die "no ACCEPT detected in '$execcmd' output: $?\n"; 267*4724848cSchristos } 268*4724848cSchristos 269*4724848cSchristos # Just make sure everything else is simply printed [as separate lines]. 270*4724848cSchristos # The sub process simply inherits our STD* and will keep consuming 271*4724848cSchristos # server's output and printing it as long as there is anything there, 272*4724848cSchristos # out of our way. 273*4724848cSchristos my $error; 274*4724848cSchristos $pid = undef; 275*4724848cSchristos if (eval { require Win32::Process; 1; }) { 276*4724848cSchristos if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) { 277*4724848cSchristos $pid = $h->GetProcessID(); 278*4724848cSchristos $self->{proc_handle} = $h; # hold handle till next round [or exit] 279*4724848cSchristos } else { 280*4724848cSchristos $error = Win32::FormatMessage(Win32::GetLastError()); 281*4724848cSchristos } 282*4724848cSchristos } else { 283*4724848cSchristos if (defined($pid = fork)) { 284*4724848cSchristos $pid or exec("$^X -ne print") or exit($!); 285*4724848cSchristos } else { 286*4724848cSchristos $error = $!; 287*4724848cSchristos } 288*4724848cSchristos } 289*4724848cSchristos 290*4724848cSchristos # Change back to original stdin 291*4724848cSchristos open(STDIN, "<&", $savedin); 292*4724848cSchristos close($savedin); 293*4724848cSchristos 294*4724848cSchristos if (!defined($pid)) { 295*4724848cSchristos kill(3, $self->{real_serverpid}); 296*4724848cSchristos die "Failed to capture s_server's output: $error\n"; 297*4724848cSchristos } 298*4724848cSchristos 299*4724848cSchristos $self->{serverpid} = $pid; 300*4724848cSchristos 301*4724848cSchristos print STDERR "Server responds on ", 302*4724848cSchristos "$self->{server_addr}:$self->{server_port}\n"; 303*4724848cSchristos 304*4724848cSchristos # Connect right away... 305*4724848cSchristos $self->connect_to_server(); 306*4724848cSchristos 307*4724848cSchristos return $self->clientstart; 308*4724848cSchristos} 309*4724848cSchristos 310*4724848cSchristossub clientstart 311*4724848cSchristos{ 312*4724848cSchristos my ($self) = shift; 313*4724848cSchristos 314*4724848cSchristos if ($self->execute) { 315*4724848cSchristos my $pid; 316*4724848cSchristos my $execcmd = $self->execute 317*4724848cSchristos ." s_client -max_protocol TLSv1.3 -engine ossltest" 318*4724848cSchristos ." -connect $self->{proxy_addr}:$self->{proxy_port}"; 319*4724848cSchristos if ($self->cipherc ne "") { 320*4724848cSchristos $execcmd .= " -cipher ".$self->cipherc; 321*4724848cSchristos } 322*4724848cSchristos if ($self->ciphersuitesc ne "") { 323*4724848cSchristos $execcmd .= " -ciphersuites ".$self->ciphersuitesc; 324*4724848cSchristos } 325*4724848cSchristos if ($self->clientflags ne "") { 326*4724848cSchristos $execcmd .= " ".$self->clientflags; 327*4724848cSchristos } 328*4724848cSchristos if ($self->clientflags !~ m/-(no)?servername/) { 329*4724848cSchristos $execcmd .= " -servername localhost"; 330*4724848cSchristos } 331*4724848cSchristos if (defined $self->sessionfile) { 332*4724848cSchristos $execcmd .= " -ign_eof"; 333*4724848cSchristos } 334*4724848cSchristos if ($self->debug) { 335*4724848cSchristos print STDERR "Client command: $execcmd\n"; 336*4724848cSchristos } 337*4724848cSchristos 338*4724848cSchristos open(my $savedout, ">&STDOUT"); 339*4724848cSchristos # If we open pipe with new descriptor, attempt to close it, 340*4724848cSchristos # explicitly or implicitly, would incur waitpid and effectively 341*4724848cSchristos # dead-lock... 342*4724848cSchristos if (!($pid = open(STDOUT, "| $execcmd"))) { 343*4724848cSchristos my $err = $!; 344*4724848cSchristos kill(3, $self->{real_serverpid}); 345*4724848cSchristos die "Failed to $execcmd: $err\n"; 346*4724848cSchristos } 347*4724848cSchristos $self->{clientpid} = $pid; 348*4724848cSchristos 349*4724848cSchristos # queue [magic] input 350*4724848cSchristos print $self->reneg ? "R" : "test"; 351*4724848cSchristos 352*4724848cSchristos # this closes client's stdin without waiting for its pid 353*4724848cSchristos open(STDOUT, ">&", $savedout); 354*4724848cSchristos close($savedout); 355*4724848cSchristos } 356*4724848cSchristos 357*4724848cSchristos # Wait for incoming connection from client 358*4724848cSchristos my $fdset = IO::Select->new($self->{proxy_sock}); 359*4724848cSchristos if (!$fdset->can_read(60)) { 360*4724848cSchristos kill(3, $self->{real_serverpid}); 361*4724848cSchristos die "s_client didn't try to connect\n"; 362*4724848cSchristos } 363*4724848cSchristos 364*4724848cSchristos my $client_sock; 365*4724848cSchristos if(!($client_sock = $self->{proxy_sock}->accept())) { 366*4724848cSchristos warn "Failed accepting incoming connection: $!\n"; 367*4724848cSchristos return 0; 368*4724848cSchristos } 369*4724848cSchristos 370*4724848cSchristos print "Connection opened\n"; 371*4724848cSchristos 372*4724848cSchristos my $server_sock = $self->{server_sock}; 373*4724848cSchristos my $indata; 374*4724848cSchristos 375*4724848cSchristos #Wait for either the server socket or the client socket to become readable 376*4724848cSchristos $fdset = IO::Select->new($server_sock, $client_sock); 377*4724848cSchristos my @ready; 378*4724848cSchristos my $ctr = 0; 379*4724848cSchristos local $SIG{PIPE} = "IGNORE"; 380*4724848cSchristos $self->{saw_session_ticket} = undef; 381*4724848cSchristos while($fdset->count && $ctr < 10) { 382*4724848cSchristos if (defined($self->{sessionfile})) { 383*4724848cSchristos # s_client got -ign_eof and won't be exiting voluntarily, so we 384*4724848cSchristos # look for data *and* session ticket... 385*4724848cSchristos last if TLSProxy::Message->success() 386*4724848cSchristos && $self->{saw_session_ticket}; 387*4724848cSchristos } 388*4724848cSchristos if (!(@ready = $fdset->can_read(1))) { 389*4724848cSchristos $ctr++; 390*4724848cSchristos next; 391*4724848cSchristos } 392*4724848cSchristos foreach my $hand (@ready) { 393*4724848cSchristos if ($hand == $server_sock) { 394*4724848cSchristos if ($server_sock->sysread($indata, 16384)) { 395*4724848cSchristos if ($indata = $self->process_packet(1, $indata)) { 396*4724848cSchristos $client_sock->syswrite($indata) or goto END; 397*4724848cSchristos } 398*4724848cSchristos $ctr = 0; 399*4724848cSchristos } else { 400*4724848cSchristos $fdset->remove($server_sock); 401*4724848cSchristos $client_sock->shutdown(SHUT_WR); 402*4724848cSchristos } 403*4724848cSchristos } elsif ($hand == $client_sock) { 404*4724848cSchristos if ($client_sock->sysread($indata, 16384)) { 405*4724848cSchristos if ($indata = $self->process_packet(0, $indata)) { 406*4724848cSchristos $server_sock->syswrite($indata) or goto END; 407*4724848cSchristos } 408*4724848cSchristos $ctr = 0; 409*4724848cSchristos } else { 410*4724848cSchristos $fdset->remove($client_sock); 411*4724848cSchristos $server_sock->shutdown(SHUT_WR); 412*4724848cSchristos } 413*4724848cSchristos } else { 414*4724848cSchristos kill(3, $self->{real_serverpid}); 415*4724848cSchristos die "Unexpected handle"; 416*4724848cSchristos } 417*4724848cSchristos } 418*4724848cSchristos } 419*4724848cSchristos 420*4724848cSchristos if ($ctr >= 10) { 421*4724848cSchristos kill(3, $self->{real_serverpid}); 422*4724848cSchristos die "No progress made"; 423*4724848cSchristos } 424*4724848cSchristos 425*4724848cSchristos END: 426*4724848cSchristos print "Connection closed\n"; 427*4724848cSchristos if($server_sock) { 428*4724848cSchristos $server_sock->close(); 429*4724848cSchristos $self->{server_sock} = undef; 430*4724848cSchristos } 431*4724848cSchristos if($client_sock) { 432*4724848cSchristos #Closing this also kills the child process 433*4724848cSchristos $client_sock->close(); 434*4724848cSchristos } 435*4724848cSchristos 436*4724848cSchristos my $pid; 437*4724848cSchristos if (--$self->{serverconnects} == 0) { 438*4724848cSchristos $pid = $self->{serverpid}; 439*4724848cSchristos print "Waiting for 'perl -ne print' process to close: $pid...\n"; 440*4724848cSchristos $pid = waitpid($pid, 0); 441*4724848cSchristos if ($pid > 0) { 442*4724848cSchristos die "exit code $? from 'perl -ne print' process\n" if $? != 0; 443*4724848cSchristos } elsif ($pid == 0) { 444*4724848cSchristos kill(3, $self->{real_serverpid}); 445*4724848cSchristos die "lost control over $self->{serverpid}?"; 446*4724848cSchristos } 447*4724848cSchristos $pid = $self->{real_serverpid}; 448*4724848cSchristos print "Waiting for s_server process to close: $pid...\n"; 449*4724848cSchristos # it's done already, just collect the exit code [and reap]... 450*4724848cSchristos waitpid($pid, 0); 451*4724848cSchristos die "exit code $? from s_server process\n" if $? != 0; 452*4724848cSchristos } else { 453*4724848cSchristos # It's a bit counter-intuitive spot to make next connection to 454*4724848cSchristos # the s_server. Rationale is that established connection works 455*4724848cSchristos # as synchronization point, in sense that this way we know that 456*4724848cSchristos # s_server is actually done with current session... 457*4724848cSchristos $self->connect_to_server(); 458*4724848cSchristos } 459*4724848cSchristos $pid = $self->{clientpid}; 460*4724848cSchristos print "Waiting for s_client process to close: $pid...\n"; 461*4724848cSchristos waitpid($pid, 0); 462*4724848cSchristos 463*4724848cSchristos return 1; 464*4724848cSchristos} 465*4724848cSchristos 466*4724848cSchristossub process_packet 467*4724848cSchristos{ 468*4724848cSchristos my ($self, $server, $packet) = @_; 469*4724848cSchristos my $len_real; 470*4724848cSchristos my $decrypt_len; 471*4724848cSchristos my $data; 472*4724848cSchristos my $recnum; 473*4724848cSchristos 474*4724848cSchristos if ($server) { 475*4724848cSchristos print "Received server packet\n"; 476*4724848cSchristos } else { 477*4724848cSchristos print "Received client packet\n"; 478*4724848cSchristos } 479*4724848cSchristos 480*4724848cSchristos if ($self->{direction} != $server) { 481*4724848cSchristos $self->{flight} = $self->{flight} + 1; 482*4724848cSchristos $self->{direction} = $server; 483*4724848cSchristos } 484*4724848cSchristos 485*4724848cSchristos print "Packet length = ".length($packet)."\n"; 486*4724848cSchristos print "Processing flight ".$self->flight."\n"; 487*4724848cSchristos 488*4724848cSchristos #Return contains the list of record found in the packet followed by the 489*4724848cSchristos #list of messages in those records and any partial message 490*4724848cSchristos my @ret = TLSProxy::Record->get_records($server, $self->flight, 491*4724848cSchristos $self->{partial}[$server].$packet); 492*4724848cSchristos $self->{partial}[$server] = $ret[2]; 493*4724848cSchristos push @{$self->{record_list}}, @{$ret[0]}; 494*4724848cSchristos push @{$self->{message_list}}, @{$ret[1]}; 495*4724848cSchristos 496*4724848cSchristos print "\n"; 497*4724848cSchristos 498*4724848cSchristos if (scalar(@{$ret[0]}) == 0 or length($ret[2]) != 0) { 499*4724848cSchristos return ""; 500*4724848cSchristos } 501*4724848cSchristos 502*4724848cSchristos #Finished parsing. Call user provided filter here 503*4724848cSchristos if (defined $self->filter) { 504*4724848cSchristos $self->filter->($self); 505*4724848cSchristos } 506*4724848cSchristos 507*4724848cSchristos #Take a note on NewSessionTicket 508*4724848cSchristos foreach my $message (reverse @{$self->{message_list}}) { 509*4724848cSchristos if ($message->{mt} == TLSProxy::Message::MT_NEW_SESSION_TICKET) { 510*4724848cSchristos $self->{saw_session_ticket} = 1; 511*4724848cSchristos last; 512*4724848cSchristos } 513*4724848cSchristos } 514*4724848cSchristos 515*4724848cSchristos #Reconstruct the packet 516*4724848cSchristos $packet = ""; 517*4724848cSchristos foreach my $record (@{$self->record_list}) { 518*4724848cSchristos $packet .= $record->reconstruct_record($server); 519*4724848cSchristos } 520*4724848cSchristos 521*4724848cSchristos print "Forwarded packet length = ".length($packet)."\n\n"; 522*4724848cSchristos 523*4724848cSchristos return $packet; 524*4724848cSchristos} 525*4724848cSchristos 526*4724848cSchristos#Read accessors 527*4724848cSchristossub execute 528*4724848cSchristos{ 529*4724848cSchristos my $self = shift; 530*4724848cSchristos return $self->{execute}; 531*4724848cSchristos} 532*4724848cSchristossub cert 533*4724848cSchristos{ 534*4724848cSchristos my $self = shift; 535*4724848cSchristos return $self->{cert}; 536*4724848cSchristos} 537*4724848cSchristossub debug 538*4724848cSchristos{ 539*4724848cSchristos my $self = shift; 540*4724848cSchristos return $self->{debug}; 541*4724848cSchristos} 542*4724848cSchristossub flight 543*4724848cSchristos{ 544*4724848cSchristos my $self = shift; 545*4724848cSchristos return $self->{flight}; 546*4724848cSchristos} 547*4724848cSchristossub record_list 548*4724848cSchristos{ 549*4724848cSchristos my $self = shift; 550*4724848cSchristos return $self->{record_list}; 551*4724848cSchristos} 552*4724848cSchristossub success 553*4724848cSchristos{ 554*4724848cSchristos my $self = shift; 555*4724848cSchristos return $self->{success}; 556*4724848cSchristos} 557*4724848cSchristossub end 558*4724848cSchristos{ 559*4724848cSchristos my $self = shift; 560*4724848cSchristos return $self->{end}; 561*4724848cSchristos} 562*4724848cSchristossub supports_IPv6 563*4724848cSchristos{ 564*4724848cSchristos my $self = shift; 565*4724848cSchristos return $have_IPv6; 566*4724848cSchristos} 567*4724848cSchristossub proxy_addr 568*4724848cSchristos{ 569*4724848cSchristos my $self = shift; 570*4724848cSchristos return $self->{proxy_addr}; 571*4724848cSchristos} 572*4724848cSchristossub proxy_port 573*4724848cSchristos{ 574*4724848cSchristos my $self = shift; 575*4724848cSchristos return $self->{proxy_port}; 576*4724848cSchristos} 577*4724848cSchristossub server_addr 578*4724848cSchristos{ 579*4724848cSchristos my $self = shift; 580*4724848cSchristos return $self->{server_addr}; 581*4724848cSchristos} 582*4724848cSchristossub server_port 583*4724848cSchristos{ 584*4724848cSchristos my $self = shift; 585*4724848cSchristos return $self->{server_port}; 586*4724848cSchristos} 587*4724848cSchristossub serverpid 588*4724848cSchristos{ 589*4724848cSchristos my $self = shift; 590*4724848cSchristos return $self->{serverpid}; 591*4724848cSchristos} 592*4724848cSchristossub clientpid 593*4724848cSchristos{ 594*4724848cSchristos my $self = shift; 595*4724848cSchristos return $self->{clientpid}; 596*4724848cSchristos} 597*4724848cSchristos 598*4724848cSchristos#Read/write accessors 599*4724848cSchristossub filter 600*4724848cSchristos{ 601*4724848cSchristos my $self = shift; 602*4724848cSchristos if (@_) { 603*4724848cSchristos $self->{filter} = shift; 604*4724848cSchristos } 605*4724848cSchristos return $self->{filter}; 606*4724848cSchristos} 607*4724848cSchristossub cipherc 608*4724848cSchristos{ 609*4724848cSchristos my $self = shift; 610*4724848cSchristos if (@_) { 611*4724848cSchristos $self->{cipherc} = shift; 612*4724848cSchristos } 613*4724848cSchristos return $self->{cipherc}; 614*4724848cSchristos} 615*4724848cSchristossub ciphersuitesc 616*4724848cSchristos{ 617*4724848cSchristos my $self = shift; 618*4724848cSchristos if (@_) { 619*4724848cSchristos $self->{ciphersuitesc} = shift; 620*4724848cSchristos } 621*4724848cSchristos return $self->{ciphersuitesc}; 622*4724848cSchristos} 623*4724848cSchristossub ciphers 624*4724848cSchristos{ 625*4724848cSchristos my $self = shift; 626*4724848cSchristos if (@_) { 627*4724848cSchristos $self->{ciphers} = shift; 628*4724848cSchristos } 629*4724848cSchristos return $self->{ciphers}; 630*4724848cSchristos} 631*4724848cSchristossub ciphersuitess 632*4724848cSchristos{ 633*4724848cSchristos my $self = shift; 634*4724848cSchristos if (@_) { 635*4724848cSchristos $self->{ciphersuitess} = shift; 636*4724848cSchristos } 637*4724848cSchristos return $self->{ciphersuitess}; 638*4724848cSchristos} 639*4724848cSchristossub serverflags 640*4724848cSchristos{ 641*4724848cSchristos my $self = shift; 642*4724848cSchristos if (@_) { 643*4724848cSchristos $self->{serverflags} = shift; 644*4724848cSchristos } 645*4724848cSchristos return $self->{serverflags}; 646*4724848cSchristos} 647*4724848cSchristossub clientflags 648*4724848cSchristos{ 649*4724848cSchristos my $self = shift; 650*4724848cSchristos if (@_) { 651*4724848cSchristos $self->{clientflags} = shift; 652*4724848cSchristos } 653*4724848cSchristos return $self->{clientflags}; 654*4724848cSchristos} 655*4724848cSchristossub serverconnects 656*4724848cSchristos{ 657*4724848cSchristos my $self = shift; 658*4724848cSchristos if (@_) { 659*4724848cSchristos $self->{serverconnects} = shift; 660*4724848cSchristos } 661*4724848cSchristos return $self->{serverconnects}; 662*4724848cSchristos} 663*4724848cSchristos# This is a bit ugly because the caller is responsible for keeping the records 664*4724848cSchristos# in sync with the updated message list; simply updating the message list isn't 665*4724848cSchristos# sufficient to get the proxy to forward the new message. 666*4724848cSchristos# But it does the trick for the one test (test_sslsessiontick) that needs it. 667*4724848cSchristossub message_list 668*4724848cSchristos{ 669*4724848cSchristos my $self = shift; 670*4724848cSchristos if (@_) { 671*4724848cSchristos $self->{message_list} = shift; 672*4724848cSchristos } 673*4724848cSchristos return $self->{message_list}; 674*4724848cSchristos} 675*4724848cSchristos 676*4724848cSchristossub fill_known_data 677*4724848cSchristos{ 678*4724848cSchristos my $length = shift; 679*4724848cSchristos my $ret = ""; 680*4724848cSchristos for (my $i = 0; $i < $length; $i++) { 681*4724848cSchristos $ret .= chr($i); 682*4724848cSchristos } 683*4724848cSchristos return $ret; 684*4724848cSchristos} 685*4724848cSchristos 686*4724848cSchristossub is_tls13 687*4724848cSchristos{ 688*4724848cSchristos my $class = shift; 689*4724848cSchristos if (@_) { 690*4724848cSchristos $is_tls13 = shift; 691*4724848cSchristos } 692*4724848cSchristos return $is_tls13; 693*4724848cSchristos} 694*4724848cSchristos 695*4724848cSchristossub reneg 696*4724848cSchristos{ 697*4724848cSchristos my $self = shift; 698*4724848cSchristos if (@_) { 699*4724848cSchristos $self->{reneg} = shift; 700*4724848cSchristos } 701*4724848cSchristos return $self->{reneg}; 702*4724848cSchristos} 703*4724848cSchristos 704*4724848cSchristos#Setting a sessionfile means that the client will not close until the given 705*4724848cSchristos#file exists. This is useful in TLSv1.3 where otherwise s_client will close 706*4724848cSchristos#immediately at the end of the handshake, but before the session has been 707*4724848cSchristos#received from the server. A side effect of this is that s_client never sends 708*4724848cSchristos#a close_notify, so instead we consider success to be when it sends application 709*4724848cSchristos#data over the connection. 710*4724848cSchristossub sessionfile 711*4724848cSchristos{ 712*4724848cSchristos my $self = shift; 713*4724848cSchristos if (@_) { 714*4724848cSchristos $self->{sessionfile} = shift; 715*4724848cSchristos TLSProxy::Message->successondata(1); 716*4724848cSchristos } 717*4724848cSchristos return $self->{sessionfile}; 718*4724848cSchristos} 719*4724848cSchristos 720*4724848cSchristossub ciphersuite 721*4724848cSchristos{ 722*4724848cSchristos my $class = shift; 723*4724848cSchristos if (@_) { 724*4724848cSchristos $ciphersuite = shift; 725*4724848cSchristos } 726*4724848cSchristos return $ciphersuite; 727*4724848cSchristos} 728*4724848cSchristos 729*4724848cSchristos1; 730