summaryrefslogtreecommitdiff
path: root/deps/openssl/openssl/util/perl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/openssl/openssl/util/perl')
-rw-r--r--deps/openssl/openssl/util/perl/OpenSSL/Test.pm426
-rw-r--r--deps/openssl/openssl/util/perl/OpenSSL/Util/Pod.pm13
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/Alert.pm51
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/Certificate.pm219
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/CertificateVerify.pm96
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/ClientHello.pm37
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/EncryptedExtensions.pm115
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/Message.pm158
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm537
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/Record.pm244
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/ServerHello.pm38
-rw-r--r--deps/openssl/openssl/util/perl/TLSProxy/ServerKeyExchange.pm49
-rw-r--r--deps/openssl/openssl/util/perl/checkhandshake.pm228
13 files changed, 1742 insertions, 469 deletions
diff --git a/deps/openssl/openssl/util/perl/OpenSSL/Test.pm b/deps/openssl/openssl/util/perl/OpenSSL/Test.pm
index a77909c606..9564b26046 100644
--- a/deps/openssl/openssl/util/perl/OpenSSL/Test.pm
+++ b/deps/openssl/openssl/util/perl/OpenSSL/Test.pm
@@ -16,11 +16,11 @@ use Exporter;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = "0.8";
@ISA = qw(Exporter);
-@EXPORT = (@Test::More::EXPORT, qw(setup indir app fuzz perlapp test perltest
- run));
+@EXPORT = (@Test::More::EXPORT, qw(setup run indir cmd app fuzz test
+ perlapp perltest subtest));
@EXPORT_OK = (@Test::More::EXPORT_OK, qw(bldtop_dir bldtop_file
srctop_dir srctop_file
- data_file
+ data_file data_dir
pipe with cmdstr quotify
openssl_versions));
@@ -66,6 +66,7 @@ use File::Spec::Functions qw/file_name_is_absolute curdir canonpath splitdir
use File::Path 2.00 qw/rmtree mkpath/;
use File::Basename;
+my $level = 0;
# The name of the test. This is set by setup() and is used in the other
# functions to verify that setup() has been used.
@@ -92,9 +93,9 @@ my %hooks = (
# exit_checker is used by run() directly after completion of a command.
# it receives the exit code from that command and is expected to return
- # 1 (for success) or 0 (for failure). This is the value that will be
- # returned by run().
- # NOTE: When run() gets the option 'capture => 1', this hook is ignored.
+ # 1 (for success) or 0 (for failure). This is the status value that run()
+ # will give back (through the |statusvar| reference and as returned value
+ # when capture => 1 doesn't apply).
exit_checker => sub { return shift == 0 ? 1 : 0 },
);
@@ -102,21 +103,6 @@ my %hooks = (
# Debug flag, to be set manually when needed
my $debug = 0;
-# Declare some utility functions that are defined at the end
-sub bldtop_file;
-sub bldtop_dir;
-sub srctop_file;
-sub srctop_dir;
-sub quotify;
-
-# Declare some private functions that are defined at the end
-sub __env;
-sub __cwd;
-sub __apps_file;
-sub __results_file;
-sub __fixup_cmd;
-sub __build_cmd;
-
=head2 Main functions
The following functions are exported by default when using C<OpenSSL::Test>.
@@ -226,25 +212,18 @@ sub indir {
=over 4
-=item B<app ARRAYREF, OPTS>
+=item B<cmd ARRAYREF, OPTS>
-=item B<test ARRAYREF, OPTS>
+This functions build up a platform dependent command based on the
+input. It takes a reference to a list that is the executable or
+script and its arguments, and some additional options (described
+further on). Where necessary, the command will be wrapped in a
+suitable environment to make sure the correct shared libraries are
+used (currently only on Unix).
-Both of these functions take a reference to a list that is a command and
-its arguments, and some additional options (described further on).
+It returns a CODEREF to be used by C<run>, C<pipe> or C<cmdstr>.
-C<app> expects to find the given command (the first item in the given list
-reference) as an executable in C<$BIN_D> (if defined, otherwise C<$TOP/apps>
-or C<$BLDTOP/apps>).
-
-C<test> expects to find the given command (the first item in the given list
-reference) as an executable in C<$TEST_D> (if defined, otherwise C<$TOP/test>
-or C<$BLDTOP/test>).
-
-Both return a CODEREF to be used by C<run>, C<pipe> or C<cmdstr>.
-
-The options that both C<app> and C<test> can take are in the form of hash
-values:
+The options that C<cmd> can take are in the form of hash values:
=over 4
@@ -260,21 +239,42 @@ string PATH, I<or>, if the value is C<undef>, C</dev/null> or similar.
=back
+=item B<app ARRAYREF, OPTS>
+
+=item B<test ARRAYREF, OPTS>
+
+Both of these are specific applications of C<cmd>, with just a couple
+of small difference:
+
+C<app> expects to find the given command (the first item in the given list
+reference) as an executable in C<$BIN_D> (if defined, otherwise C<$TOP/apps>
+or C<$BLDTOP/apps>).
+
+C<test> expects to find the given command (the first item in the given list
+reference) as an executable in C<$TEST_D> (if defined, otherwise C<$TOP/test>
+or C<$BLDTOP/test>).
+
+Also, for both C<app> and C<test>, the command may be prefixed with
+the content of the environment variable C<$EXE_SHELL>, which is useful
+in case OpenSSL has been cross compiled.
+
=item B<perlapp ARRAYREF, OPTS>
=item B<perltest ARRAYREF, OPTS>
-Both these functions function the same way as B<app> and B<test>, except
-that they expect the command to be a perl script. Also, they support one
-more option:
+These are also specific applications of C<cmd>, where the interpreter
+is predefined to be C<perl>, and they expect the script to be
+interpreted to reside in the same location as C<app> and C<test>.
+
+C<perlapp> and C<perltest> will also take the following option:
=over 4
=item B<interpreter_args =E<gt> ARRAYref>
-The array reference is a set of arguments for perl rather than the script.
-Take care so that none of them can be seen as a script! Flags and their
-eventual arguments only!
+The array reference is a set of arguments for the interpreter rather
+than the script. Take care so that none of them can be seen as a
+script! Flags and their eventual arguments only!
=back
@@ -285,54 +285,114 @@ An example:
=back
+=begin comment
+
+One might wonder over the complexity of C<apps>, C<fuzz>, C<test>, ...
+with all the lazy evaluations and all that. The reason for this is that
+we want to make sure the directory in which those programs are found are
+correct at the time these commands are used. Consider the following code
+snippet:
+
+ my $cmd = app(["openssl", ...]);
+
+ indir "foo", sub {
+ ok(run($cmd), "Testing foo")
+ };
+
+If there wasn't this lazy evaluation, the directory where C<openssl> is
+found would be incorrect at the time C<run> is called, because it was
+calculated before we moved into the directory "foo".
+
+=end comment
+
=cut
+sub cmd {
+ my $cmd = shift;
+ my %opts = @_;
+ return sub {
+ my $num = shift;
+ # Make a copy to not destroy the caller's array
+ my @cmdargs = ( @$cmd );
+ my @prog = __wrap_cmd(shift @cmdargs, $opts{exe_shell} // ());
+
+ return __decorate_cmd($num, [ @prog, quotify(@cmdargs) ],
+ %opts);
+ }
+}
+
sub app {
my $cmd = shift;
my %opts = @_;
- return sub { my $num = shift;
- return __build_cmd($num, \&__apps_file, $cmd, %opts); }
+ return sub {
+ my @cmdargs = ( @{$cmd} );
+ my @prog = __fixup_prg(__apps_file(shift @cmdargs, __exeext()));
+ return cmd([ @prog, @cmdargs ],
+ exe_shell => $ENV{EXE_SHELL}, %opts) -> (shift);
+ }
}
sub fuzz {
my $cmd = shift;
my %opts = @_;
- return sub { my $num = shift;
- return __build_cmd($num, \&__fuzz_file, $cmd, %opts); }
+ return sub {
+ my @cmdargs = ( @{$cmd} );
+ my @prog = __fixup_prg(__fuzz_file(shift @cmdargs, __exeext()));
+ return cmd([ @prog, @cmdargs ],
+ exe_shell => $ENV{EXE_SHELL}, %opts) -> (shift);
+ }
}
sub test {
my $cmd = shift;
my %opts = @_;
- return sub { my $num = shift;
- return __build_cmd($num, \&__test_file, $cmd, %opts); }
+ return sub {
+ my @cmdargs = ( @{$cmd} );
+ my @prog = __fixup_prg(__test_file(shift @cmdargs, __exeext()));
+ return cmd([ @prog, @cmdargs ],
+ exe_shell => $ENV{EXE_SHELL}, %opts) -> (shift);
+ }
}
sub perlapp {
my $cmd = shift;
my %opts = @_;
- return sub { my $num = shift;
- return __build_cmd($num, \&__perlapps_file, $cmd, %opts); }
+ return sub {
+ my @interpreter_args = defined $opts{interpreter_args} ?
+ @{$opts{interpreter_args}} : ();
+ my @interpreter = __fixup_prg($^X);
+ my @cmdargs = ( @{$cmd} );
+ my @prog = __apps_file(shift @cmdargs, undef);
+ return cmd([ @interpreter, @interpreter_args,
+ @prog, @cmdargs ], %opts) -> (shift);
+ }
}
sub perltest {
my $cmd = shift;
my %opts = @_;
- return sub { my $num = shift;
- return __build_cmd($num, \&__perltest_file, $cmd, %opts); }
+ return sub {
+ my @interpreter_args = defined $opts{interpreter_args} ?
+ @{$opts{interpreter_args}} : ();
+ my @interpreter = __fixup_prg($^X);
+ my @cmdargs = ( @{$cmd} );
+ my @prog = __test_file(shift @cmdargs, undef);
+ return cmd([ @interpreter, @interpreter_args,
+ @prog, @cmdargs ], %opts) -> (shift);
+ }
}
=over 4
=item B<run CODEREF, OPTS>
-This CODEREF is expected to be the value return by C<app> or C<test>,
-anything else will most likely cause an error unless you know what you're
-doing.
+CODEREF is expected to be the value return by C<cmd> or any of its
+derivatives, anything else will most likely cause an error unless you
+know what you're doing.
C<run> executes the command returned by CODEREF and return either the
-resulting output (if the option C<capture> is set true) or a boolean indicating
-if the command succeeded or not.
+resulting output (if the option C<capture> is set true) or a boolean
+indicating if the command succeeded or not.
The options that C<run> can take are in the form of hash values:
@@ -345,6 +405,18 @@ return the resulting output as an array of lines. If false or not given,
the command will be executed with C<system()>, and C<run> will return 1 if
the command was successful or 0 if it wasn't.
+=item B<prefix =E<gt> EXPR>
+
+If specified, EXPR will be used as a string to prefix the output from the
+command. This is useful if the output contains lines starting with C<ok >
+or C<not ok > that can disturb Test::Harness.
+
+=item B<statusvar =E<gt> VARREF>
+
+If used, B<VARREF> must be a reference to a scalar variable. It will be
+assigned a boolean indicating if the command succeeded or not. This is
+particularly useful together with B<capture>.
+
=back
For further discussion on what is considered a successful command or not, see
@@ -369,6 +441,9 @@ sub run {
my $r = 0;
my $e = 0;
+ die "OpenSSL::Test::run(): statusvar value not a scalar reference"
+ if $opts{statusvar} && ref($opts{statusvar}) ne "SCALAR";
+
# In non-verbose, we want to shut up the command interpreter, in case
# it has something to complain about. On VMS, it might complain both
# on stdout and stderr
@@ -381,17 +456,35 @@ sub run {
open STDERR, ">", devnull();
}
+ $ENV{HARNESS_OSSL_LEVEL} = $level + 1;
+
# The dance we do with $? is the same dance the Unix shells appear to
# do. For example, a program that gets aborted (and therefore signals
# SIGABRT = 6) will appear to exit with the code 134. We mimic this
# to make it easier to compare with a manual run of the command.
- if ($opts{capture}) {
- @r = `$prefix$cmd`;
- $e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
+ if ($opts{capture} || defined($opts{prefix})) {
+ my $pipe;
+ local $_;
+
+ open($pipe, '-|', "$prefix$cmd") or die "Can't start command: $!";
+ while(<$pipe>) {
+ my $l = ($opts{prefix} // "") . $_;
+ if ($opts{capture}) {
+ push @r, $l;
+ } else {
+ print STDOUT $l;
+ }
+ }
+ close $pipe;
} else {
+ $ENV{HARNESS_OSSL_PREFIX} = "# ";
system("$prefix$cmd");
- $e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
- $r = $hooks{exit_checker}->($e);
+ delete $ENV{HARNESS_OSSL_PREFIX};
+ }
+ $e = ($? & 0x7f) ? ($? & 0x7f)|0x80 : ($? >> 8);
+ $r = $hooks{exit_checker}->($e);
+ if ($opts{statusvar}) {
+ ${$opts{statusvar}} = $r;
}
if ($ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}) {
@@ -514,6 +607,23 @@ sub srctop_file {
=over 4
+=item B<data_dir LIST>
+
+LIST is a list of directories that make up a path from the data directory
+associated with the test (see L</DESCRIPTION> above).
+C<data_dir> returns the resulting directory as a string, adapted to the local
+operating system.
+
+=back
+
+=cut
+
+sub data_dir {
+ return __data_dir(@_);
+}
+
+=over 4
+
=item B<data_file LIST, FILENAME>
LIST is a list of directories that make up a path from the data directory
@@ -571,7 +681,7 @@ sub pipe {
=item B<with HASHREF, CODEREF>
-C<with> will temporarly install hooks given by the HASHREF and then execute
+C<with> will temporarily install hooks given by the HASHREF and then execute
the given CODEREF. Hooks are usually expected to have a coderef as value.
The currently available hoosk are:
@@ -617,7 +727,7 @@ sub with {
C<cmdstr> takes a CODEREF from C<app> or C<test> and simply returns the
command as a string.
-C<cmdstr> takes some additiona options OPTS that affect the string returned:
+C<cmdstr> takes some additional options OPTS that affect the string returned:
=over 4
@@ -781,6 +891,14 @@ sub __env {
$end_with_bailout = $ENV{STOPTEST} ? 1 : 0;
};
+# __srctop_file and __srctop_dir are helpers to build file and directory
+# names on top of the source directory. They depend on $SRCTOP, and
+# therefore on the proper use of setup() and when needed, indir().
+# __bldtop_file and __bldtop_dir do the same thing but relative to $BLDTOP.
+# __srctop_file and __bldtop_file take the same kind of argument as
+# File::Spec::Functions::catfile.
+# Similarly, __srctop_dir and __bldtop_dir take the same kind of argument
+# as File::Spec::Functions::catdir
sub __srctop_file {
BAIL_OUT("Must run setup() first") if (! $test_name);
@@ -807,6 +925,9 @@ sub __bldtop_dir {
return catdir($directories{BLDTOP},@_);
}
+# __exeext is a function that returns the platform dependent file extension
+# for executable binaries, or the value of the environment variable $EXE_EXT
+# if that one is defined.
sub __exeext {
my $ext = "";
if ($^O eq "VMS" ) { # VMS
@@ -817,56 +938,56 @@ sub __exeext {
return $ENV{"EXE_EXT"} || $ext;
}
+# __test_file, __apps_file and __fuzz_file return the full path to a file
+# relative to the test/, apps/ or fuzz/ directory in the build tree or the
+# source tree, depending on where the file is found. Note that when looking
+# in the build tree, the file name with an added extension is looked for, if
+# an extension is given. The intent is to look for executable binaries (in
+# the build tree) or possibly scripts (in the source tree).
+# These functions all take the same arguments as File::Spec::Functions::catfile,
+# *plus* a mandatory extension argument. This extension argument can be undef,
+# and is ignored in such a case.
sub __test_file {
BAIL_OUT("Must run setup() first") if (! $test_name);
+ my $e = pop || "";
my $f = pop;
- my $out = catfile($directories{BLDTEST},@_,$f . __exeext());
- $out = catfile($directories{SRCTEST},@_,$f) unless -x $out;
- return $out;
-}
-
-sub __perltest_file {
- BAIL_OUT("Must run setup() first") if (! $test_name);
-
- my $f = pop;
- my $out = catfile($directories{BLDTEST},@_,$f);
+ my $out = catfile($directories{BLDTEST},@_,$f . $e);
$out = catfile($directories{SRCTEST},@_,$f) unless -f $out;
- return ($^X, $out);
+ return $out;
}
sub __apps_file {
BAIL_OUT("Must run setup() first") if (! $test_name);
+ my $e = pop || "";
my $f = pop;
- my $out = catfile($directories{BLDAPPS},@_,$f . __exeext());
- $out = catfile($directories{SRCAPPS},@_,$f) unless -x $out;
+ my $out = catfile($directories{BLDAPPS},@_,$f . $e);
+ $out = catfile($directories{SRCAPPS},@_,$f) unless -f $out;
return $out;
}
sub __fuzz_file {
BAIL_OUT("Must run setup() first") if (! $test_name);
+ my $e = pop || "";
my $f = pop;
- my $out = catfile($directories{BLDFUZZ},@_,$f . __exeext());
- $out = catfile($directories{SRCFUZZ},@_,$f) unless -x $out;
+ my $out = catfile($directories{BLDFUZZ},@_,$f . $e);
+ $out = catfile($directories{SRCFUZZ},@_,$f) unless -f $out;
return $out;
}
-sub __perlapps_file {
+sub __data_file {
BAIL_OUT("Must run setup() first") if (! $test_name);
my $f = pop;
- my $out = catfile($directories{BLDAPPS},@_,$f);
- $out = catfile($directories{SRCAPPS},@_,$f) unless -f $out;
- return ($^X, $out);
+ return catfile($directories{SRCDATA},@_,$f);
}
-sub __data_file {
+sub __data_dir {
BAIL_OUT("Must run setup() first") if (! $test_name);
- my $f = pop;
- return catfile($directories{SRCDATA},@_,$f);
+ return catdir($directories{SRCDATA},@_);
}
sub __results_file {
@@ -876,6 +997,16 @@ sub __results_file {
return catfile($directories{RESULTS},@_,$f);
}
+# __cwd DIR
+# __cwd DIR, OPTS
+#
+# __cwd changes directory to DIR (string) and changes all the relative
+# entries in %directories accordingly. OPTS is an optional series of
+# hash style arguments to alter __cwd's behavior:
+#
+# create = 0|1 The directory we move to is created if 1, not if 0.
+# cleanup = 0|1 The directory we move from is removed if 1, not if 0.
+
sub __cwd {
my $dir = catdir(shift);
my %opts = @_;
@@ -937,7 +1068,7 @@ sub __cwd {
}
# We put back new values carefully. Doing the obvious
- # %directories = ( %tmp_irectories )
+ # %directories = ( %tmp_directories )
# will clear out any value that happens to be an absolute path
foreach (keys %tmp_directories) {
$directories{$_} = $tmp_directories{$_};
@@ -964,28 +1095,46 @@ sub __cwd {
return $reverse;
}
-sub __fixup_cmd {
- my $prog = shift;
+# __wrap_cmd CMD
+# __wrap_cmd CMD, EXE_SHELL
+#
+# __wrap_cmd "wraps" CMD (string) with a beginning command that makes sure
+# the command gets executed with an appropriate environment. If EXE_SHELL
+# is given, it is used as the beginning command.
+#
+# __wrap_cmd returns a list that should be used to build up a larger list
+# of command tokens, or be joined together like this:
+#
+# join(" ", __wrap_cmd($cmd))
+sub __wrap_cmd {
+ my $cmd = shift;
my $exe_shell = shift;
- my $prefix = __bldtop_file("util", "shlib_wrap.sh")." ";
+ my @prefix = ( __bldtop_file("util", "shlib_wrap.sh") );
- if (defined($exe_shell)) {
- $prefix = "$exe_shell ";
- } elsif ($^O eq "VMS" ) { # VMS
- $prefix = ($prog =~ /^(?:[\$a-z0-9_]+:)?[<\[]/i ? "mcr " : "mcr []");
- } elsif ($^O eq "MSWin32") { # Windows
- $prefix = "";
+ if(defined($exe_shell)) {
+ @prefix = ( $exe_shell );
+ } elsif ($^O eq "VMS" || $^O eq "MSWin32") {
+ # VMS and Windows don't use any wrapper script for the moment
+ @prefix = ();
}
- # We test both with and without extension. The reason
- # is that we might be passed a complete file spec, with
- # extension.
- if ( ! -x $prog ) {
- my $prog = "$prog";
- if ( ! -x $prog ) {
- $prog = undef;
- }
+ return (@prefix, $cmd);
+}
+
+# __fixup_prg PROG
+#
+# __fixup_prg does whatever fixup is needed to execute an executable binary
+# given by PROG (string).
+#
+# __fixup_prg returns a string with the possibly prefixed program path spec.
+sub __fixup_prg {
+ my $prog = shift;
+
+ my $prefix = "";
+
+ if ($^O eq "VMS" ) {
+ $prefix = ($prog =~ /^(?:[\$a-z0-9_]+:)?[<\[]/i ? "mcr " : "mcr []");
}
if (defined($prog)) {
@@ -1001,45 +1150,25 @@ sub __fixup_cmd {
return undef;
}
-sub __build_cmd {
+# __decorate_cmd NUM, CMDARRAYREF
+#
+# __decorate_cmd takes a command number NUM and a command token array
+# CMDARRAYREF, builds up a command string from them and decorates it
+# with necessary redirections.
+# __decorate_cmd returns a list of two strings, one with the command
+# string to actually be used, the other to be displayed for the user.
+# The reason these strings might differ is that we redirect stderr to
+# the null device unless we're verbose and unless the user has
+# explicitly specified a stderr redirection.
+sub __decorate_cmd {
BAIL_OUT("Must run setup() first") if (! $test_name);
my $num = shift;
- my $path_builder = shift;
- # Make a copy to not destroy the caller's array
- my @cmdarray = ( @{$_[0]} ); shift;
+ my $cmd = shift;
my %opts = @_;
- # We do a little dance, as $path_builder might return a list of
- # more than one. If so, only the first is to be considered a
- # program to fix up, the rest is part of the arguments. This
- # happens for perl scripts, where $path_builder will return
- # a list of two, $^X and the script name.
- # Also, if $path_builder returned more than one, we don't apply
- # the EXE_SHELL environment variable.
- my @prog = ($path_builder->(shift @cmdarray));
- my $first = shift @prog;
- my $exe_shell = @prog ? undef : $ENV{EXE_SHELL};
- my $cmd = __fixup_cmd($first, $exe_shell);
- if (@prog) {
- if ( ! -f $prog[0] ) {
- print STDERR "$prog[0] not found\n";
- $cmd = undef;
- }
- }
- my @args = (@prog, @cmdarray);
- if (defined($opts{interpreter_args})) {
- unshift @args, @{$opts{interpreter_args}};
- }
-
- return () if !$cmd;
-
- my $arg_str = "";
+ my $cmdstr = join(" ", @$cmd);
my $null = devnull();
-
-
- $arg_str = " ".join(" ", quotify @args) if @args;
-
my $fileornull = sub { $_[0] ? $_[0] : $null; };
my $stdin = "";
my $stdout = "";
@@ -1049,19 +1178,19 @@ sub __build_cmd {
$stdout= " > ".$fileornull->($opts{stdout}) if exists($opts{stdout});
$stderr=" 2> ".$fileornull->($opts{stderr}) if exists($opts{stderr});
- my $display_cmd = "$cmd$arg_str$stdin$stdout$stderr";
+ my $display_cmd = "$cmdstr$stdin$stdout$stderr";
$stderr=" 2> ".$null
unless $stderr || !$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE};
- $cmd .= "$arg_str$stdin$stdout$stderr";
+ $cmdstr .= "$stdin$stdout$stderr";
if ($debug) {
- print STDERR "DEBUG[__build_cmd]: \$cmd = \"$cmd\"\n";
- print STDERR "DEBUG[__build_cmd]: \$display_cmd = \"$display_cmd\"\n";
+ print STDERR "DEBUG[__decorate_cmd]: \$cmdstr = \"$cmdstr\"\n";
+ print STDERR "DEBUG[__decorate_cmd]: \$display_cmd = \"$display_cmd\"\n";
}
- return ($cmd, $display_cmd);
+ return ($cmdstr, $display_cmd);
}
=head1 SEE ALSO
@@ -1070,9 +1199,18 @@ L<Test::More>, L<Test::Harness>
=head1 AUTHORS
-Richard Levitte E<lt>levitte@openssl.orgE<gt> with assitance and
+Richard Levitte E<lt>levitte@openssl.orgE<gt> with assistance and
inspiration from Andy Polyakov E<lt>appro@openssl.org<gt>.
=cut
+no warnings 'redefine';
+sub subtest {
+ $level++;
+
+ Test::More::subtest @_;
+
+ $level--;
+};
+
1;
diff --git a/deps/openssl/openssl/util/perl/OpenSSL/Util/Pod.pm b/deps/openssl/openssl/util/perl/OpenSSL/Util/Pod.pm
index 5c0af95918..9f76fbf1a6 100644
--- a/deps/openssl/openssl/util/perl/OpenSSL/Util/Pod.pm
+++ b/deps/openssl/openssl/util/perl/OpenSSL/Util/Pod.pm
@@ -53,11 +53,8 @@ The additional hash is for extra parameters:
=item B<section =E<gt> N>
-The value MUST be a number, and will be the default man section number
-to be used with the given .pod file. This number can be altered if
-the .pod file has a line like this:
-
- =for comment openssl_manual_section: 4
+The value MUST be a number, and will be the man section number
+to be used with the given .pod file.
=item B<debug =E<gt> 0|1>
@@ -109,12 +106,6 @@ sub extract_pod_info {
my %podinfo = ( section => $defaults{section});
while(<$input>) {
s|\R$||;
- if (m|^=for\s+comment\s+openssl_manual_section:\s*([0-9])\s*$|) {
- print STDERR "DEBUG: Found man section number $1\n"
- if $defaults{debug};
- $podinfo{section} = $1;
- }
-
# Stop reading when we have reached past the NAME section.
last if (m|^=head1|
&& defined $podinfo{lastsect}
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Alert.pm b/deps/openssl/openssl/util/perl/TLSProxy/Alert.pm
new file mode 100644
index 0000000000..e66883d459
--- /dev/null
+++ b/deps/openssl/openssl/util/perl/TLSProxy/Alert.pm
@@ -0,0 +1,51 @@
+# Copyright 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;
+
+package TLSProxy::Alert;
+
+sub new
+{
+ my $class = shift;
+ my ($server,
+ $encrypted,
+ $level,
+ $description) = @_;
+
+ my $self = {
+ server => $server,
+ encrypted => $encrypted,
+ level => $level,
+ description => $description
+ };
+
+ return bless $self, $class;
+}
+
+#Read only accessors
+sub server
+{
+ my $self = shift;
+ return $self->{server};
+}
+sub encrypted
+{
+ my $self = shift;
+ return $self->{encrypted};
+}
+sub level
+{
+ my $self = shift;
+ return $self->{level};
+}
+sub description
+{
+ my $self = shift;
+ return $self->{description};
+}
+1;
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Certificate.pm b/deps/openssl/openssl/util/perl/TLSProxy/Certificate.pm
new file mode 100644
index 0000000000..d3bf7f2180
--- /dev/null
+++ b/deps/openssl/openssl/util/perl/TLSProxy/Certificate.pm
@@ -0,0 +1,219 @@
+# 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::Certificate;
+
+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_CERTIFICATE,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{first_certificate} = "";
+ $self->{extension_data} = "";
+ $self->{remaining_certdata} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+
+ if (TLSProxy::Proxy->is_tls13()) {
+ my $context_len = unpack('C', $self->data);
+ my $context = substr($self->data, 1, $context_len);
+
+ my $remdata = substr($self->data, 1 + $context_len);
+
+ my ($hicertlistlen, $certlistlen) = unpack('Cn', $remdata);
+ $certlistlen += ($hicertlistlen << 16);
+
+ $remdata = substr($remdata, 3);
+
+ die "Invalid Certificate List length"
+ if length($remdata) != $certlistlen;
+
+ my ($hicertlen, $certlen) = unpack('Cn', $remdata);
+ $certlen += ($hicertlen << 16);
+
+ die "Certificate too long" if ($certlen + 3) > $certlistlen;
+
+ $remdata = substr($remdata, 3);
+
+ my $certdata = substr($remdata, 0, $certlen);
+
+ $remdata = substr($remdata, $certlen);
+
+ my $extensions_len = unpack('n', $remdata);
+ $remdata = substr($remdata, 2);
+
+ die "Extensions too long"
+ if ($certlen + 3 + $extensions_len + 2) > $certlistlen;
+
+ my $extension_data = "";
+ if ($extensions_len != 0) {
+ $extension_data = substr($remdata, 0, $extensions_len);
+
+ 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;
+ }
+ $remdata = substr($remdata, $extensions_len);
+
+ $self->context($context);
+ $self->first_certificate($certdata);
+ $self->extension_data(\%extensions);
+ $self->remaining_certdata($remdata);
+
+ print " Context:".$context."\n";
+ print " Certificate List Len:".$certlistlen."\n";
+ print " Certificate Len:".$certlen."\n";
+ print " Extensions Len:".$extensions_len."\n";
+ } else {
+ my ($hicertlistlen, $certlistlen) = unpack('Cn', $self->data);
+ $certlistlen += ($hicertlistlen << 16);
+
+ my $remdata = substr($self->data, 3);
+
+ die "Invalid Certificate List length"
+ if length($remdata) != $certlistlen;
+
+ my ($hicertlen, $certlen) = unpack('Cn', $remdata);
+ $certlen += ($hicertlen << 16);
+
+ die "Certificate too long" if ($certlen + 3) > $certlistlen;
+
+ $remdata = substr($remdata, 3);
+
+ my $certdata = substr($remdata, 0, $certlen);
+
+ $remdata = substr($remdata, $certlen);
+
+ $self->first_certificate($certdata);
+ $self->remaining_certdata($remdata);
+
+ print " Certificate List Len:".$certlistlen."\n";
+ print " Certificate Len:".$certlen."\n";
+ }
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+ my $extensions = "";
+
+ if (TLSProxy::Proxy->is_tls13()) {
+ 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('C', length($self->context()));
+ $data .= $self->context;
+ my $certlen = length($self->first_certificate);
+ my $certlistlen = $certlen + length($extensions)
+ + length($self->remaining_certdata);
+ my $hi = $certlistlen >> 16;
+ $certlistlen = $certlistlen & 0xffff;
+ $data .= pack('Cn', $hi, $certlistlen);
+ $hi = $certlen >> 16;
+ $certlen = $certlen & 0xffff;
+ $data .= pack('Cn', $hi, $certlen);
+ $data .= pack('n', length($extensions));
+ $data .= $extensions;
+ $data .= $self->remaining_certdata();
+ $self->data($data);
+ } else {
+ my $certlen = length($self->first_certificate);
+ my $certlistlen = $certlen + length($self->remaining_certdata);
+ my $hi = $certlistlen >> 16;
+ $certlistlen = $certlistlen & 0xffff;
+ $data .= pack('Cn', $hi, $certlistlen);
+ $hi = $certlen >> 16;
+ $certlen = $certlen & 0xffff;
+ $data .= pack('Cn', $hi, $certlen);
+ $data .= $self->remaining_certdata();
+ $self->data($data);
+ }
+}
+
+#Read/write accessors
+sub context
+{
+ my $self = shift;
+ if (@_) {
+ $self->{context} = shift;
+ }
+ return $self->{context};
+}
+sub first_certificate
+{
+ my $self = shift;
+ if (@_) {
+ $self->{first_certificate} = shift;
+ }
+ return $self->{first_certificate};
+}
+sub remaining_certdata
+{
+ my $self = shift;
+ if (@_) {
+ $self->{remaining_certdata} = shift;
+ }
+ return $self->{remaining_certdata};
+}
+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/deps/openssl/openssl/util/perl/TLSProxy/CertificateVerify.pm b/deps/openssl/openssl/util/perl/TLSProxy/CertificateVerify.pm
new file mode 100644
index 0000000000..8bf969fba1
--- /dev/null
+++ b/deps/openssl/openssl/util/perl/TLSProxy/CertificateVerify.pm
@@ -0,0 +1,96 @@
+# 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::CertificateVerify;
+
+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_CERTIFICATE_VERIFY,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{sigalg} = -1;
+ $self->{signature} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+
+ my $sigalg = -1;
+ my $remdata = $self->data;
+ my $record = ${$self->records}[0];
+
+ if (TLSProxy::Proxy->is_tls13()
+ || $record->version() == TLSProxy::Record::VERS_TLS_1_2) {
+ $sigalg = unpack('n', $remdata);
+ $remdata = substr($remdata, 2);
+ }
+
+ my $siglen = unpack('n', substr($remdata, 0, 2));
+ my $sig = substr($remdata, 2);
+
+ die "Invalid CertificateVerify signature length" if length($sig) != $siglen;
+
+ print " SigAlg:".$sigalg."\n";
+ print " Signature Len:".$siglen."\n";
+
+ $self->sigalg($sigalg);
+ $self->signature($sig);
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data = "";
+ my $sig = $self->signature();
+ my $olddata = $self->data();
+
+ $data .= pack("n", $self->sigalg()) if ($self->sigalg() != -1);
+ $data .= pack("n", length($sig));
+ $data .= $sig;
+
+ $self->data($data);
+}
+
+#Read/write accessors
+sub sigalg
+{
+ my $self = shift;
+ if (@_) {
+ $self->{sigalg} = shift;
+ }
+ return $self->{sigalg};
+}
+sub signature
+{
+ my $self = shift;
+ if (@_) {
+ $self->{signature} = shift;
+ }
+ return $self->{signature};
+}
+1;
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/ClientHello.pm b/deps/openssl/openssl/util/perl/TLSProxy/ClientHello.pm
index ec739d2970..2ae9d6f55d 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/ClientHello.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/ClientHello.pm
@@ -114,6 +114,24 @@ sub process_extensions
}
}
+sub extension_contents
+{
+ my $self = shift;
+ my $key = shift;
+ my $extension = "";
+
+ my $extdata = ${$self->extension_data}{$key};
+ $extension .= pack("n", $key);
+ $extension .= pack("n", length($extdata));
+ $extension .= $extdata;
+ if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) {
+ $extension .= pack("n", $key);
+ $extension .= pack("n", length($extdata));
+ $extension .= $extdata;
+ }
+ return $extension;
+}
+
#Reconstruct the on-the-wire message data following changes
sub set_message_contents
{
@@ -131,15 +149,16 @@ sub set_message_contents
$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;
- }
+ next if ($key == TLSProxy::Message::EXT_PSK);
+ $extensions .= $self->extension_contents($key);
+ }
+ #PSK extension always goes last...
+ if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) {
+ $extensions .= $self->extension_contents(TLSProxy::Message::EXT_PSK);
+ }
+ #unless we have EXT_FORCE_LAST
+ if (defined ${$self->extension_data}{TLSProxy::Message::EXT_FORCE_LAST}) {
+ $extensions .= $self->extension_contents(TLSProxy::Message::EXT_FORCE_LAST);
}
$data .= pack('n', length($extensions));
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/EncryptedExtensions.pm b/deps/openssl/openssl/util/perl/TLSProxy/EncryptedExtensions.pm
new file mode 100644
index 0000000000..81242e29ff
--- /dev/null
+++ b/deps/openssl/openssl/util/perl/TLSProxy/EncryptedExtensions.pm
@@ -0,0 +1,115 @@
+# 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::EncryptedExtensions;
+
+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_ENCRYPTED_EXTENSIONS,
+ $data,
+ $records,
+ $startoffset,
+ $message_frag_lens);
+
+ $self->{extension_data} = "";
+
+ return $self;
+}
+
+sub parse
+{
+ my $self = shift;
+
+ my $extensions_len = unpack('n', $self->data);
+ if (!defined $extensions_len) {
+ $extensions_len = 0;
+ }
+
+ my $extension_data;
+ if ($extensions_len != 0) {
+ $extension_data = substr($self->data, 2);
+
+ if (length($extension_data) != $extensions_len) {
+ die "Invalid extension length\n";
+ }
+ } else {
+ if (length($self->data) != 2) {
+ 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->extension_data(\%extensions);
+
+ print " Extensions Len:".$extensions_len."\n";
+}
+
+#Reconstruct the on-the-wire message data following changes
+sub set_message_contents
+{
+ my $self = shift;
+ my $data;
+ my $extensions = "";
+
+ 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 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/deps/openssl/openssl/util/perl/TLSProxy/Message.pm b/deps/openssl/openssl/util/perl/TLSProxy/Message.pm
index 0821bdedd3..16ed012066 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/Message.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/Message.pm
@@ -1,4 +1,4 @@
-# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+# 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
@@ -9,6 +9,8 @@ use strict;
package TLSProxy::Message;
+use TLSProxy::Alert;
+
use constant TLS_MESSAGE_HEADER_LENGTH => 4;
#Message types
@@ -17,6 +19,7 @@ use constant {
MT_CLIENT_HELLO => 1,
MT_SERVER_HELLO => 2,
MT_NEW_SESSION_TICKET => 4,
+ MT_ENCRYPTED_EXTENSIONS => 8,
MT_CERTIFICATE => 11,
MT_SERVER_KEY_EXCHANGE => 12,
MT_CERTIFICATE_REQUEST => 13,
@@ -38,6 +41,7 @@ use constant {
use constant {
AL_DESC_CLOSE_NOTIFY => 0,
AL_DESC_UNEXPECTED_MESSAGE => 10,
+ AL_DESC_ILLEGAL_PARAMETER => 47,
AL_DESC_NO_RENEGOTIATION => 100
};
@@ -46,6 +50,7 @@ my %message_type = (
MT_CLIENT_HELLO, "ClientHello",
MT_SERVER_HELLO, "ServerHello",
MT_NEW_SESSION_TICKET, "NewSessionTicket",
+ MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions",
MT_CERTIFICATE, "Certificate",
MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
MT_CERTIFICATE_REQUEST, "CertificateRequest",
@@ -58,13 +63,73 @@ my %message_type = (
);
use constant {
+ EXT_SERVER_NAME => 0,
+ EXT_MAX_FRAGMENT_LENGTH => 1,
EXT_STATUS_REQUEST => 5,
+ EXT_SUPPORTED_GROUPS => 10,
+ EXT_EC_POINT_FORMATS => 11,
+ EXT_SRP => 12,
+ EXT_SIG_ALGS => 13,
+ EXT_USE_SRTP => 14,
+ EXT_ALPN => 16,
+ EXT_SCT => 18,
+ EXT_PADDING => 21,
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
+ EXT_KEY_SHARE => 51,
+ EXT_PSK => 41,
+ EXT_SUPPORTED_VERSIONS => 43,
+ EXT_COOKIE => 44,
+ EXT_PSK_KEX_MODES => 45,
+ EXT_POST_HANDSHAKE_AUTH => 49,
+ EXT_SIG_ALGS_CERT => 50,
+ EXT_RENEGOTIATE => 65281,
+ EXT_NPN => 13172,
+ # This extension is an unofficial extension only ever written by OpenSSL
+ # (i.e. not read), and even then only when enabled. We use it to test
+ # handling of duplicate extensions.
+ EXT_DUPLICATE_EXTENSION => 0xfde8,
+ EXT_UNKNOWN => 0xfffe,
+ #Unknown extension that should appear last
+ EXT_FORCE_LAST => 0xffff
+};
+
+# SignatureScheme of TLS 1.3 from:
+# https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme
+# We have to manually grab the SHA224 equivalents from the old registry
+use constant {
+ SIG_ALG_RSA_PKCS1_SHA256 => 0x0401,
+ SIG_ALG_RSA_PKCS1_SHA384 => 0x0501,
+ SIG_ALG_RSA_PKCS1_SHA512 => 0x0601,
+ SIG_ALG_ECDSA_SECP256R1_SHA256 => 0x0403,
+ SIG_ALG_ECDSA_SECP384R1_SHA384 => 0x0503,
+ SIG_ALG_ECDSA_SECP521R1_SHA512 => 0x0603,
+ SIG_ALG_RSA_PSS_RSAE_SHA256 => 0x0804,
+ SIG_ALG_RSA_PSS_RSAE_SHA384 => 0x0805,
+ SIG_ALG_RSA_PSS_RSAE_SHA512 => 0x0806,
+ SIG_ALG_ED25519 => 0x0807,
+ SIG_ALG_ED448 => 0x0808,
+ SIG_ALG_RSA_PSS_PSS_SHA256 => 0x0809,
+ SIG_ALG_RSA_PSS_PSS_SHA384 => 0x080a,
+ SIG_ALG_RSA_PSS_PSS_SHA512 => 0x080b,
+ SIG_ALG_RSA_PKCS1_SHA1 => 0x0201,
+ SIG_ALG_ECDSA_SHA1 => 0x0203,
+ SIG_ALG_DSA_SHA1 => 0x0202,
+ SIG_ALG_DSA_SHA256 => 0x0402,
+ SIG_ALG_DSA_SHA384 => 0x0502,
+ SIG_ALG_DSA_SHA512 => 0x0602,
+ OSSL_SIG_ALG_RSA_PKCS1_SHA224 => 0x0301,
+ OSSL_SIG_ALG_DSA_SHA224 => 0x0302,
+ OSSL_SIG_ALG_ECDSA_SHA224 => 0x0303
+};
+
+use constant {
+ CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f,
+ CIPHER_DHE_RSA_AES_128_SHA => 0x0033,
+ CIPHER_ADH_AES_128_SHA => 0x0034,
+ CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301,
+ CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302
};
my $payload = "";
@@ -77,6 +142,8 @@ my $end = 0;
my @message_rec_list = ();
my @message_frag_lens = ();
my $ciphersuite = 0;
+my $successondata = 0;
+my $alert;
sub clear
{
@@ -86,8 +153,10 @@ sub clear
$server = 0;
$success = 0;
$end = 0;
+ $successondata = 0;
@message_rec_list = ();
@message_frag_lens = ();
+ $alert = undef;
}
#Class method to extract messages from a record
@@ -111,10 +180,12 @@ sub get_messages
#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);
+ if (!TLSProxy::Proxy->is_tls13()) {
+ if ($server) {
+ TLSProxy::Record->server_encrypting(1);
+ } else {
+ TLSProxy::Record->client_encrypting(1);
+ }
}
} elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
if ($record->len == 0 || $record->len_real == 0) {
@@ -197,16 +268,29 @@ sub get_messages
} elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) {
print " [ENCRYPTED APPLICATION DATA]\n";
print " [".$record->decrypt_data."]\n";
+
+ if ($successondata) {
+ $success = 1;
+ $end = 1;
+ }
} elsif ($record->content_type == TLSProxy::Record::RT_ALERT) {
my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data);
+ print " [$alertlev, $alertdesc]\n";
#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;
+ #Fatal or close notify alerts end the test
+ if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) {
+ $end = 1;
+ }
+ $alert = TLSProxy::Alert->new(
+ $server,
+ $record->encrypted,
+ $alertlev,
+ $alertdesc);
}
return @messages;
@@ -239,6 +323,33 @@ sub create_message
[@message_frag_lens]
);
$message->parse();
+ } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) {
+ $message = TLSProxy::EncryptedExtensions->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } elsif ($mt == MT_CERTIFICATE) {
+ $message = TLSProxy::Certificate->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
+ } elsif ($mt == MT_CERTIFICATE_VERIFY) {
+ $message = TLSProxy::CertificateVerify->new(
+ $server,
+ $data,
+ [@message_rec_list],
+ $startoffset,
+ [@message_frag_lens]
+ );
+ $message->parse();
} elsif ($mt == MT_SERVER_KEY_EXCHANGE) {
$message = TLSProxy::ServerKeyExchange->new(
$server,
@@ -287,6 +398,12 @@ sub fail
my $class = shift;
return !$success && $end;
}
+
+sub alert
+{
+ return $alert;
+}
+
sub new
{
my $class = shift;
@@ -319,7 +436,7 @@ sub ciphersuite
}
#Update all the underlying records with the modified data from this message
-#Note: Does not currently support re-encrypting
+#Note: Only supports re-encrypting for TLSv1.3
sub repack
{
my $self = shift;
@@ -362,8 +479,14 @@ sub repack
# 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);
+ # Only support re-encryption for TLSv1.3.
+ if (TLSProxy::Proxy->is_tls13() && $rec->encrypted()) {
+ #Add content type (1 byte) and 16 tag bytes
+ $rec->data($rec->decrypt_data
+ .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16));
+ } else {
+ $rec->data($rec->decrypt_data);
+ }
#Update the fragment len in case we changed it above
${$self->message_frag_lens}[0] = length($msgdata)
@@ -452,5 +575,12 @@ sub encoded_length
my $self = shift;
return TLS_MESSAGE_HEADER_LENGTH + length($self->data);
}
-
+sub successondata
+{
+ my $class = shift;
+ if (@_) {
+ $successondata = shift;
+ }
+ return $successondata;
+}
1;
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm b/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm
index de143626d3..8c13520ec6 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/Proxy.pm
@@ -17,52 +17,21 @@ use TLSProxy::Record;
use TLSProxy::Message;
use TLSProxy::ClientHello;
use TLSProxy::ServerHello;
+use TLSProxy::EncryptedExtensions;
+use TLSProxy::Certificate;
+use TLSProxy::CertificateVerify;
use TLSProxy::ServerKeyExchange;
use TLSProxy::NewSessionTicket;
-use Time::HiRes qw/usleep/;
-my $have_IPv6 = 0;
+my $have_IPv6;
my $IP_factory;
-sub new
+BEGIN
{
- 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
+ # first, then fall back on the core modules. Worst case scenario, we
# fall back to IO::Socket::INET, only supports IPv4.
eval {
require IO::Socket::INET6;
@@ -93,26 +62,72 @@ sub new
$have_IPv6 = 1;
} else {
$IP_factory = sub { IO::Socket::INET->new(@_); };
+ $have_IPv6 = 0;
}
}
+}
+
+my $is_tls13 = 0;
+my $ciphersuite = undef;
+
+sub new
+{
+ my $class = shift;
+ my ($filter,
+ $execute,
+ $cert,
+ $debug) = @_;
+
+ my $self = {
+ #Public read/write
+ proxy_addr => $have_IPv6 ? "[::1]" : "127.0.0.1",
+ filter => $filter,
+ serverflags => "",
+ clientflags => "",
+ serverconnects => 1,
+ reneg => 0,
+ sessionfile => undef,
+
+ #Public read
+ proxy_port => 0,
+ server_port => 0,
+ serverpid => 0,
+ clientpid => 0,
+ execute => $execute,
+ cert => $cert,
+ debug => $debug,
+ cipherc => "",
+ ciphersuitesc => "",
+ ciphers => "AES128-SHA",
+ ciphersuitess => "TLS_AES_128_GCM_SHA256",
+ flight => -1,
+ direction => -1,
+ partial => ["", ""],
+ record_list => [],
+ message_list => [],
+ };
# Create the Proxy socket
my $proxaddr = $self->{proxy_addr};
$proxaddr =~ s/[\[\]]//g; # Remove [ and ]
my @proxyargs = (
LocalHost => $proxaddr,
- LocalPort => $self->{proxy_port},
+ LocalPort => 0,
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";
+ if (my $sock = $IP_factory->(@proxyargs)) {
+ $self->{proxy_sock} = $sock;
+ $self->{proxy_port} = $sock->sockport();
+ $self->{proxy_addr} = $sock->sockhost();
+ $self->{proxy_addr} =~ s/(.*:.*)/[$1]/;
+ print "Proxy started on port ",
+ "$self->{proxy_addr}:$self->{proxy_port}\n";
+ # use same address for s_server
+ $self->{server_addr} = $self->{proxy_addr};
} else {
- warn "Failed creating proxy socket (".$proxaddr.",".$self->{proxy_port}."): $!\n";
+ warn "Failed creating proxy socket (".$proxaddr.",0): $!\n";
}
return bless $self, $class;
@@ -130,13 +145,17 @@ sub clearClient
my $self = shift;
$self->{cipherc} = "";
+ $self->{ciphersuitec} = "";
$self->{flight} = -1;
$self->{direction} = -1;
$self->{partial} = ["", ""];
$self->{record_list} = [];
$self->{message_list} = [];
$self->{clientflags} = "";
+ $self->{sessionfile} = undef;
$self->{clientpid} = 0;
+ $is_tls13 = 0;
+ $ciphersuite = undef;
TLSProxy::Message->clear();
TLSProxy::Record->clear();
@@ -148,6 +167,7 @@ sub clear
$self->clearClient;
$self->{ciphers} = "AES128-SHA";
+ $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256";
$self->{serverflags} = "";
$self->{serverconnects} = 1;
$self->{serverpid} = 0;
@@ -170,6 +190,25 @@ sub clientrestart
$self->clientstart;
}
+sub connect_to_server
+{
+ my $self = shift;
+ my $servaddr = $self->{server_addr};
+
+ $servaddr =~ s/[\[\]]//g; # Remove [ and ]
+
+ my $sock = $IP_factory->(PeerAddr => $servaddr,
+ PeerPort => $self->{server_port},
+ Proto => 'tcp');
+ if (!defined($sock)) {
+ my $err = $!;
+ kill(3, $self->{real_serverpid});
+ die "unable to connect: $err\n";
+ }
+
+ $self->{server_sock} = $sock;
+}
+
sub start
{
my ($self) = shift;
@@ -179,27 +218,90 @@ sub start
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;
+ my $execcmd = $self->execute
+ ." s_server -max_protocol TLSv1.3 -no_comp -rev -engine ossltest"
+ #In TLSv1.3 we issue two session tickets. The default session id
+ #callback gets confused because the ossltest engine causes the same
+ #session id to be created twice due to the changed random number
+ #generation. Using "-ext_cache" replaces the default callback with a
+ #different one that doesn't get confused.
+ ." -ext_cache"
+ ." -accept $self->{server_addr}:0"
+ ." -cert ".$self->cert." -cert2 ".$self->cert
+ ." -naccept ".$self->serverconnects;
+ if ($self->ciphers ne "") {
+ $execcmd .= " -cipher ".$self->ciphers;
+ }
+ if ($self->ciphersuitess ne "") {
+ $execcmd .= " -ciphersuites ".$self->ciphersuitess;
+ }
+ if ($self->serverflags ne "") {
+ $execcmd .= " ".$self->serverflags;
+ }
+ if ($self->debug) {
+ print STDERR "Server command: $execcmd\n";
+ }
+
+ open(my $savedin, "<&STDIN");
+
+ # Temporarily replace STDIN so that sink process can inherit it...
+ $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n";
+ $self->{real_serverpid} = $pid;
+
+ # Process the output from s_server until we find the ACCEPT line, which
+ # tells us what the accepting address and port are.
+ while (<>) {
+ print;
+ s/\R$//; # Better chomp
+ next unless (/^ACCEPT\s.*:(\d+)$/);
+ $self->{server_port} = $1;
+ last;
+ }
+
+ if ($self->{server_port} == 0) {
+ # This actually means that s_server exited, because otherwise
+ # we would still searching for ACCEPT...
+ waitpid($pid, 0);
+ die "no ACCEPT detected in '$execcmd' output: $?\n";
+ }
+
+ # Just make sure everything else is simply printed [as separate lines].
+ # The sub process simply inherits our STD* and will keep consuming
+ # server's output and printing it as long as there is anything there,
+ # out of our way.
+ my $error;
+ $pid = undef;
+ if (eval { require Win32::Process; 1; }) {
+ if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) {
+ $pid = $h->GetProcessID();
+ $self->{proc_handle} = $h; # hold handle till next round [or exit]
+ } else {
+ $error = Win32::FormatMessage(Win32::GetLastError());
}
- if ($self->debug) {
- print STDERR "Server command: $execcmd\n";
+ } else {
+ if (defined($pid = fork)) {
+ $pid or exec("$^X -ne print") or exit($!);
+ } else {
+ $error = $!;
}
- exec($execcmd);
}
- $self->serverpid($pid);
+
+ # Change back to original stdin
+ open(STDIN, "<&", $savedin);
+ close($savedin);
+
+ if (!defined($pid)) {
+ kill(3, $self->{real_serverpid});
+ die "Failed to capture s_server's output: $error\n";
+ }
+
+ $self->{serverpid} = $pid;
+
+ print STDERR "Server responds on ",
+ "$self->{server_addr}:$self->{server_port}\n";
+
+ # Connect right away...
+ $self->connect_to_server();
return $self->clientstart;
}
@@ -207,38 +309,57 @@ sub start
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);
+ my $pid;
+ my $execcmd = $self->execute
+ ." s_client -max_protocol TLSv1.3 -engine ossltest"
+ ." -connect $self->{proxy_addr}:$self->{proxy_port}";
+ if ($self->cipherc ne "") {
+ $execcmd .= " -cipher ".$self->cipherc;
+ }
+ if ($self->ciphersuitesc ne "") {
+ $execcmd .= " -ciphersuites ".$self->ciphersuitesc;
+ }
+ if ($self->clientflags ne "") {
+ $execcmd .= " ".$self->clientflags;
+ }
+ if ($self->clientflags !~ m/-(no)?servername/) {
+ $execcmd .= " -servername localhost";
+ }
+ if (defined $self->sessionfile) {
+ $execcmd .= " -ign_eof";
+ }
+ if ($self->debug) {
+ print STDERR "Client command: $execcmd\n";
+ }
+
+ open(my $savedout, ">&STDOUT");
+ # If we open pipe with new descriptor, attempt to close it,
+ # explicitly or implicitly, would incur waitpid and effectively
+ # dead-lock...
+ if (!($pid = open(STDOUT, "| $execcmd"))) {
+ my $err = $!;
+ kill(3, $self->{real_serverpid});
+ die "Failed to $execcmd: $err\n";
}
- $self->clientpid($pid);
+ $self->{clientpid} = $pid;
+
+ # queue [magic] input
+ print $self->reneg ? "R" : "test";
+
+ # this closes client's stdin without waiting for its pid
+ open(STDOUT, ">&", $savedout);
+ close($savedout);
}
# Wait for incoming connection from client
+ my $fdset = IO::Select->new($self->{proxy_sock});
+ if (!$fdset->can_read(60)) {
+ kill(3, $self->{real_serverpid});
+ die "s_client didn't try to connect\n";
+ }
+
my $client_sock;
if(!($client_sock = $self->{proxy_sock}->accept())) {
warn "Failed accepting incoming connection: $!\n";
@@ -247,89 +368,96 @@ sub clientstart
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 $server_sock = $self->{server_sock};
my $indata;
- my @handles = ($server_sock, $client_sock);
#Wait for either the server socket or the client socket to become readable
+ $fdset = IO::Select->new($server_sock, $client_sock);
my @ready;
+ my $ctr = 0;
local $SIG{PIPE} = "IGNORE";
- while(!(TLSProxy::Message->end) && (@ready = $sel->can_read)) {
+ $self->{saw_session_ticket} = undef;
+ while($fdset->count && $ctr < 10) {
+ if (defined($self->{sessionfile})) {
+ # s_client got -ign_eof and won't be exiting voluntarily, so we
+ # look for data *and* session ticket...
+ last if TLSProxy::Message->success()
+ && $self->{saw_session_ticket};
+ }
+ if (!(@ready = $fdset->can_read(1))) {
+ $ctr++;
+ next;
+ }
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);
+ if ($server_sock->sysread($indata, 16384)) {
+ if ($indata = $self->process_packet(1, $indata)) {
+ $client_sock->syswrite($indata) or goto END;
+ }
+ $ctr = 0;
+ } else {
+ $fdset->remove($server_sock);
+ $client_sock->shutdown(SHUT_WR);
+ }
} elsif ($hand == $client_sock) {
- $client_sock->sysread($indata, 16384) or goto END;
- $indata = $self->process_packet(0, $indata);
- $server_sock->syswrite($indata);
+ if ($client_sock->sysread($indata, 16384)) {
+ if ($indata = $self->process_packet(0, $indata)) {
+ $server_sock->syswrite($indata) or goto END;
+ }
+ $ctr = 0;
+ } else {
+ $fdset->remove($client_sock);
+ $server_sock->shutdown(SHUT_WR);
+ }
} else {
- print "Err\n";
- goto END;
+ kill(3, $self->{real_serverpid});
+ die "Unexpected handle";
}
}
}
+ if ($ctr >= 10) {
+ kill(3, $self->{real_serverpid});
+ die "No progress made";
+ }
+
END:
print "Connection closed\n";
if($server_sock) {
$server_sock->close();
+ $self->{server_sock} = undef;
}
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;
+
+ my $pid;
+ if (--$self->{serverconnects} == 0) {
+ $pid = $self->{serverpid};
+ print "Waiting for 'perl -ne print' process to close: $pid...\n";
+ $pid = waitpid($pid, 0);
+ if ($pid > 0) {
+ die "exit code $? from 'perl -ne print' process\n" if $? != 0;
+ } elsif ($pid == 0) {
+ kill(3, $self->{real_serverpid});
+ die "lost control over $self->{serverpid}?";
+ }
+ $pid = $self->{real_serverpid};
+ print "Waiting for s_server process to close: $pid...\n";
+ # it's done already, just collect the exit code [and reap]...
+ waitpid($pid, 0);
+ die "exit code $? from s_server process\n" if $? != 0;
} else {
- # Give s_server sufficient time to finish what it was doing
- usleep(250000);
+ # It's a bit counter-intuitive spot to make next connection to
+ # the s_server. Rationale is that established connection works
+ # as syncronization point, in sense that this way we know that
+ # s_server is actually done with current session...
+ $self->connect_to_server();
}
- die "clientpid is zero\n" if $self->clientpid == 0;
- print "Waiting for client process to close: ".$self->clientpid."\n";
- waitpid($self->clientpid, 0);
+ $pid = $self->{clientpid};
+ print "Waiting for s_client process to close: $pid...\n";
+ waitpid($pid, 0);
return 1;
}
@@ -358,9 +486,10 @@ sub process_packet
#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);
+ 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->{record_list}}, @{$ret[0]};
push @{$self->{message_list}}, @{$ret[1]};
print "\n";
@@ -374,10 +503,18 @@ sub process_packet
$self->filter->($self);
}
+ #Take a note on NewSessionTicket
+ foreach my $message (reverse @{$self->{message_list}}) {
+ if ($message->{mt} == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
+ $self->{saw_session_ticket} = 1;
+ last;
+ }
+ }
+
#Reconstruct the packet
$packet = "";
foreach my $record (@{$self->record_list}) {
- $packet .= $record->reconstruct_record();
+ $packet .= $record->reconstruct_record($server);
}
print "Forwarded packet length = ".length($packet)."\n\n";
@@ -436,29 +573,33 @@ 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 serverpid
+{
+ my $self = shift;
+ return $self->{serverpid};
+}
+sub clientpid
+{
+ my $self = shift;
+ return $self->{clientpid};
+}
+
+#Read/write accessors
sub filter
{
my $self = shift;
if (@_) {
- $self->{filter} = shift;
+ $self->{filter} = shift;
}
return $self->{filter};
}
@@ -466,23 +607,39 @@ sub cipherc
{
my $self = shift;
if (@_) {
- $self->{cipherc} = shift;
+ $self->{cipherc} = shift;
}
return $self->{cipherc};
}
+sub ciphersuitesc
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphersuitesc} = shift;
+ }
+ return $self->{ciphersuitesc};
+}
sub ciphers
{
my $self = shift;
if (@_) {
- $self->{ciphers} = shift;
+ $self->{ciphers} = shift;
}
return $self->{ciphers};
}
+sub ciphersuitess
+{
+ my $self = shift;
+ if (@_) {
+ $self->{ciphersuitess} = shift;
+ }
+ return $self->{ciphersuitess};
+}
sub serverflags
{
my $self = shift;
if (@_) {
- $self->{serverflags} = shift;
+ $self->{serverflags} = shift;
}
return $self->{serverflags};
}
@@ -490,7 +647,7 @@ sub clientflags
{
my $self = shift;
if (@_) {
- $self->{clientflags} = shift;
+ $self->{clientflags} = shift;
}
return $self->{clientflags};
}
@@ -498,7 +655,7 @@ sub serverconnects
{
my $self = shift;
if (@_) {
- $self->{serverconnects} = shift;
+ $self->{serverconnects} = shift;
}
return $self->{serverconnects};
}
@@ -514,22 +671,6 @@ sub message_list
}
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
{
@@ -541,13 +682,47 @@ sub fill_known_data
return $ret;
}
+sub is_tls13
+{
+ my $class = shift;
+ if (@_) {
+ $is_tls13 = shift;
+ }
+ return $is_tls13;
+}
+
sub reneg
{
my $self = shift;
if (@_) {
- $self->{reneg} = shift;
+ $self->{reneg} = shift;
}
return $self->{reneg};
}
+#Setting a sessionfile means that the client will not close until the given
+#file exists. This is useful in TLSv1.3 where otherwise s_client will close
+#immediately at the end of the handshake, but before the session has been
+#received from the server. A side effect of this is that s_client never sends
+#a close_notify, so instead we consider success to be when it sends application
+#data over the connection.
+sub sessionfile
+{
+ my $self = shift;
+ if (@_) {
+ $self->{sessionfile} = shift;
+ TLSProxy::Message->successondata(1);
+ }
+ return $self->{sessionfile};
+}
+
+sub ciphersuite
+{
+ my $class = shift;
+ if (@_) {
+ $ciphersuite = shift;
+ }
+ return $ciphersuite;
+}
+
1;
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/Record.pm b/deps/openssl/openssl/util/perl/TLSProxy/Record.pm
index 786ba0c72b..0a280cb269 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/Record.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/Record.pm
@@ -11,8 +11,8 @@ use TLSProxy::Proxy;
package TLSProxy::Record;
-my $server_ccs_seen = 0;
-my $client_ccs_seen = 0;
+my $server_encrypting = 0;
+my $client_encrypting = 0;
my $etm = 0;
use constant TLS_RECORD_HEADER_LENGTH => 5;
@@ -35,12 +35,13 @@ my %record_type = (
);
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
+ VERS_TLS_1_4 => 0x0305,
+ VERS_TLS_1_3 => 0x0304,
+ VERS_TLS_1_2 => 0x0303,
+ VERS_TLS_1_1 => 0x0302,
+ VERS_TLS_1_0 => 0x0301,
+ VERS_SSL_3_0 => 0x0300,
+ VERS_SSL_LT_3_0 => 0x02ff
};
my %tls_version = (
@@ -62,72 +63,66 @@ sub get_records
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 " Record $recnum ", $server ? "(server -> client)\n"
+ : "(client -> server)\n";
+
+ #Get the record header (unpack can't fail if $packet is too short)
+ my ($content_type, $version, $len) = unpack('Cnn', $packet);
+
+ if (length($packet) < TLS_RECORD_HEADER_LENGTH + ($len // 0)) {
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);
- }
+ last;
+ }
- 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) {
+ my $data = substr($packet, TLS_RECORD_HEADER_LENGTH, $len);
+
+ print " Content type: ".$record_type{$content_type}."\n";
+ print " Version: $tls_version{$version}\n";
+ print " Length: $len\n";
+
+ my $record = TLSProxy::Record->new(
+ $flight,
+ $content_type,
+ $version,
+ $len,
+ 0,
+ $len, # len_real
+ $len, # decrypt_len
+ $data, # data
+ $data # decrypt_data
+ );
+
+ if ($content_type != RT_CCS
+ && (!TLSProxy::Proxy->is_tls13()
+ || $content_type != RT_ALERT)) {
+ if (($server && $server_encrypting)
+ || (!$server && $client_encrypting)) {
+ if (!TLSProxy::Proxy->is_tls13() && $etm) {
$record->decryptETM();
} else {
$record->decrypt();
}
+ $record->encrypted(1);
+
+ if (TLSProxy::Proxy->is_tls13()) {
+ print " Inner content type: "
+ .$record_type{$record->content_type()}."\n";
+ }
}
+ }
- push @record_list, $record;
+ 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;
+ #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++;
- }
+ $packet = substr($packet, TLS_RECORD_HEADER_LENGTH + $len);
+ $recnum++;
}
return (\@record_list, \@message_list, $partial);
@@ -135,26 +130,26 @@ sub get_records
sub clear
{
- $server_ccs_seen = 0;
- $client_ccs_seen = 0;
+ $server_encrypting = 0;
+ $client_encrypting = 0;
}
#Class level accessors
-sub server_ccs_seen
+sub server_encrypting
{
my $class = shift;
if (@_) {
- $server_ccs_seen = shift;
+ $server_encrypting = shift;
}
- return $server_ccs_seen;
+ return $server_encrypting;
}
-sub client_ccs_seen
+sub client_encrypting
{
my $class = shift;
if (@_) {
- $client_ccs_seen = shift;
+ $client_encrypting= shift;
}
- return $client_ccs_seen;
+ return $client_encrypting;
}
#Enable/Disable Encrypt-then-MAC
sub etm
@@ -190,7 +185,9 @@ sub new
data => $data,
decrypt_data => $decrypt_data,
orig_decrypt_data => $decrypt_data,
- sent => 0
+ sent => 0,
+ encrypted => 0,
+ outer_content_type => RT_APPLICATION_DATA
};
return bless $self, $class;
@@ -227,22 +224,44 @@ sub decryptETM
sub decrypt()
{
my ($self) = shift;
-
+ my $mactaglen = 20;
my $data = $self->data;
- if($self->version >= VERS_TLS_1_1()) {
- #TLS1.1+ has an explicit IV. Throw it away
+ #Throw away any IVs
+ if (TLSProxy::Proxy->is_tls13()) {
+ #A TLS1.3 client, when processing the server's initial flight, could
+ #respond with either an encrypted or an unencrypted alert.
+ if ($self->content_type() == RT_ALERT) {
+ #TODO(TLS1.3): Eventually it is sufficient just to check the record
+ #content type. If an alert is encrypted it will have a record
+ #content type of application data. However we haven't done the
+ #record layer changes yet, so it's a bit more complicated. For now
+ #we will additionally check if the data length is 2 (1 byte for
+ #alert level, 1 byte for alert description). If it is, then this is
+ #an unencrypted alert, so don't try to decrypt
+ return $data if (length($data) == 2);
+ }
+ $mactaglen = 16;
+ } elsif ($self->version >= VERS_TLS_1_1()) {
+ #16 bytes for a standard IV
$data = substr($data, 16);
- }
- #Find out what the padding byte is
- my $padval = unpack("C", substr($data, length($data) - 1));
+ #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 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);
+ #Throw away the MAC or TAG
+ $data = substr($data, 0, length($data) - $mactaglen);
+
+ if (TLSProxy::Proxy->is_tls13()) {
+ #Get the content type
+ my $content_type = unpack("C", substr($data, length($data) - 1));
+ $self->content_type($content_type);
+ $data = substr($data, 0, length($data) - 1);
+ }
$self->decrypt_data($data);
$self->decrypt_len(length($data));
@@ -254,9 +273,11 @@ sub decrypt()
sub reconstruct_record
{
my $self = shift;
+ my $server = shift;
my $data;
- if ($self->{sent}) {
+ #We only replay the records in the same direction
+ if ($self->{sent} || ($self->flight & 1) != $server) {
return "";
}
$self->{sent} = 1;
@@ -264,7 +285,14 @@ sub reconstruct_record
if ($self->sslv2) {
$data = pack('n', $self->len | 0x8000);
} else {
- $data = pack('Cnn', $self->content_type, $self->version, $self->len);
+ if (TLSProxy::Proxy->is_tls13() && $self->encrypted) {
+ $data = pack('Cnn', $self->outer_content_type, $self->version,
+ $self->len);
+ } else {
+ $data = pack('Cnn', $self->content_type, $self->version,
+ $self->len);
+ }
+
}
$data .= $self->data;
@@ -277,16 +305,6 @@ 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;
@@ -336,4 +354,48 @@ sub len
}
return $self->{len};
}
+sub version
+{
+ my $self = shift;
+ if (@_) {
+ $self->{version} = shift;
+ }
+ return $self->{version};
+}
+sub content_type
+{
+ my $self = shift;
+ if (@_) {
+ $self->{content_type} = shift;
+ }
+ return $self->{content_type};
+}
+sub encrypted
+{
+ my $self = shift;
+ if (@_) {
+ $self->{encrypted} = shift;
+ }
+ return $self->{encrypted};
+}
+sub outer_content_type
+{
+ my $self = shift;
+ if (@_) {
+ $self->{outer_content_type} = shift;
+ }
+ return $self->{outer_content_type};
+}
+sub is_fatal_alert
+{
+ my $self = shift;
+ my $server = shift;
+
+ if (($self->{flight} & 1) == $server
+ && $self->{content_type} == TLSProxy::Record::RT_ALERT) {
+ my ($level, $alert) = unpack('CC', $self->decrypt_data);
+ return $alert if ($level == 2);
+ }
+ return 0;
+}
1;
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/ServerHello.pm b/deps/openssl/openssl/util/perl/TLSProxy/ServerHello.pm
index 79a8be9a89..84f2faab05 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/ServerHello.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/ServerHello.pm
@@ -1,4 +1,4 @@
-# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+# 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
@@ -12,6 +12,11 @@ package TLSProxy::ServerHello;
use vars '@ISA';
push @ISA, 'TLSProxy::Message';
+my $hrrrandom = pack("C*", 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE,
+ 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2,
+ 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09,
+ 0xE2, 0xC8, 0xA8, 0x33, 0x9C);
+
sub new
{
my $class = shift;
@@ -45,16 +50,23 @@ sub parse
my $self = shift;
my $ptr = 2;
my ($server_version) = unpack('n', $self->data);
+ my $neg_version = $server_version;
+
my $random = substr($self->data, $ptr, 32);
$ptr += 32;
- my $session_id_len = unpack('C', substr($self->data, $ptr));
+ my $session_id_len = 0;
+ my $session = "";
+ $session_id_len = unpack('C', substr($self->data, $ptr));
$ptr++;
- my $session = substr($self->data, $ptr, $session_id_len);
+ $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));
+ my $comp_meth = 0;
+ $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;
@@ -82,6 +94,18 @@ sub parse
my $extdata = substr($extension_data, 4, $size);
$extension_data = substr($extension_data, 4 + $size);
$extensions{$type} = $extdata;
+ if ($type == TLSProxy::Message::EXT_SUPPORTED_VERSIONS) {
+ $neg_version = unpack('n', $extdata);
+ }
+ }
+
+ if ($random eq $hrrrandom) {
+ TLSProxy::Proxy->is_tls13(1);
+ } elsif ($neg_version == TLSProxy::Record::VERS_TLS_1_3) {
+ TLSProxy::Proxy->is_tls13(1);
+
+ TLSProxy::Record->server_encrypting(1);
+ TLSProxy::Record->client_encrypting(1);
}
$self->server_version($server_version);
@@ -89,11 +113,13 @@ sub parse
$self->session_id_len($session_id_len);
$self->session($session);
$self->ciphersuite($ciphersuite);
+ TLSProxy::Proxy->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";
@@ -145,9 +171,9 @@ sub server_version
{
my $self = shift;
if (@_) {
- $self->{client_version} = shift;
+ $self->{server_version} = shift;
}
- return $self->{client_version};
+ return $self->{server_version};
}
sub random
{
diff --git a/deps/openssl/openssl/util/perl/TLSProxy/ServerKeyExchange.pm b/deps/openssl/openssl/util/perl/TLSProxy/ServerKeyExchange.pm
index 6e5b4cdcb4..cb4cc7c762 100644
--- a/deps/openssl/openssl/util/perl/TLSProxy/ServerKeyExchange.pm
+++ b/deps/openssl/openssl/util/perl/TLSProxy/ServerKeyExchange.pm
@@ -33,6 +33,7 @@ sub new
$self->{p} = "";
$self->{g} = "";
$self->{pub_key} = "";
+ $self->{sigalg} = -1;
$self->{sig} = "";
return $self;
@@ -41,10 +42,13 @@ sub new
sub parse
{
my $self = shift;
+ my $sigalg = -1;
- #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)
+ #Minimal SKE parsing. Only supports one known DHE ciphersuite at the moment
+ return if TLSProxy::Proxy->ciphersuite()
+ != TLSProxy::Message::CIPHER_ADH_AES_128_SHA
+ && TLSProxy::Proxy->ciphersuite()
+ != TLSProxy::Message::CIPHER_DHE_RSA_AES_128_SHA;
my $p_len = unpack('n', $self->data);
my $ptr = 2;
@@ -62,18 +66,28 @@ sub parse
$ptr += $pub_key_len;
#We assume its signed
- my $sig_len = unpack('n', substr($self->data, $ptr));
+ my $record = ${$self->records}[0];
+
+ if (TLSProxy::Proxy->is_tls13()
+ || $record->version() == TLSProxy::Record::VERS_TLS_1_2) {
+ $sigalg = unpack('n', substr($self->data, $ptr));
+ $ptr += 2;
+ }
my $sig = "";
- if (defined $sig_len) {
- $ptr += 2;
- $sig = substr($self->data, $ptr, $sig_len);
- $ptr += $sig_len;
+ if (defined $sigalg) {
+ my $sig_len = unpack('n', substr($self->data, $ptr));
+ 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);
+ $self->sigalg($sigalg) if defined $sigalg;
+ $self->signature($sig);
}
@@ -89,9 +103,10 @@ sub set_message_contents
$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;
+ $data .= pack('n', $self->sigalg) if ($self->sigalg != -1);
+ if (length($self->signature) > 0) {
+ $data .= pack('n', length($self->signature));
+ $data .= $self->signature;
}
$self->data($data);
@@ -123,7 +138,15 @@ sub pub_key
}
return $self->{pub_key};
}
-sub sig
+sub sigalg
+{
+ my $self = shift;
+ if (@_) {
+ $self->{sigalg} = shift;
+ }
+ return $self->{sigalg};
+}
+sub signature
{
my $self = shift;
if (@_) {
diff --git a/deps/openssl/openssl/util/perl/checkhandshake.pm b/deps/openssl/openssl/util/perl/checkhandshake.pm
new file mode 100644
index 0000000000..c53b96d5ee
--- /dev/null
+++ b/deps/openssl/openssl/util/perl/checkhandshake.pm
@@ -0,0 +1,228 @@
+#! /usr/bin/env perl
+# Copyright 2015-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
+
+package checkhandshake;
+
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+
+use Exporter;
+our @ISA = 'Exporter';
+our @EXPORT = qw(@handmessages @extensions checkhandshake);
+
+use constant {
+ DEFAULT_HANDSHAKE => 1,
+ OCSP_HANDSHAKE => 2,
+ RESUME_HANDSHAKE => 4,
+ CLIENT_AUTH_HANDSHAKE => 8,
+ RENEG_HANDSHAKE => 16,
+ NPN_HANDSHAKE => 32,
+ EC_HANDSHAKE => 64,
+ HRR_HANDSHAKE => 128,
+ HRR_RESUME_HANDSHAKE => 256,
+
+ ALL_HANDSHAKES => 511
+};
+
+use constant {
+ #DEFAULT also includes SESSION_TICKET_SRV_EXTENSION and SERVER_NAME_CLI
+ DEFAULT_EXTENSIONS => 0x00000007,
+ SESSION_TICKET_SRV_EXTENSION => 0x00000002,
+ SERVER_NAME_CLI_EXTENSION => 0x00000004,
+ SERVER_NAME_SRV_EXTENSION => 0x00000008,
+ STATUS_REQUEST_CLI_EXTENSION => 0x00000010,
+ STATUS_REQUEST_SRV_EXTENSION => 0x00000020,
+ ALPN_CLI_EXTENSION => 0x00000040,
+ ALPN_SRV_EXTENSION => 0x00000080,
+ SCT_CLI_EXTENSION => 0x00000100,
+ SCT_SRV_EXTENSION => 0x00000200,
+ RENEGOTIATE_CLI_EXTENSION => 0x00000400,
+ NPN_CLI_EXTENSION => 0x00000800,
+ NPN_SRV_EXTENSION => 0x00001000,
+ SRP_CLI_EXTENSION => 0x00002000,
+ #Client side for ec point formats is a default extension
+ EC_POINT_FORMAT_SRV_EXTENSION => 0x00004000,
+ PSK_CLI_EXTENSION => 0x00008000,
+ PSK_SRV_EXTENSION => 0x00010000,
+ KEY_SHARE_SRV_EXTENSION => 0x00020000,
+ PSK_KEX_MODES_EXTENSION => 0x00040000,
+ KEY_SHARE_HRR_EXTENSION => 0x00080000,
+ SUPPORTED_GROUPS_SRV_EXTENSION => 0x00100000,
+ POST_HANDSHAKE_AUTH_CLI_EXTENSION => 0x00200000
+};
+
+our @handmessages = ();
+our @extensions = ();
+
+sub checkhandshake($$$$)
+{
+ my ($proxy, $handtype, $exttype, $testname) = @_;
+
+ subtest $testname => sub {
+ my $loop = 0;
+ my $numtests;
+ my $extcount;
+ my $clienthelloseen = 0;
+
+ my $lastmt = 0;
+ my $numsh = 0;
+ if (TLSProxy::Proxy::is_tls13()) {
+ #How many ServerHellos are we expecting?
+ for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
+ next if (($handmessages[$loop][1] & $handtype) == 0);
+ $numsh++ if ($lastmt != TLSProxy::Message::MT_SERVER_HELLO
+ && $handmessages[$loop][0] == TLSProxy::Message::MT_SERVER_HELLO);
+ $lastmt = $handmessages[$loop][0];
+ }
+ }
+
+ #First count the number of tests
+ my $nextmess = 0;
+ my $message = undef;
+ my $chnum = 0;
+ my $shnum = 0;
+ if (!TLSProxy::Proxy::is_tls13()) {
+ # In non-TLSv1.3 we always treat reneg CH and SH like the first CH
+ # and SH
+ $chnum = 1;
+ $shnum = 1;
+ }
+ #If we're only expecting one ServerHello out of two then we skip the
+ #first ServerHello in the list completely
+ $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13());
+ $loop = 0;
+ for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
+ next if (($handmessages[$loop][1] & $handtype) == 0);
+ if (scalar @{$proxy->message_list} > $nextmess) {
+ $message = ${$proxy->message_list}[$nextmess];
+ $nextmess++;
+ } else {
+ $message = undef;
+ }
+ $numtests++;
+
+ next if (!defined $message);
+ if (TLSProxy::Proxy::is_tls13()) {
+ $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
+ $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO;
+ }
+ next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+ && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
+ && $message->mt() !=
+ TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
+ && $message->mt() != TLSProxy::Message::MT_CERTIFICATE);
+
+ next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE
+ && !TLSProxy::Proxy::is_tls13();
+
+ my $extchnum = 1;
+ my $extshnum = 1;
+ for (my $extloop = 0;
+ $extensions[$extloop][2] != 0;
+ $extloop++) {
+ $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
+ && TLSProxy::Proxy::is_tls13();
+ $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO
+ && $extchnum == 2;
+ next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
+ && $extchnum != $chnum;
+ next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO
+ && $extshnum != $shnum;
+ next if ($message->mt() != $extensions[$extloop][0]);
+ $numtests++;
+ }
+ $numtests++;
+ }
+
+ plan tests => $numtests;
+
+ $nextmess = 0;
+ $message = undef;
+ if (TLSProxy::Proxy::is_tls13()) {
+ $chnum = 0;
+ $shnum = 0;
+ } else {
+ # In non-TLSv1.3 we always treat reneg CH and SH like the first CH
+ # and SH
+ $chnum = 1;
+ $shnum = 1;
+ }
+ #If we're only expecting one ServerHello out of two then we skip the
+ #first ServerHello in the list completely
+ $shnum++ if ($numsh == 1 && TLSProxy::Proxy::is_tls13());
+ for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) {
+ next if (($handmessages[$loop][1] & $handtype) == 0);
+ if (scalar @{$proxy->message_list} > $nextmess) {
+ $message = ${$proxy->message_list}[$nextmess];
+ $nextmess++;
+ } else {
+ $message = undef;
+ }
+ if (!defined $message) {
+ fail("Message type check. Got nothing, expected "
+ .$handmessages[$loop][0]);
+ next;
+ } else {
+ ok($message->mt == $handmessages[$loop][0],
+ "Message type check. Got ".$message->mt
+ .", expected ".$handmessages[$loop][0]);
+ }
+ if (TLSProxy::Proxy::is_tls13()) {
+ $chnum++ if $message->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
+ $shnum++ if $message->mt() == TLSProxy::Message::MT_SERVER_HELLO;
+ }
+
+ next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+ && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
+ && $message->mt() !=
+ TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
+ && $message->mt() != TLSProxy::Message::MT_CERTIFICATE);
+
+ next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE
+ && !TLSProxy::Proxy::is_tls13();
+
+ if ($message->mt() == TLSProxy::Message::MT_CLIENT_HELLO) {
+ #Add renegotiate extension we will expect if renegotiating
+ $exttype |= RENEGOTIATE_CLI_EXTENSION
+ if ($clienthelloseen && !TLSProxy::Proxy::is_tls13());
+ $clienthelloseen = 1;
+ }
+ #Now check that we saw the extensions we expected
+ my $msgexts = $message->extension_data();
+ my $extchnum = 1;
+ my $extshnum = 1;
+ for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0;
+ $extloop++) {
+ #In TLSv1.3 we can have two ClientHellos if there has been a
+ #HelloRetryRequest, and they may have different extensions. Skip
+ #if these are extensions for a different ClientHello
+ $extchnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
+ && TLSProxy::Proxy::is_tls13();
+ $extshnum = 2 if $extensions[$extloop][0] != TLSProxy::Message::MT_SERVER_HELLO
+ && $extchnum == 2;
+ next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
+ && $extchnum != $chnum;
+ next if $extensions[$extloop][0] == TLSProxy::Message::MT_SERVER_HELLO
+ && $extshnum != $shnum;
+ next if ($message->mt() != $extensions[$extloop][0]);
+ ok (($extensions[$extloop][2] & $exttype) == 0
+ || defined ($msgexts->{$extensions[$extloop][1]}),
+ "Extension presence check (Message: ".$message->mt()
+ ." Extension: ".($extensions[$extloop][2] & $exttype).", "
+ .$extloop.")");
+ $extcount++ if (($extensions[$extloop][2] & $exttype) != 0);
+ }
+ ok($extcount == keys %$msgexts, "Extensions count mismatch ("
+ .$extcount.", ".(keys %$msgexts)
+ .")");
+ }
+ }
+}
+
+1;