aboutsummaryrefslogtreecommitdiff
path: root/openssl-1.1.0h/util/perl/TLSProxy
diff options
context:
space:
mode:
authorWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-04-30 00:33:56 +0200
committerWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-04-30 00:33:56 +0200
commitaa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch)
tree4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /openssl-1.1.0h/util/perl/TLSProxy
downloadsmtps-and-pop3s-console-program-master.tar.gz
smtps-and-pop3s-console-program-master.zip
initial/final commitHEADmaster
Diffstat (limited to 'openssl-1.1.0h/util/perl/TLSProxy')
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/ClientHello.pm242
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/Message.pm456
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/NewSessionTicket.pm81
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/Proxy.pm553
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/Record.pm339
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/ServerHello.pm210
-rw-r--r--openssl-1.1.0h/util/perl/TLSProxy/ServerKeyExchange.pm134
7 files changed, 2015 insertions, 0 deletions
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/ClientHello.pm b/openssl-1.1.0h/util/perl/TLSProxy/ClientHello.pm
new file mode 100644
index 0000000..ec739d2
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/ClientHello.pm
@@ -0,0 +1,242 @@
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+package TLSProxy::ClientHello;
+
+use vars '@ISA';
+push @ISA, 'TLSProxy::Message';
+
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens) = @_;
+
+ my $self = $class->SUPER::new(
+ $server,
+ 1,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{client_version} = 0;
+ $self->{random} = [];
+ $self->{session_id_len} = 0;
+ $self->{session} = "";
+ $self->{ciphersuite_len} = 0;
+ $self->{ciphersuites} = [];
+ $self->{comp_meth_len} = 0;
+ $self->{comp_meths} = [];
+ $self->{extensions_len} = 0;
+ $self->{extension_data} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+ my $ptr = 2;
+ my ($client_version) = unpack('n', $self->data);
+ my $random = substr($self->data, $ptr, 32);
+ $ptr += 32;
+ my $session_id_len = unpack('C', substr($self->data, $ptr));
+ $ptr++;
+ my $session = substr($self->data, $ptr, $session_id_len);
+ $ptr += $session_id_len;
+ my $ciphersuite_len = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ my @ciphersuites = unpack('n*', substr($self->data, $ptr,
+ $ciphersuite_len));
+ $ptr += $ciphersuite_len;
+ my $comp_meth_len = unpack('C', substr($self->data, $ptr));
+ $ptr++;
+ my @comp_meths = unpack('C*', substr($self->data, $ptr, $comp_meth_len));
+ $ptr += $comp_meth_len;
+ my $extensions_len = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ #For now we just deal with this as a block of data. In the future we will
+ #want to parse this
+ my $extension_data = substr($self->data, $ptr);
+
+ if (length($extension_data) != $extensions_len) {
+ die "Invalid extension length\n";
+ }
+ my %extensions = ();
+ while (length($extension_data) >= 4) {
+ my ($type, $size) = unpack("nn", $extension_data);
+ my $extdata = substr($extension_data, 4, $size);
+ $extension_data = substr($extension_data, 4 + $size);
+ $extensions{$type} = $extdata;
+ }
+
+ $self->client_version($client_version);
+ $self->random($random);
+ $self->session_id_len($session_id_len);
+ $self->session($session);
+ $self->ciphersuite_len($ciphersuite_len);
+ $self->ciphersuites(\@ciphersuites);
+ $self->comp_meth_len($comp_meth_len);
+ $self->comp_meths(\@comp_meths);
+ $self->extensions_len($extensions_len);
+ $self->extension_data(\%extensions);
+
+ $self->process_extensions();
+
+ print " Client Version:".$client_version."\n";
+ print " Session ID Len:".$session_id_len."\n";
+ print " Ciphersuite len:".$ciphersuite_len."\n";
+ print " Compression Method Len:".$comp_meth_len."\n";
+ print " Extensions Len:".$extensions_len."\n";
+}
+
+#Perform any actions necessary based on the extensions we've seen
+sub process_extensions
+{
+ my $self = shift;
+ my %extensions = %{$self->extension_data};
+
+ #Clear any state from a previous run
+ TLSProxy::Record->etm(0);
+
+ if (exists $extensions{TLSProxy::Message::EXT_ENCRYPT_THEN_MAC}) {
+ TLSProxy::Record->etm(1);
+ }
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+ my $extensions = "";
+
+ $data = pack('n', $self->client_version);
+ $data .= $self->random;
+ $data .= pack('C', $self->session_id_len);
+ $data .= $self->session;
+ $data .= pack('n', $self->ciphersuite_len);
+ $data .= pack("n*", @{$self->ciphersuites});
+ $data .= pack('C', $self->comp_meth_len);
+ $data .= pack("C*", @{$self->comp_meths});
+
+ foreach my $key (keys %{$self->extension_data}) {
+ my $extdata = ${$self->extension_data}{$key};
+ $extensions .= pack("n", $key);
+ $extensions .= pack("n", length($extdata));
+ $extensions .= $extdata;
+ if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) {
+ $extensions .= pack("n", $key);
+ $extensions .= pack("n", length($extdata));
+ $extensions .= $extdata;
+ }
+ }
+
+ $data .= pack('n', length($extensions));
+ $data .= $extensions;
+
+ $self->data($data);
+}
+
+#Read/write accessors
+sub client_version
+{
+ my $self = shift;
+ if (@_) {
+ $self->{client_version} = shift;
+ }
+ return $self->{client_version};
+}
+sub random
+{
+ my $self = shift;
+ if (@_) {
+ $self->{random} = shift;
+ }
+ return $self->{random};
+}
+sub session_id_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{session_id_len} = shift;
+ }
+ return $self->{session_id_len};
+}
+sub session
+{
+ my $self = shift;
+ if (@_) {
+ $self->{session} = shift;
+ }
+ return $self->{session};
+}
+sub ciphersuite_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphersuite_len} = shift;
+ }
+ return $self->{ciphersuite_len};
+}
+sub ciphersuites
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphersuites} = shift;
+ }
+ return $self->{ciphersuites};
+}
+sub comp_meth_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{comp_meth_len} = shift;
+ }
+ return $self->{comp_meth_len};
+}
+sub comp_meths
+{
+ my $self = shift;
+ if (@_) {
+ $self->{comp_meths} = shift;
+ }
+ return $self->{comp_meths};
+}
+sub extensions_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{extensions_len} = shift;
+ }
+ return $self->{extensions_len};
+}
+sub extension_data
+{
+ my $self = shift;
+ if (@_) {
+ $self->{extension_data} = shift;
+ }
+ return $self->{extension_data};
+}
+sub set_extension
+{
+ my ($self, $ext_type, $ext_data) = @_;
+ $self->{extension_data}{$ext_type} = $ext_data;
+}
+sub delete_extension
+{
+ my ($self, $ext_type) = @_;
+ delete $self->{extension_data}{$ext_type};
+}
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/Message.pm b/openssl-1.1.0h/util/perl/TLSProxy/Message.pm
new file mode 100644
index 0000000..0821bde
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/Message.pm
@@ -0,0 +1,456 @@
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+package TLSProxy::Message;
+
+use constant TLS_MESSAGE_HEADER_LENGTH => 4;
+
+#Message types
+use constant {
+ MT_HELLO_REQUEST => 0,
+ MT_CLIENT_HELLO => 1,
+ MT_SERVER_HELLO => 2,
+ MT_NEW_SESSION_TICKET => 4,
+ MT_CERTIFICATE => 11,
+ MT_SERVER_KEY_EXCHANGE => 12,
+ MT_CERTIFICATE_REQUEST => 13,
+ MT_SERVER_HELLO_DONE => 14,
+ MT_CERTIFICATE_VERIFY => 15,
+ MT_CLIENT_KEY_EXCHANGE => 16,
+ MT_FINISHED => 20,
+ MT_CERTIFICATE_STATUS => 22,
+ MT_NEXT_PROTO => 67
+};
+
+#Alert levels
+use constant {
+ AL_LEVEL_WARN => 1,
+ AL_LEVEL_FATAL => 2
+};
+
+#Alert descriptions
+use constant {
+ AL_DESC_CLOSE_NOTIFY => 0,
+ AL_DESC_UNEXPECTED_MESSAGE => 10,
+ AL_DESC_NO_RENEGOTIATION => 100
+};
+
+my %message_type = (
+ MT_HELLO_REQUEST, "HelloRequest",
+ MT_CLIENT_HELLO, "ClientHello",
+ MT_SERVER_HELLO, "ServerHello",
+ MT_NEW_SESSION_TICKET, "NewSessionTicket",
+ MT_CERTIFICATE, "Certificate",
+ MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
+ MT_CERTIFICATE_REQUEST, "CertificateRequest",
+ MT_SERVER_HELLO_DONE, "ServerHelloDone",
+ MT_CERTIFICATE_VERIFY, "CertificateVerify",
+ MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange",
+ MT_FINISHED, "Finished",
+ MT_CERTIFICATE_STATUS, "CertificateStatus",
+ MT_NEXT_PROTO, "NextProto"
+);
+
+use constant {
+ EXT_STATUS_REQUEST => 5,
+ EXT_ENCRYPT_THEN_MAC => 22,
+ EXT_EXTENDED_MASTER_SECRET => 23,
+ EXT_SESSION_TICKET => 35,
+ # This extension does not exist and isn't recognised by OpenSSL.
+ # We use it to test handling of duplicate extensions.
+ EXT_DUPLICATE_EXTENSION => 1234
+};
+
+my $payload = "";
+my $messlen = -1;
+my $mt;
+my $startoffset = -1;
+my $server = 0;
+my $success = 0;
+my $end = 0;
+my @message_rec_list = ();
+my @message_frag_lens = ();
+my $ciphersuite = 0;
+
+sub clear
+{
+ $payload = "";
+ $messlen = -1;
+ $startoffset = -1;
+ $server = 0;
+ $success = 0;
+ $end = 0;
+ @message_rec_list = ();
+ @message_frag_lens = ();
+}
+
+#Class method to extract messages from a record
+sub get_messages
+{
+ my $class = shift;
+ my $serverin = shift;
+ my $record = shift;
+ my @messages = ();
+ my $message;
+
+ @message_frag_lens = ();
+
+ if ($serverin != $server && length($payload) != 0) {
+ die "Changed peer, but we still have fragment data\n";
+ }
+ $server = $serverin;
+
+ if ($record->content_type == TLSProxy::Record::RT_CCS) {
+ if ($payload ne "") {
+ #We can't handle this yet
+ die "CCS received before message data complete\n";
+ }
+ if ($server) {
+ TLSProxy::Record->server_ccs_seen(1);
+ } else {
+ TLSProxy::Record->client_ccs_seen(1);
+ }
+ } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
+ if ($record->len == 0 || $record->len_real == 0) {
+ print " Message truncated\n";
+ } else {
+ my $recoffset = 0;
+
+ if (length $payload > 0) {
+ #We are continuing processing a message started in a previous
+ #record. Add this record to the list associated with this
+ #message
+ push @message_rec_list, $record;
+
+ if ($messlen <= length($payload)) {
+ #Shouldn't happen
+ die "Internal error: invalid messlen: ".$messlen
+ ." payload length:".length($payload)."\n";
+ }
+ if (length($payload) + $record->decrypt_len >= $messlen) {
+ #We can complete the message with this record
+ $recoffset = $messlen - length($payload);
+ $payload .= substr($record->decrypt_data, 0, $recoffset);
+ push @message_frag_lens, $recoffset;
+ $message = create_message($server, $mt, $payload,
+ $startoffset);
+ push @messages, $message;
+
+ $payload = "";
+ } else {
+ #This is just part of the total message
+ $payload .= $record->decrypt_data;
+ $recoffset = $record->decrypt_len;
+ push @message_frag_lens, $record->decrypt_len;
+ }
+ print " Partial message data read: ".$recoffset." bytes\n";
+ }
+
+ while ($record->decrypt_len > $recoffset) {
+ #We are at the start of a new message
+ if ($record->decrypt_len - $recoffset < 4) {
+ #Whilst technically probably valid we can't cope with this
+ die "End of record in the middle of a message header\n";
+ }
+ @message_rec_list = ($record);
+ my $lenhi;
+ my $lenlo;
+ ($mt, $lenhi, $lenlo) = unpack('CnC',
+ substr($record->decrypt_data,
+ $recoffset));
+ $messlen = ($lenhi << 8) | $lenlo;
+ print " Message type: $message_type{$mt}\n";
+ print " Message Length: $messlen\n";
+ $startoffset = $recoffset;
+ $recoffset += 4;
+ $payload = "";
+
+ if ($recoffset <= $record->decrypt_len) {
+ #Some payload data is present in this record
+ if ($record->decrypt_len - $recoffset >= $messlen) {
+ #We can complete the message with this record
+ $payload .= substr($record->decrypt_data, $recoffset,
+ $messlen);
+ $recoffset += $messlen;
+ push @message_frag_lens, $messlen;
+ $message = create_message($server, $mt, $payload,
+ $startoffset);
+ push @messages, $message;
+
+ $payload = "";
+ } else {
+ #This is just part of the total message
+ $payload .= substr($record->decrypt_data, $recoffset,
+ $record->decrypt_len - $recoffset);
+ $recoffset = $record->decrypt_len;
+ push @message_frag_lens, $recoffset;
+ }
+ }
+ }
+ }
+ } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) {
+ print " [ENCRYPTED APPLICATION DATA]\n";
+ print " [".$record->decrypt_data."]\n";
+ } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) {
+ my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data);
+ #A CloseNotify from the client indicates we have finished successfully
+ #(we assume)
+ if (!$end && !$server && $alertlev == AL_LEVEL_WARN
+ && $alertdesc == AL_DESC_CLOSE_NOTIFY) {
+ $success = 1;
+ }
+ #All alerts end the test
+ $end = 1;
+ }
+
+ return @messages;
+}
+
+#Function to work out which sub-class we need to create and then
+#construct it
+sub create_message
+{
+ my ($server, $mt, $data, $startoffset) = @_;
+ my $message;
+
+ #We only support ClientHello in this version...needs to be extended for
+ #others
+ if ($mt == MT_CLIENT_HELLO) {
+ $message = TLSProxy::ClientHello->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } elsif ($mt == MT_SERVER_HELLO) {
+ $message = TLSProxy::ServerHello->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
+ $message = TLSProxy::ServerKeyExchange->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } elsif ($mt == MT_NEW_SESSION_TICKET) {
+ $message = TLSProxy::NewSessionTicket->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } else {
+ #Unknown message type
+ $message = TLSProxy::Message->new(
+ $server,
+ $mt,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ }
+
+ return $message;
+}
+
+sub end
+{
+ my $class = shift;
+ return $end;
+}
+sub success
+{
+ my $class = shift;
+ return $success;
+}
+sub fail
+{
+ my $class = shift;
+ return !$success && $end;
+}
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $mt,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens) = @_;
+
+ my $self = {
+ server => $server,
+ data => $data,
+ records => $records,
+ mt => $mt,
+ startoffset => $startoffset,
+ message_frag_lens => $message_frag_lens
+ };
+
+ return bless $self, $class;
+}
+
+sub ciphersuite
+{
+ my $class = shift;
+ if (@_) {
+ $ciphersuite = shift;
+ }
+ return $ciphersuite;
+}
+
+#Update all the underlying records with the modified data from this message
+#Note: Does not currently support re-encrypting
+sub repack
+{
+ my $self = shift;
+ my $msgdata;
+
+ my $numrecs = $#{$self->records};
+
+ $self->set_message_contents();
+
+ my $lenhi;
+ my $lenlo;
+
+ $lenlo = length($self->data) & 0xff;
+ $lenhi = length($self->data) >> 8;
+ $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data;
+
+ if ($numrecs == 0) {
+ #The message is fully contained within one record
+ my ($rec) = @{$self->records};
+ my $recdata = $rec->decrypt_data;
+
+ my $old_length;
+
+ # We use empty message_frag_lens to indicates that pre-repacking,
+ # the message wasn't present. The first fragment length doesn't include
+ # the TLS header, so we need to check and compute the right length.
+ if (@{$self->message_frag_lens}) {
+ $old_length = ${$self->message_frag_lens}[0] +
+ TLS_MESSAGE_HEADER_LENGTH;
+ } else {
+ $old_length = 0;
+ }
+
+ my $prefix = substr($recdata, 0, $self->startoffset);
+ my $suffix = substr($recdata, $self->startoffset + $old_length);
+
+ $rec->decrypt_data($prefix.($msgdata).($suffix));
+ # TODO(openssl-team): don't keep explicit lengths.
+ # (If a length override is ever needed to construct invalid packets,
+ # use an explicit override field instead.)
+ $rec->decrypt_len(length($rec->decrypt_data));
+ $rec->len($rec->len + length($msgdata) - $old_length);
+ # Don't support re-encryption.
+ $rec->data($rec->decrypt_data);
+
+ #Update the fragment len in case we changed it above
+ ${$self->message_frag_lens}[0] = length($msgdata)
+ - TLS_MESSAGE_HEADER_LENGTH;
+ return;
+ }
+
+ #Note we don't currently support changing a fragmented message length
+ my $recctr = 0;
+ my $datadone = 0;
+ foreach my $rec (@{$self->records}) {
+ my $recdata = $rec->decrypt_data;
+ if ($recctr == 0) {
+ #This is the first record
+ my $remainlen = length($recdata) - $self->startoffset;
+ $rec->data(substr($recdata, 0, $self->startoffset)
+ .substr(($msgdata), 0, $remainlen));
+ $datadone += $remainlen;
+ } elsif ($recctr + 1 == $numrecs) {
+ #This is the last record
+ $rec->data(substr($msgdata, $datadone));
+ } else {
+ #This is a middle record
+ $rec->data(substr($msgdata, $datadone, length($rec->data)));
+ $datadone += length($rec->data);
+ }
+ $recctr++;
+ }
+}
+
+#To be overridden by sub-classes
+sub set_message_contents
+{
+}
+
+#Read only accessors
+sub server
+{
+ my $self = shift;
+ return $self->{server};
+}
+
+#Read/write accessors
+sub mt
+{
+ my $self = shift;
+ if (@_) {
+ $self->{mt} = shift;
+ }
+ return $self->{mt};
+}
+sub data
+{
+ my $self = shift;
+ if (@_) {
+ $self->{data} = shift;
+ }
+ return $self->{data};
+}
+sub records
+{
+ my $self = shift;
+ if (@_) {
+ $self->{records} = shift;
+ }
+ return $self->{records};
+}
+sub startoffset
+{
+ my $self = shift;
+ if (@_) {
+ $self->{startoffset} = shift;
+ }
+ return $self->{startoffset};
+}
+sub message_frag_lens
+{
+ my $self = shift;
+ if (@_) {
+ $self->{message_frag_lens} = shift;
+ }
+ return $self->{message_frag_lens};
+}
+sub encoded_length
+{
+ my $self = shift;
+ return TLS_MESSAGE_HEADER_LENGTH + length($self->data);
+}
+
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/NewSessionTicket.pm b/openssl-1.1.0h/util/perl/TLSProxy/NewSessionTicket.pm
new file mode 100644
index 0000000..e509985
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/NewSessionTicket.pm
@@ -0,0 +1,81 @@
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+package TLSProxy::NewSessionTicket;
+
+use vars '@ISA';
+push @ISA, 'TLSProxy::Message';
+
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens) = @_;
+
+ my $self = $class->SUPER::new(
+ $server,
+ TLSProxy::Message::MT_NEW_SESSION_TICKET,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{ticket_lifetime_hint} = 0;
+ $self->{ticket} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+
+ my $ticket_lifetime_hint = unpack('N', $self->data);
+ my $ticket_len = unpack('n', $self->data);
+ my $ticket = substr($self->data, 6, $ticket_len);
+
+ $self->ticket_lifetime_hint($ticket_lifetime_hint);
+ $self->ticket($ticket);
+}
+
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+
+ $data = pack('N', $self->ticket_lifetime_hint);
+ $data .= pack('n', length($self->ticket));
+ $data .= $self->ticket;
+
+ $self->data($data);
+}
+
+#Read/write accessors
+sub ticket_lifetime_hint
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ticket_lifetime_hint} = shift;
+ }
+ return $self->{ticket_lifetime_hint};
+}
+sub ticket
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ticket} = shift;
+ }
+ return $self->{ticket};
+}
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/Proxy.pm b/openssl-1.1.0h/util/perl/TLSProxy/Proxy.pm
new file mode 100644
index 0000000..de14362
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/Proxy.pm
@@ -0,0 +1,553 @@
+# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use POSIX ":sys_wait_h";
+
+package TLSProxy::Proxy;
+
+use File::Spec;
+use IO::Socket;
+use IO::Select;
+use TLSProxy::Record;
+use TLSProxy::Message;
+use TLSProxy::ClientHello;
+use TLSProxy::ServerHello;
+use TLSProxy::ServerKeyExchange;
+use TLSProxy::NewSessionTicket;
+use Time::HiRes qw/usleep/;
+
+my $have_IPv6 = 0;
+my $IP_factory;
+
+sub new
+{
+ my $class = shift;
+ my ($filter,
+ $execute,
+ $cert,
+ $debug) = @_;
+
+ my $self = {
+ #Public read/write
+ proxy_addr => "localhost",
+ proxy_port => 4453,
+ server_addr => "localhost",
+ server_port => 4443,
+ filter => $filter,
+ serverflags => "",
+ clientflags => "",
+ serverconnects => 1,
+ serverpid => 0,
+ clientpid => 0,
+ reneg => 0,
+
+ #Public read
+ execute => $execute,
+ cert => $cert,
+ debug => $debug,
+ cipherc => "",
+ ciphers => "AES128-SHA",
+ flight => -1,
+ direction => -1,
+ partial => ["", ""],
+ record_list => [],
+ message_list => [],
+ };
+
+ # IO::Socket::IP is on the core module list, IO::Socket::INET6 isn't.
+ # However, IO::Socket::INET6 is older and is said to be more widely
+ # deployed for the moment, and may have less bugs, so we try the latter
+ # first, then fall back on the code modules. Worst case scenario, we
+ # fall back to IO::Socket::INET, only supports IPv4.
+ eval {
+ require IO::Socket::INET6;
+ my $s = IO::Socket::INET6->new(
+ LocalAddr => "::1",
+ LocalPort => 0,
+ Listen=>1,
+ );
+ $s or die "\n";
+ $s->close();
+ };
+ if ($@ eq "") {
+ $IP_factory = sub { IO::Socket::INET6->new(@_); };
+ $have_IPv6 = 1;
+ } else {
+ eval {
+ require IO::Socket::IP;
+ my $s = IO::Socket::IP->new(
+ LocalAddr => "::1",
+ LocalPort => 0,
+ Listen=>1,
+ );
+ $s or die "\n";
+ $s->close();
+ };
+ if ($@ eq "") {
+ $IP_factory = sub { IO::Socket::IP->new(@_); };
+ $have_IPv6 = 1;
+ } else {
+ $IP_factory = sub { IO::Socket::INET->new(@_); };
+ }
+ }
+
+ # Create the Proxy socket
+ my $proxaddr = $self->{proxy_addr};
+ $proxaddr =~ s/[\[\]]//g; # Remove [ and ]
+ my @proxyargs = (
+ LocalHost => $proxaddr,
+ LocalPort => $self->{proxy_port},
+ Proto => "tcp",
+ Listen => SOMAXCONN,
+ );
+ push @proxyargs, ReuseAddr => 1
+ unless $^O eq "MSWin32";
+ $self->{proxy_sock} = $IP_factory->(@proxyargs);
+
+ if ($self->{proxy_sock}) {
+ print "Proxy started on port ".$self->{proxy_port}."\n";
+ } else {
+ warn "Failed creating proxy socket (".$proxaddr.",".$self->{proxy_port}."): $!\n";
+ }
+
+ return bless $self, $class;
+}
+
+sub DESTROY
+{
+ my $self = shift;
+
+ $self->{proxy_sock}->close() if $self->{proxy_sock};
+}
+
+sub clearClient
+{
+ my $self = shift;
+
+ $self->{cipherc} = "";
+ $self->{flight} = -1;
+ $self->{direction} = -1;
+ $self->{partial} = ["", ""];
+ $self->{record_list} = [];
+ $self->{message_list} = [];
+ $self->{clientflags} = "";
+ $self->{clientpid} = 0;
+
+ TLSProxy::Message->clear();
+ TLSProxy::Record->clear();
+}
+
+sub clear
+{
+ my $self = shift;
+
+ $self->clearClient;
+ $self->{ciphers} = "AES128-SHA";
+ $self->{serverflags} = "";
+ $self->{serverconnects} = 1;
+ $self->{serverpid} = 0;
+ $self->{reneg} = 0;
+}
+
+sub restart
+{
+ my $self = shift;
+
+ $self->clear;
+ $self->start;
+}
+
+sub clientrestart
+{
+ my $self = shift;
+
+ $self->clear;
+ $self->clientstart;
+}
+
+sub start
+{
+ my ($self) = shift;
+ my $pid;
+
+ if ($self->{proxy_sock} == 0) {
+ return 0;
+ }
+
+ $pid = fork();
+ if ($pid == 0) {
+ my $execcmd = $self->execute
+ ." s_server -max_protocol TLSv1.2 -no_comp -rev -engine ossltest -accept "
+ .($self->server_port)
+ ." -cert ".$self->cert." -naccept ".$self->serverconnects;
+ unless ($self->supports_IPv6) {
+ $execcmd .= " -4";
+ }
+ if ($self->ciphers ne "") {
+ $execcmd .= " -cipher ".$self->ciphers;
+ }
+ if ($self->serverflags ne "") {
+ $execcmd .= " ".$self->serverflags;
+ }
+ if ($self->debug) {
+ print STDERR "Server command: $execcmd\n";
+ }
+ exec($execcmd);
+ }
+ $self->serverpid($pid);
+
+ return $self->clientstart;
+}
+
+sub clientstart
+{
+ my ($self) = shift;
+ my $oldstdout;
+
+ if ($self->execute) {
+ my $pid = fork();
+ if ($pid == 0) {
+ my $echostr;
+ if ($self->reneg()) {
+ $echostr = "R";
+ } else {
+ $echostr = "test";
+ }
+ my $execcmd = "echo ".$echostr." | ".$self->execute
+ ." s_client -max_protocol TLSv1.2 -engine ossltest -connect "
+ .($self->proxy_addr).":".($self->proxy_port);
+ unless ($self->supports_IPv6) {
+ $execcmd .= " -4";
+ }
+ if ($self->cipherc ne "") {
+ $execcmd .= " -cipher ".$self->cipherc;
+ }
+ if ($self->clientflags ne "") {
+ $execcmd .= " ".$self->clientflags;
+ }
+ if ($self->debug) {
+ print STDERR "Client command: $execcmd\n";
+ }
+ exec($execcmd);
+ }
+ $self->clientpid($pid);
+ }
+
+ # Wait for incoming connection from client
+ my $client_sock;
+ if(!($client_sock = $self->{proxy_sock}->accept())) {
+ warn "Failed accepting incoming connection: $!\n";
+ return 0;
+ }
+
+ print "Connection opened\n";
+
+ # Now connect to the server
+ my $retry = 50;
+ my $server_sock;
+ #We loop over this a few times because sometimes s_server can take a while
+ #to start up
+ do {
+ my $servaddr = $self->server_addr;
+ $servaddr =~ s/[\[\]]//g; # Remove [ and ]
+ eval {
+ $server_sock = $IP_factory->(
+ PeerAddr => $servaddr,
+ PeerPort => $self->server_port,
+ MultiHomed => 1,
+ Proto => 'tcp'
+ );
+ };
+
+ $retry--;
+ #Some buggy IP factories can return a defined server_sock that hasn't
+ #actually connected, so we check peerport too
+ if ($@ || !defined($server_sock) || !defined($server_sock->peerport)) {
+ $server_sock->close() if defined($server_sock);
+ undef $server_sock;
+ if ($retry) {
+ #Sleep for a short while
+ select(undef, undef, undef, 0.1);
+ } else {
+ warn "Failed to start up server (".$servaddr.",".$self->server_port."): $!\n";
+ return 0;
+ }
+ }
+ } while (!$server_sock);
+
+ my $sel = IO::Select->new($server_sock, $client_sock);
+ my $indata;
+ my @handles = ($server_sock, $client_sock);
+
+ #Wait for either the server socket or the client socket to become readable
+ my @ready;
+ local $SIG{PIPE} = "IGNORE";
+ while(!(TLSProxy::Message->end) && (@ready = $sel->can_read)) {
+ foreach my $hand (@ready) {
+ if ($hand == $server_sock) {
+ $server_sock->sysread($indata, 16384) or goto END;
+ $indata = $self->process_packet(1, $indata);
+ $client_sock->syswrite($indata);
+ } elsif ($hand == $client_sock) {
+ $client_sock->sysread($indata, 16384) or goto END;
+ $indata = $self->process_packet(0, $indata);
+ $server_sock->syswrite($indata);
+ } else {
+ print "Err\n";
+ goto END;
+ }
+ }
+ }
+
+ END:
+ print "Connection closed\n";
+ if($server_sock) {
+ $server_sock->close();
+ }
+ if($client_sock) {
+ #Closing this also kills the child process
+ $client_sock->close();
+ }
+ if(!$self->debug) {
+ select($oldstdout);
+ }
+ $self->serverconnects($self->serverconnects - 1);
+ if ($self->serverconnects == 0) {
+ die "serverpid is zero\n" if $self->serverpid == 0;
+ print "Waiting for server process to close: "
+ .$self->serverpid."\n";
+ waitpid( $self->serverpid, 0);
+ die "exit code $? from server process\n" if $? != 0;
+ } else {
+ # Give s_server sufficient time to finish what it was doing
+ usleep(250000);
+ }
+ die "clientpid is zero\n" if $self->clientpid == 0;
+ print "Waiting for client process to close: ".$self->clientpid."\n";
+ waitpid($self->clientpid, 0);
+
+ return 1;
+}
+
+sub process_packet
+{
+ my ($self, $server, $packet) = @_;
+ my $len_real;
+ my $decrypt_len;
+ my $data;
+ my $recnum;
+
+ if ($server) {
+ print "Received server packet\n";
+ } else {
+ print "Received client packet\n";
+ }
+
+ if ($self->{direction} != $server) {
+ $self->{flight} = $self->{flight} + 1;
+ $self->{direction} = $server;
+ }
+
+ print "Packet length = ".length($packet)."\n";
+ print "Processing flight ".$self->flight."\n";
+
+ #Return contains the list of record found in the packet followed by the
+ #list of messages in those records and any partial message
+ my @ret = TLSProxy::Record->get_records($server, $self->flight, $self->{partial}[$server].$packet);
+ $self->{partial}[$server] = $ret[2];
+ push @{$self->record_list}, @{$ret[0]};
+ push @{$self->{message_list}}, @{$ret[1]};
+
+ print "\n";
+
+ if (scalar(@{$ret[0]}) == 0 or length($ret[2]) != 0) {
+ return "";
+ }
+
+ #Finished parsing. Call user provided filter here
+ if (defined $self->filter) {
+ $self->filter->($self);
+ }
+
+ #Reconstruct the packet
+ $packet = "";
+ foreach my $record (@{$self->record_list}) {
+ $packet .= $record->reconstruct_record();
+ }
+
+ print "Forwarded packet length = ".length($packet)."\n\n";
+
+ return $packet;
+}
+
+#Read accessors
+sub execute
+{
+ my $self = shift;
+ return $self->{execute};
+}
+sub cert
+{
+ my $self = shift;
+ return $self->{cert};
+}
+sub debug
+{
+ my $self = shift;
+ return $self->{debug};
+}
+sub flight
+{
+ my $self = shift;
+ return $self->{flight};
+}
+sub record_list
+{
+ my $self = shift;
+ return $self->{record_list};
+}
+sub success
+{
+ my $self = shift;
+ return $self->{success};
+}
+sub end
+{
+ my $self = shift;
+ return $self->{end};
+}
+sub supports_IPv6
+{
+ my $self = shift;
+ return $have_IPv6;
+}
+sub proxy_addr
+{
+ my $self = shift;
+ return $self->{proxy_addr};
+}
+sub proxy_port
+{
+ my $self = shift;
+ return $self->{proxy_port};
+}
+
+#Read/write accessors
+sub server_addr
+{
+ my $self = shift;
+ if (@_) {
+ $self->{server_addr} = shift;
+ }
+ return $self->{server_addr};
+}
+sub server_port
+{
+ my $self = shift;
+ if (@_) {
+ $self->{server_port} = shift;
+ }
+ return $self->{server_port};
+}
+sub filter
+{
+ my $self = shift;
+ if (@_) {
+ $self->{filter} = shift;
+ }
+ return $self->{filter};
+}
+sub cipherc
+{
+ my $self = shift;
+ if (@_) {
+ $self->{cipherc} = shift;
+ }
+ return $self->{cipherc};
+}
+sub ciphers
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphers} = shift;
+ }
+ return $self->{ciphers};
+}
+sub serverflags
+{
+ my $self = shift;
+ if (@_) {
+ $self->{serverflags} = shift;
+ }
+ return $self->{serverflags};
+}
+sub clientflags
+{
+ my $self = shift;
+ if (@_) {
+ $self->{clientflags} = shift;
+ }
+ return $self->{clientflags};
+}
+sub serverconnects
+{
+ my $self = shift;
+ if (@_) {
+ $self->{serverconnects} = shift;
+ }
+ return $self->{serverconnects};
+}
+# This is a bit ugly because the caller is responsible for keeping the records
+# in sync with the updated message list; simply updating the message list isn't
+# sufficient to get the proxy to forward the new message.
+# But it does the trick for the one test (test_sslsessiontick) that needs it.
+sub message_list
+{
+ my $self = shift;
+ if (@_) {
+ $self->{message_list} = shift;
+ }
+ return $self->{message_list};
+}
+sub serverpid
+{
+ my $self = shift;
+ if (@_) {
+ $self->{serverpid} = shift;
+ }
+ return $self->{serverpid};
+}
+sub clientpid
+{
+ my $self = shift;
+ if (@_) {
+ $self->{clientpid} = shift;
+ }
+ return $self->{clientpid};
+}
+
+sub fill_known_data
+{
+ my $length = shift;
+ my $ret = "";
+ for (my $i = 0; $i < $length; $i++) {
+ $ret .= chr($i);
+ }
+ return $ret;
+}
+
+sub reneg
+{
+ my $self = shift;
+ if (@_) {
+ $self->{reneg} = shift;
+ }
+ return $self->{reneg};
+}
+
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/Record.pm b/openssl-1.1.0h/util/perl/TLSProxy/Record.pm
new file mode 100644
index 0000000..786ba0c
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/Record.pm
@@ -0,0 +1,339 @@
+# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+use TLSProxy::Proxy;
+
+package TLSProxy::Record;
+
+my $server_ccs_seen = 0;
+my $client_ccs_seen = 0;
+my $etm = 0;
+
+use constant TLS_RECORD_HEADER_LENGTH => 5;
+
+#Record types
+use constant {
+ RT_APPLICATION_DATA => 23,
+ RT_HANDSHAKE => 22,
+ RT_ALERT => 21,
+ RT_CCS => 20,
+ RT_UNKNOWN => 100
+};
+
+my %record_type = (
+ RT_APPLICATION_DATA, "APPLICATION DATA",
+ RT_HANDSHAKE, "HANDSHAKE",
+ RT_ALERT, "ALERT",
+ RT_CCS, "CCS",
+ RT_UNKNOWN, "UNKNOWN"
+);
+
+use constant {
+ VERS_TLS_1_3 => 772,
+ VERS_TLS_1_2 => 771,
+ VERS_TLS_1_1 => 770,
+ VERS_TLS_1_0 => 769,
+ VERS_SSL_3_0 => 768,
+ VERS_SSL_LT_3_0 => 767
+};
+
+my %tls_version = (
+ VERS_TLS_1_3, "TLS1.3",
+ VERS_TLS_1_2, "TLS1.2",
+ VERS_TLS_1_1, "TLS1.1",
+ VERS_TLS_1_0, "TLS1.0",
+ VERS_SSL_3_0, "SSL3",
+ VERS_SSL_LT_3_0, "SSL<3"
+);
+
+#Class method to extract records from a packet of data
+sub get_records
+{
+ my $class = shift;
+ my $server = shift;
+ my $flight = shift;
+ my $packet = shift;
+ my $partial = "";
+ my @record_list = ();
+ my @message_list = ();
+ my $data;
+ my $content_type;
+ my $version;
+ my $len;
+ my $len_real;
+ my $decrypt_len;
+
+ my $recnum = 1;
+ while (length ($packet) > 0) {
+ print " Record $recnum";
+ if ($server) {
+ print " (server -> client)\n";
+ } else {
+ print " (client -> server)\n";
+ }
+ #Get the record header
+ if (length($packet) < TLS_RECORD_HEADER_LENGTH
+ || length($packet) < 5 + unpack("n", substr($packet, 3, 2))) {
+ print "Partial data : ".length($packet)." bytes\n";
+ $partial = $packet;
+ $packet = "";
+ } else {
+ ($content_type, $version, $len) = unpack('CnnC*', $packet);
+ $data = substr($packet, 5, $len);
+
+ print " Content type: ".$record_type{$content_type}."\n";
+ print " Version: $tls_version{$version}\n";
+ print " Length: $len";
+ if ($len == length($data)) {
+ print "\n";
+ $decrypt_len = $len_real = $len;
+ } else {
+ print " (expected), ".length($data)." (actual)\n";
+ $decrypt_len = $len_real = length($data);
+ }
+
+ my $record = TLSProxy::Record->new(
+ $flight,
+ $content_type,
+ $version,
+ $len,
+ 0,
+ $len_real,
+ $decrypt_len,
+ substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real),
+ substr($packet, TLS_RECORD_HEADER_LENGTH, $len_real)
+ );
+
+ if (($server && $server_ccs_seen)
+ || (!$server && $client_ccs_seen)) {
+ if ($etm) {
+ $record->decryptETM();
+ } else {
+ $record->decrypt();
+ }
+ }
+
+ push @record_list, $record;
+
+ #Now figure out what messages are contained within this record
+ my @messages = TLSProxy::Message->get_messages($server, $record);
+ push @message_list, @messages;
+
+ $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len_real);
+ $recnum++;
+ }
+ }
+
+ return (\@record_list, \@message_list, $partial);
+}
+
+sub clear
+{
+ $server_ccs_seen = 0;
+ $client_ccs_seen = 0;
+}
+
+#Class level accessors
+sub server_ccs_seen
+{
+ my $class = shift;
+ if (@_) {
+ $server_ccs_seen = shift;
+ }
+ return $server_ccs_seen;
+}
+sub client_ccs_seen
+{
+ my $class = shift;
+ if (@_) {
+ $client_ccs_seen = shift;
+ }
+ return $client_ccs_seen;
+}
+#Enable/Disable Encrypt-then-MAC
+sub etm
+{
+ my $class = shift;
+ if (@_) {
+ $etm = shift;
+ }
+ return $etm;
+}
+
+sub new
+{
+ my $class = shift;
+ my ($flight,
+ $content_type,
+ $version,
+ $len,
+ $sslv2,
+ $len_real,
+ $decrypt_len,
+ $data,
+ $decrypt_data) = @_;
+
+ my $self = {
+ flight => $flight,
+ content_type => $content_type,
+ version => $version,
+ len => $len,
+ sslv2 => $sslv2,
+ len_real => $len_real,
+ decrypt_len => $decrypt_len,
+ data => $data,
+ decrypt_data => $decrypt_data,
+ orig_decrypt_data => $decrypt_data,
+ sent => 0
+ };
+
+ return bless $self, $class;
+}
+
+#Decrypt using encrypt-then-MAC
+sub decryptETM
+{
+ my ($self) = shift;
+
+ my $data = $self->data;
+
+ if($self->version >= VERS_TLS_1_1()) {
+ #TLS1.1+ has an explicit IV. Throw it away
+ $data = substr($data, 16);
+ }
+
+ #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME)
+ $data = substr($data, 0, length($data) - 20);
+
+ #Find out what the padding byte is
+ my $padval = unpack("C", substr($data, length($data) - 1));
+
+ #Throw away the padding
+ $data = substr($data, 0, length($data) - ($padval + 1));
+
+ $self->decrypt_data($data);
+ $self->decrypt_len(length($data));
+
+ return $data;
+}
+
+#Standard decrypt
+sub decrypt()
+{
+ my ($self) = shift;
+
+ my $data = $self->data;
+
+ if($self->version >= VERS_TLS_1_1()) {
+ #TLS1.1+ has an explicit IV. Throw it away
+ $data = substr($data, 16);
+ }
+
+ #Find out what the padding byte is
+ my $padval = unpack("C", substr($data, length($data) - 1));
+
+ #Throw away the padding
+ $data = substr($data, 0, length($data) - ($padval + 1));
+
+ #Throw away the MAC (assumes MAC is 20 bytes for now. FIXME)
+ $data = substr($data, 0, length($data) - 20);
+
+ $self->decrypt_data($data);
+ $self->decrypt_len(length($data));
+
+ return $data;
+}
+
+#Reconstruct the on-the-wire record representation
+sub reconstruct_record
+{
+ my $self = shift;
+ my $data;
+
+ if ($self->{sent}) {
+ return "";
+ }
+ $self->{sent} = 1;
+
+ if ($self->sslv2) {
+ $data = pack('n', $self->len | 0x8000);
+ } else {
+ $data = pack('Cnn', $self->content_type, $self->version, $self->len);
+ }
+ $data .= $self->data;
+
+ return $data;
+}
+
+#Read only accessors
+sub flight
+{
+ my $self = shift;
+ return $self->{flight};
+}
+sub content_type
+{
+ my $self = shift;
+ return $self->{content_type};
+}
+sub version
+{
+ my $self = shift;
+ return $self->{version};
+}
+sub sslv2
+{
+ my $self = shift;
+ return $self->{sslv2};
+}
+sub len_real
+{
+ my $self = shift;
+ return $self->{len_real};
+}
+sub orig_decrypt_data
+{
+ my $self = shift;
+ return $self->{orig_decrypt_data};
+}
+
+#Read/write accessors
+sub decrypt_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{decrypt_len} = shift;
+ }
+ return $self->{decrypt_len};
+}
+sub data
+{
+ my $self = shift;
+ if (@_) {
+ $self->{data} = shift;
+ }
+ return $self->{data};
+}
+sub decrypt_data
+{
+ my $self = shift;
+ if (@_) {
+ $self->{decrypt_data} = shift;
+ }
+ return $self->{decrypt_data};
+}
+sub len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{len} = shift;
+ }
+ return $self->{len};
+}
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/ServerHello.pm b/openssl-1.1.0h/util/perl/TLSProxy/ServerHello.pm
new file mode 100644
index 0000000..79a8be9
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/ServerHello.pm
@@ -0,0 +1,210 @@
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+package TLSProxy::ServerHello;
+
+use vars '@ISA';
+push @ISA, 'TLSProxy::Message';
+
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens) = @_;
+
+ my $self = $class->SUPER::new(
+ $server,
+ TLSProxy::Message::MT_SERVER_HELLO,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{server_version} = 0;
+ $self->{random} = [];
+ $self->{session_id_len} = 0;
+ $self->{session} = "";
+ $self->{ciphersuite} = 0;
+ $self->{comp_meth} = 0;
+ $self->{extension_data} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+ my $ptr = 2;
+ my ($server_version) = unpack('n', $self->data);
+ my $random = substr($self->data, $ptr, 32);
+ $ptr += 32;
+ my $session_id_len = unpack('C', substr($self->data, $ptr));
+ $ptr++;
+ my $session = substr($self->data, $ptr, $session_id_len);
+ $ptr += $session_id_len;
+ my $ciphersuite = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ my $comp_meth = unpack('C', substr($self->data, $ptr));
+ $ptr++;
+ my $extensions_len = unpack('n', substr($self->data, $ptr));
+ if (!defined $extensions_len) {
+ $extensions_len = 0;
+ } else {
+ $ptr += 2;
+ }
+ #For now we just deal with this as a block of data. In the future we will
+ #want to parse this
+ my $extension_data;
+ if ($extensions_len != 0) {
+ $extension_data = substr($self->data, $ptr);
+
+ if (length($extension_data) != $extensions_len) {
+ die "Invalid extension length\n";
+ }
+ } else {
+ if (length($self->data) != $ptr) {
+ die "Invalid extension length\n";
+ }
+ $extension_data = "";
+ }
+ my %extensions = ();
+ while (length($extension_data) >= 4) {
+ my ($type, $size) = unpack("nn", $extension_data);
+ my $extdata = substr($extension_data, 4, $size);
+ $extension_data = substr($extension_data, 4 + $size);
+ $extensions{$type} = $extdata;
+ }
+
+ $self->server_version($server_version);
+ $self->random($random);
+ $self->session_id_len($session_id_len);
+ $self->session($session);
+ $self->ciphersuite($ciphersuite);
+ $self->comp_meth($comp_meth);
+ $self->extension_data(\%extensions);
+
+ $self->process_data();
+
+ print " Server Version:".$server_version."\n";
+ print " Session ID Len:".$session_id_len."\n";
+ print " Ciphersuite:".$ciphersuite."\n";
+ print " Compression Method:".$comp_meth."\n";
+ print " Extensions Len:".$extensions_len."\n";
+}
+
+#Perform any actions necessary based on the data we've seen
+sub process_data
+{
+ my $self = shift;
+
+ TLSProxy::Message->ciphersuite($self->ciphersuite);
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+ my $extensions = "";
+
+ $data = pack('n', $self->server_version);
+ $data .= $self->random;
+ $data .= pack('C', $self->session_id_len);
+ $data .= $self->session;
+ $data .= pack('n', $self->ciphersuite);
+ $data .= pack('C', $self->comp_meth);
+
+ foreach my $key (keys %{$self->extension_data}) {
+ my $extdata = ${$self->extension_data}{$key};
+ $extensions .= pack("n", $key);
+ $extensions .= pack("n", length($extdata));
+ $extensions .= $extdata;
+ if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) {
+ $extensions .= pack("n", $key);
+ $extensions .= pack("n", length($extdata));
+ $extensions .= $extdata;
+ }
+ }
+
+ $data .= pack('n', length($extensions));
+ $data .= $extensions;
+ $self->data($data);
+}
+
+#Read/write accessors
+sub server_version
+{
+ my $self = shift;
+ if (@_) {
+ $self->{client_version} = shift;
+ }
+ return $self->{client_version};
+}
+sub random
+{
+ my $self = shift;
+ if (@_) {
+ $self->{random} = shift;
+ }
+ return $self->{random};
+}
+sub session_id_len
+{
+ my $self = shift;
+ if (@_) {
+ $self->{session_id_len} = shift;
+ }
+ return $self->{session_id_len};
+}
+sub session
+{
+ my $self = shift;
+ if (@_) {
+ $self->{session} = shift;
+ }
+ return $self->{session};
+}
+sub ciphersuite
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphersuite} = shift;
+ }
+ return $self->{ciphersuite};
+}
+sub comp_meth
+{
+ my $self = shift;
+ if (@_) {
+ $self->{comp_meth} = shift;
+ }
+ return $self->{comp_meth};
+}
+sub extension_data
+{
+ my $self = shift;
+ if (@_) {
+ $self->{extension_data} = shift;
+ }
+ return $self->{extension_data};
+}
+sub set_extension
+{
+ my ($self, $ext_type, $ext_data) = @_;
+ $self->{extension_data}{$ext_type} = $ext_data;
+}
+sub delete_extension
+{
+ my ($self, $ext_type) = @_;
+ delete $self->{extension_data}{$ext_type};
+}
+1;
diff --git a/openssl-1.1.0h/util/perl/TLSProxy/ServerKeyExchange.pm b/openssl-1.1.0h/util/perl/TLSProxy/ServerKeyExchange.pm
new file mode 100644
index 0000000..6e5b4cd
--- /dev/null
+++ b/openssl-1.1.0h/util/perl/TLSProxy/ServerKeyExchange.pm
@@ -0,0 +1,134 @@
+# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+
+package TLSProxy::ServerKeyExchange;
+
+use vars '@ISA';
+push @ISA, 'TLSProxy::Message';
+
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens) = @_;
+
+ my $self = $class->SUPER::new(
+ $server,
+ TLSProxy::Message::MT_SERVER_KEY_EXCHANGE,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ #DHE
+ $self->{p} = "";
+ $self->{g} = "";
+ $self->{pub_key} = "";
+ $self->{sig} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+
+ #Minimal SKE parsing. Only supports DHE at the moment (if its not DHE
+ #the parsing data will be trash...which is ok as long as we don't try to
+ #use it)
+
+ my $p_len = unpack('n', $self->data);
+ my $ptr = 2;
+ my $p = substr($self->data, $ptr, $p_len);
+ $ptr += $p_len;
+
+ my $g_len = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ my $g = substr($self->data, $ptr, $g_len);
+ $ptr += $g_len;
+
+ my $pub_key_len = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ my $pub_key = substr($self->data, $ptr, $pub_key_len);
+ $ptr += $pub_key_len;
+
+ #We assume its signed
+ my $sig_len = unpack('n', substr($self->data, $ptr));
+ my $sig = "";
+ if (defined $sig_len) {
+ $ptr += 2;
+ $sig = substr($self->data, $ptr, $sig_len);
+ $ptr += $sig_len;
+ }
+
+ $self->p($p);
+ $self->g($g);
+ $self->pub_key($pub_key);
+ $self->sig($sig);
+}
+
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+
+ $data = pack('n', length($self->p));
+ $data .= $self->p;
+ $data .= pack('n', length($self->g));
+ $data .= $self->g;
+ $data .= pack('n', length($self->pub_key));
+ $data .= $self->pub_key;
+ if (length($self->sig) > 0) {
+ $data .= pack('n', length($self->sig));
+ $data .= $self->sig;
+ }
+
+ $self->data($data);
+}
+
+#Read/write accessors
+#DHE
+sub p
+{
+ my $self = shift;
+ if (@_) {
+ $self->{p} = shift;
+ }
+ return $self->{p};
+}
+sub g
+{
+ my $self = shift;
+ if (@_) {
+ $self->{g} = shift;
+ }
+ return $self->{g};
+}
+sub pub_key
+{
+ my $self = shift;
+ if (@_) {
+ $self->{pub_key} = shift;
+ }
+ return $self->{pub_key};
+}
+sub sig
+{
+ my $self = shift;
+ if (@_) {
+ $self->{sig} = shift;
+ }
+ return $self->{sig};
+}
+1;