Proxy.pm 18 KB

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