Proxy.pm 20 KB

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