foreach my $message (@{$proxy->message_list}) {
if ($message->mt == $message_type) {
my %extensions = %{$message->extension_data};
- # Add a duplicate (unknown) extension.
- $message->set_extension(TLSProxy::Message::EXT_DUPLICATE_EXTENSION, "");
- $message->set_extension(TLSProxy::Message::EXT_DUPLICATE_EXTENSION, "");
+ # Add a duplicate extension. We use cryptopro_bug since we never
+ # normally write that one, and it is allowed as unsolicited in the
+ # ServerHello
+ $message->set_extension(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION, "");
+ $message->dupext(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION);
$message->repack();
}
}
$sent_unsolisited_extension = 1;
}
+sub inject_cryptopro_extension
+{
+ my $proxy = shift;
+
+ # We're only interested in the initial ClientHello
+ if ($proxy->flight != 0) {
+ return;
+ }
+
+ my $message = ${$proxy->message_list}[0];
+ $message->set_extension(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION, "");
+ $message->repack();
+}
+
# Test 1-2: Sending a duplicate extension should fail.
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 7;
+plan tests => 8;
ok($fatal_alert, "Duplicate ClientHello extension");
$fatal_alert = 0;
$proxy->start();
ok($fatal_alert, "Unsolicited server name extension (TLSv1.3)");
}
+
+#Test 8: Send the cryptopro extension in a ClientHello. Normally this is an
+# unsolicited extension only ever seen in the ServerHello. We should
+# ignore it in a ClientHello
+$proxy->clear();
+$proxy->filter(\&inject_cryptopro_extension);
+$proxy->start();
+ok(TLSProxy::Message->success(), "Cryptopro extension in ClientHello");
$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;
$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;
}
foreach my $key (keys %{$self->extension_data}) {
next if ($key == TLSProxy::Message::EXT_PSK);
$extensions .= $self->extension_contents($key);
+ #Add extension twice if we are duplicating that extension
+ $extensions .= $self->extension_contents($key) if ($key == $self->dupext);
}
#PSK extension always goes last...
if (defined ${$self->extension_data}{TLSProxy::Message::EXT_PSK}) {
$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));
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_CRYPTOPRO_BUG_EXTENSION => 0xfde8,
EXT_UNKNOWN => 0xfffe,
#Unknown extension that should appear last
EXT_FORCE_LAST => 0xffff
records => $records,
mt => $mt,
startoffset => $startoffset,
- message_frag_lens => $message_frag_lens
+ message_frag_lens => $message_frag_lens,
+ dupext => -1
};
return bless $self, $class;
my $self = shift;
return TLS_MESSAGE_HEADER_LENGTH + length($self->data);
}
+sub dupext
+{
+ my $self = shift;
+ if (@_) {
+ $self->{dupext} = shift;
+ }
+ return $self->{dupext};
+}
sub successondata
{
my $class = shift;
$extensions .= pack("n", $key);
$extensions .= pack("n", length($extdata));
$extensions .= $extdata;
- if ($key == TLSProxy::Message::EXT_DUPLICATE_EXTENSION) {
+ if ($key == $self->dupext) {
$extensions .= pack("n", $key);
$extensions .= pack("n", length($extdata));
$extensions .= $extdata;