+
+sub add_unknown_record_type
+{
+ my $proxy = shift;
+ my $records = $proxy->record_list;
+ state $added_record;
+
+ # We'll change a record after the initial version neg has taken place
+ if ($proxy->flight == 0) {
+ $added_record = 0;
+ return;
+ } elsif ($proxy->flight != 1 || $added_record) {
+ $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
+ return;
+ }
+
+ my $record = TLSProxy::Record->new(
+ 1,
+ TLSProxy::Record::RT_UNKNOWN,
+ @{$records}[-1]->version(),
+ 1,
+ 0,
+ 1,
+ 1,
+ "X",
+ "X"
+ );
+
+ #Find ServerHello record and insert after that
+ my $i;
+ for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
+ next;
+ }
+ $i++;
+
+ splice @{$proxy->record_list}, $i, 0, $record;
+ $added_record = 1;
+}
+
+sub change_version
+{
+ my $proxy = shift;
+ my $records = $proxy->record_list;
+
+ # We'll change a version after the initial version neg has taken place
+ if ($proxy->flight != 1) {
+ $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 70;
+ return;
+ }
+
+ if ($#{$records} > 1) {
+ # ... typically in ServerHelloDone
+ @{$records}[-1]->version(TLSProxy::Record::VERS_TLS_1_1);
+ }
+}
+
+sub change_outer_record_type
+{
+ my $proxy = shift;
+ my $records = $proxy->record_list;
+
+ # We'll change a record after the initial version neg has taken place
+ if ($proxy->flight != 1) {
+ $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
+ return;
+ }
+
+ # Find CCS record and change record after that
+ my $i = 0;
+ foreach my $record (@{$records}) {
+ last if $record->content_type == TLSProxy::Record::RT_CCS;
+ $i++;
+ }
+ if (defined(${$records}[++$i])) {
+ ${$records}[$i]->outer_content_type(TLSProxy::Record::RT_HANDSHAKE);
+ }
+}
+
+sub not_on_record_boundary
+{
+ my $proxy = shift;
+ my $records = $proxy->record_list;
+ my $data;
+
+ #Find server's first flight
+ if ($proxy->flight != 1) {
+ $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == 10;
+ return;
+ }
+
+ if ($boundary_test_type == DATA_AFTER_SERVER_HELLO) {
+ #Merge the ServerHello and EncryptedExtensions records into one
+ my $i = 0;
+ foreach my $record (@{$records}) {
+ if ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) {
+ $record->{sent} = 1; # pretend it's sent already
+ last;
+ }
+ $i++;
+ }
+
+ if (defined(${$records}[$i+1])) {
+ $data = ${$records}[$i]->data();
+ $data .= ${$records}[$i+1]->decrypt_data();
+ ${$records}[$i+1]->data($data);
+ ${$records}[$i+1]->len(length $data);
+
+ #Delete the old ServerHello record
+ splice @{$records}, $i, 1;
+ }
+ } elsif ($boundary_test_type == DATA_AFTER_FINISHED) {
+ return if @{$proxy->{message_list}}[-1]->{mt}
+ != TLSProxy::Message::MT_FINISHED;
+
+ my $last_record = @{$records}[-1];
+ $data = $last_record->decrypt_data;
+
+ #Add a KeyUpdate message onto the end of the Finished record
+ my $keyupdate = pack "C5",
+ 0x18, # KeyUpdate
+ 0x00, 0x00, 0x01, # Message length
+ 0x00; # Update not requested
+
+ $data .= $keyupdate;
+
+ #Add content type and tag
+ $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
+
+ #Update the record
+ $last_record->data($data);
+ $last_record->len(length $data);
+ } elsif ($boundary_test_type == DATA_AFTER_KEY_UPDATE) {
+ return if @{$proxy->{message_list}}[-1]->{mt}
+ != TLSProxy::Message::MT_FINISHED;
+
+ #KeyUpdates must end on a record boundary
+
+ my $record = TLSProxy::Record->new(
+ 1,
+ TLSProxy::Record::RT_APPLICATION_DATA,
+ TLSProxy::Record::VERS_TLS_1_2,
+ 0,
+ 0,
+ 0,
+ 0,
+ "",
+ ""
+ );
+
+ #Add two KeyUpdate messages into a single record
+ my $keyupdate = pack "C5",
+ 0x18, # KeyUpdate
+ 0x00, 0x00, 0x01, # Message length
+ 0x00; # Update not requested
+
+ $data = $keyupdate.$keyupdate;
+
+ #Add content type and tag
+ $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
+
+ $record->data($data);
+ $record->len(length $data);
+ push @{$records}, $record;
+ } else {
+ return if @{$proxy->{message_list}}[-1]->{mt}
+ != TLSProxy::Message::MT_FINISHED;
+
+ my $record = TLSProxy::Record->new(
+ 1,
+ TLSProxy::Record::RT_APPLICATION_DATA,
+ TLSProxy::Record::VERS_TLS_1_2,
+ 0,
+ 0,
+ 0,
+ 0,
+ "",
+ ""
+ );
+
+ #Add a partial KeyUpdate message into the record
+ $data = pack "C1",
+ 0x18; # KeyUpdate message type. Omit the rest of the message header
+
+ #Add content type and tag
+ $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
+
+ $record->data($data);
+ $record->len(length $data);
+ push @{$records}, $record;
+
+ if ($boundary_test_type == DATA_BETWEEN_KEY_UPDATE) {
+ #Now add an app data record
+ $record = TLSProxy::Record->new(
+ 1,
+ TLSProxy::Record::RT_APPLICATION_DATA,
+ TLSProxy::Record::VERS_TLS_1_2,
+ 0,
+ 0,
+ 0,
+ 0,
+ "",
+ ""
+ );
+
+ #Add an empty app data record (just content type and tag)
+ $data = pack("C", TLSProxy::Record::RT_APPLICATION_DATA).("\0"x16);
+
+ $record->data($data);
+ $record->len(length $data);
+ push @{$records}, $record;
+ }
+
+ #Now add the rest of the KeyUpdate message
+ $record = TLSProxy::Record->new(
+ 1,
+ TLSProxy::Record::RT_APPLICATION_DATA,
+ TLSProxy::Record::VERS_TLS_1_2,
+ 0,
+ 0,
+ 0,
+ 0,
+ "",
+ ""
+ );
+
+ #Add the last 4 bytes of the KeyUpdate record
+ $data = pack "C4",
+ 0x00, 0x00, 0x01, # Message length
+ 0x00; # Update not requested
+
+ #Add content type and tag
+ $data .= pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16);
+
+ $record->data($data);
+ $record->len(length $data);
+ push @{$records}, $record;
+
+ }
+}