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