if disabled("tls1_3");
$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+$ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
use constant {
DEFAULT_HANDSHAKE => 1,
ALL_HANDSHAKES => 15
};
+use constant {
+ DEFAULT_EXTENSIONS => 0x00000001,
+ SERVER_NAME_CLI_EXTENSION => 0x00000002,
+ SERVER_NAME_SRV_EXTENSION => 0x00000004,
+ STATUS_REQUEST_CLI_EXTENSION => 0x00000008,
+ STATUS_REQUEST_SRV_EXTENSION => 0x00000010,
+ ALPN_CLI_EXTENSION => 0x00000020,
+ ALPN_SRV_EXTENSION => 0x00000040,
+ SCT_CLI_EXTENSION => 0x00000080
+};
+
my @handmessages = (
[TLSProxy::Message::MT_CLIENT_HELLO, ALL_HANDSHAKES],
[TLSProxy::Message::MT_SERVER_HELLO, ALL_HANDSHAKES],
[0, 0]
);
+my @extensions = (
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, SERVER_NAME_CLI_EXTENSION],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST, STATUS_REQUEST_CLI_EXTENSION],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN, ALPN_CLI_EXTENSION],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT, SCT_CLI_EXTENSION],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE, DEFAULT_EXTENSIONS],
+ [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, DEFAULT_EXTENSIONS],
+
+ [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, DEFAULT_EXTENSIONS],
+
+ [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_SERVER_NAME, SERVER_NAME_SRV_EXTENSION],
+ [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_STATUS_REQUEST, STATUS_REQUEST_SRV_EXTENSION],
+ [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, TLSProxy::Message::EXT_ALPN, ALPN_SRV_EXTENSION],
+ [0,0,0]
+);
+
my $proxy = TLSProxy::Proxy->new(
undef,
cmdstr(app(["openssl"]), display => 1),
(!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
);
-sub checkmessages($$);
+sub checkmessages($$$);
#Test 1: Check we get all the right messages for a default handshake
(undef, my $session) = tempfile();
#$proxy->serverconnects(2);
$proxy->clientflags("-sess_out ".$session);
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 3;
-checkmessages(DEFAULT_HANDSHAKE, "Default handshake test");
+plan tests => 12;
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS, "Default handshake test");
#TODO(TLS1.3): Test temporarily disabled until we implement TLS1.3 resumption
#Test 2: Resumption handshake
#checkmessages(RESUME_HANDSHAKE, "Resumption handshake test");
unlink $session;
-#Test 3: A default handshake, but with a CertificateStatus message
+#Test 3: A status_request handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-status");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE,
+ DEFAULT_EXTENSIONS | STATUS_REQUEST_CLI_EXTENSION,
+ "status_request handshake test (client)");
+
+#Test 4: A status_request handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-status_file "
+ .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
+ "status_request handshake test (server)");
+
+#Test 5: A status_request handshake (client and server)
#TODO(TLS1.3): TLS1.3 doesn't actually have CertificateStatus messages. This is
#a temporary test until such time as we do proper TLS1.3 style certificate
#status
$proxy->serverflags("-status_file "
.srctop_file("test", "recipes", "ocsp-response.der"));
$proxy->start();
-checkmessages(OCSP_HANDSHAKE, "OCSP handshake test");
+checkmessages(OCSP_HANDSHAKE,
+ DEFAULT_EXTENSIONS | STATUS_REQUEST_CLI_EXTENSION
+ | STATUS_REQUEST_SRV_EXTENSION,
+ "status_request handshake test");
-#Test 4: A client auth handshake
+#Test 6: A client auth handshake
$proxy->clear();
$proxy->clientflags("-cert ".srctop_file("apps", "server.pem"));
$proxy->serverflags("-Verify 5");
$proxy->start();
-checkmessages(CLIENT_AUTH_HANDSHAKE, "Client auth handshake test");
+checkmessages(CLIENT_AUTH_HANDSHAKE, DEFAULT_EXTENSIONS,
+ "Client auth handshake test");
-sub checkmessages($$)
+#Test 7: Server name handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-servername testhost");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS | SERVER_NAME_CLI_EXTENSION,
+ "Server name handshake test (client)");
+
+#Test 8: Server name handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
+ "Server name handshake test (server)");
+
+#Test 9: Server name handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-servername testhost");
+$proxy->serverflags("-servername testhost");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE,
+ DEFAULT_EXTENSIONS | SERVER_NAME_CLI_EXTENSION
+ | SERVER_NAME_SRV_EXTENSION,
+ "Server name handshake test");
+
+#Test 10: ALPN handshake (client request only)
+$proxy->clear();
+$proxy->clientflags("-alpn test");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS | ALPN_CLI_EXTENSION,
+ "ALPN handshake test (client)");
+
+#Test 11: ALPN handshake (server support only)
+$proxy->clear();
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE, DEFAULT_EXTENSIONS,
+ "ALPN handshake test (server)");
+
+#Test 12: ALPN handshake (client and server)
+$proxy->clear();
+$proxy->clientflags("-alpn test");
+$proxy->serverflags("-alpn test");
+$proxy->start();
+checkmessages(DEFAULT_HANDSHAKE,
+ DEFAULT_EXTENSIONS | ALPN_CLI_EXTENSION | ALPN_SRV_EXTENSION,
+ "ALPN handshake test");
+
+#Test 13: SCT handshake (client request only)
+#TODO(TLS1.3): This only checks that the client side extension appears. The
+#SCT extension is unusual in that we have no built-in server side implementation
+#The server side implementation can nomrally be added using the custom
+#extensions framework (e.g. by using the "-serverinfo" s_server option). However
+#currently we only support <= TLS1.2 for custom extensions because the existing
+#framework and API has no knowledge of the TLS1.3 messages
+$proxy->clear();
+#Note: -ct also sends status_request
+$proxy->clientflags("-ct");
+$proxy->serverflags("-status_file "
+ .srctop_file("test", "recipes", "ocsp-response.der"));
+$proxy->start();
+checkmessages(OCSP_HANDSHAKE,
+ DEFAULT_EXTENSIONS | SCT_CLI_EXTENSION
+ | STATUS_REQUEST_CLI_EXTENSION | STATUS_REQUEST_SRV_EXTENSION,
+ "SCT handshake test");
+
+sub checkmessages($$$)
{
- my ($handtype, $testname) = @_;
+ my ($handtype, $exttype, $testname) = @_;
subtest $testname => sub {
my $loop = 0;
my $numtests;
+ my $extcount;
#First count the number of tests
for ($numtests = 1; $handmessages[$loop][1] != 0; $loop++) {
$numtests++ if (($handmessages[$loop][1] & $handtype) != 0);
}
+ #Add number of extensions we check plus 3 for the number of messages
+ #that contain extensions
+ $numtests += $#extensions + 3;
+
plan tests => $numtests;
$loop = 0;
"Message type check. Got ".$message->mt
.", expected ".$handmessages[$loop][0]);
$loop++;
+
+
+ next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+ && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
+ && $message->mt() !=
+ TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS);
+ #Now check that we saw the extensions we expected
+ my $msgexts = $message->extension_data();
+ for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0;
+ $extloop++) {
+ 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)
+ .")");
}
ok($handmessages[$loop][1] == 0, "All expected messages processed");
}
--- /dev/null
+# 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;