10a05173cSchristos# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. 2162ae260Schristos# 3*66bae5e7Schristos# Licensed under the Apache License 2.0 (the "License"). You may not use 4162ae260Schristos# this file except in compliance with the License. You can obtain a copy 5162ae260Schristos# in the file LICENSE in the source distribution or at 6162ae260Schristos# https://www.openssl.org/source/license.html 7162ae260Schristos 8162ae260Schristosuse strict; 9162ae260Schristos 10162ae260Schristospackage TLSProxy::Message; 11162ae260Schristos 1205901b04Schristosuse TLSProxy::Alert; 1305901b04Schristos 14162ae260Schristosuse constant TLS_MESSAGE_HEADER_LENGTH => 4; 15162ae260Schristos 16162ae260Schristos#Message types 17162ae260Schristosuse constant { 18162ae260Schristos MT_HELLO_REQUEST => 0, 19162ae260Schristos MT_CLIENT_HELLO => 1, 20162ae260Schristos MT_SERVER_HELLO => 2, 21162ae260Schristos MT_NEW_SESSION_TICKET => 4, 2205901b04Schristos MT_ENCRYPTED_EXTENSIONS => 8, 23162ae260Schristos MT_CERTIFICATE => 11, 24162ae260Schristos MT_SERVER_KEY_EXCHANGE => 12, 25162ae260Schristos MT_CERTIFICATE_REQUEST => 13, 26162ae260Schristos MT_SERVER_HELLO_DONE => 14, 27162ae260Schristos MT_CERTIFICATE_VERIFY => 15, 28162ae260Schristos MT_CLIENT_KEY_EXCHANGE => 16, 29162ae260Schristos MT_FINISHED => 20, 30162ae260Schristos MT_CERTIFICATE_STATUS => 22, 31162ae260Schristos MT_NEXT_PROTO => 67 32162ae260Schristos}; 33162ae260Schristos 34162ae260Schristos#Alert levels 35162ae260Schristosuse constant { 36162ae260Schristos AL_LEVEL_WARN => 1, 37162ae260Schristos AL_LEVEL_FATAL => 2 38162ae260Schristos}; 39162ae260Schristos 40162ae260Schristos#Alert descriptions 41162ae260Schristosuse constant { 42162ae260Schristos AL_DESC_CLOSE_NOTIFY => 0, 43162ae260Schristos AL_DESC_UNEXPECTED_MESSAGE => 10, 4405901b04Schristos AL_DESC_ILLEGAL_PARAMETER => 47, 45162ae260Schristos AL_DESC_NO_RENEGOTIATION => 100 46162ae260Schristos}; 47162ae260Schristos 48162ae260Schristosmy %message_type = ( 49162ae260Schristos MT_HELLO_REQUEST, "HelloRequest", 50162ae260Schristos MT_CLIENT_HELLO, "ClientHello", 51162ae260Schristos MT_SERVER_HELLO, "ServerHello", 52162ae260Schristos MT_NEW_SESSION_TICKET, "NewSessionTicket", 5305901b04Schristos MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", 54162ae260Schristos MT_CERTIFICATE, "Certificate", 55162ae260Schristos MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange", 56162ae260Schristos MT_CERTIFICATE_REQUEST, "CertificateRequest", 57162ae260Schristos MT_SERVER_HELLO_DONE, "ServerHelloDone", 58162ae260Schristos MT_CERTIFICATE_VERIFY, "CertificateVerify", 59162ae260Schristos MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange", 60162ae260Schristos MT_FINISHED, "Finished", 61162ae260Schristos MT_CERTIFICATE_STATUS, "CertificateStatus", 62162ae260Schristos MT_NEXT_PROTO, "NextProto" 63162ae260Schristos); 64162ae260Schristos 65162ae260Schristosuse constant { 6605901b04Schristos EXT_SERVER_NAME => 0, 6705901b04Schristos EXT_MAX_FRAGMENT_LENGTH => 1, 68162ae260Schristos EXT_STATUS_REQUEST => 5, 6905901b04Schristos EXT_SUPPORTED_GROUPS => 10, 7005901b04Schristos EXT_EC_POINT_FORMATS => 11, 7105901b04Schristos EXT_SRP => 12, 7205901b04Schristos EXT_SIG_ALGS => 13, 7305901b04Schristos EXT_USE_SRTP => 14, 7405901b04Schristos EXT_ALPN => 16, 7505901b04Schristos EXT_SCT => 18, 7605901b04Schristos EXT_PADDING => 21, 77162ae260Schristos EXT_ENCRYPT_THEN_MAC => 22, 78162ae260Schristos EXT_EXTENDED_MASTER_SECRET => 23, 79162ae260Schristos EXT_SESSION_TICKET => 35, 8005901b04Schristos EXT_KEY_SHARE => 51, 8105901b04Schristos EXT_PSK => 41, 8205901b04Schristos EXT_SUPPORTED_VERSIONS => 43, 8305901b04Schristos EXT_COOKIE => 44, 8405901b04Schristos EXT_PSK_KEX_MODES => 45, 8505901b04Schristos EXT_POST_HANDSHAKE_AUTH => 49, 8605901b04Schristos EXT_SIG_ALGS_CERT => 50, 8705901b04Schristos EXT_RENEGOTIATE => 65281, 8805901b04Schristos EXT_NPN => 13172, 89fa9f2818Schristos EXT_CRYPTOPRO_BUG_EXTENSION => 0xfde8, 9005901b04Schristos EXT_UNKNOWN => 0xfffe, 9105901b04Schristos #Unknown extension that should appear last 9205901b04Schristos EXT_FORCE_LAST => 0xffff 9305901b04Schristos}; 9405901b04Schristos 9505901b04Schristos# SignatureScheme of TLS 1.3 from: 9605901b04Schristos# https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme 9705901b04Schristos# We have to manually grab the SHA224 equivalents from the old registry 9805901b04Schristosuse constant { 9905901b04Schristos SIG_ALG_RSA_PKCS1_SHA256 => 0x0401, 10005901b04Schristos SIG_ALG_RSA_PKCS1_SHA384 => 0x0501, 10105901b04Schristos SIG_ALG_RSA_PKCS1_SHA512 => 0x0601, 10205901b04Schristos SIG_ALG_ECDSA_SECP256R1_SHA256 => 0x0403, 10305901b04Schristos SIG_ALG_ECDSA_SECP384R1_SHA384 => 0x0503, 10405901b04Schristos SIG_ALG_ECDSA_SECP521R1_SHA512 => 0x0603, 10505901b04Schristos SIG_ALG_RSA_PSS_RSAE_SHA256 => 0x0804, 10605901b04Schristos SIG_ALG_RSA_PSS_RSAE_SHA384 => 0x0805, 10705901b04Schristos SIG_ALG_RSA_PSS_RSAE_SHA512 => 0x0806, 10805901b04Schristos SIG_ALG_ED25519 => 0x0807, 10905901b04Schristos SIG_ALG_ED448 => 0x0808, 11005901b04Schristos SIG_ALG_RSA_PSS_PSS_SHA256 => 0x0809, 11105901b04Schristos SIG_ALG_RSA_PSS_PSS_SHA384 => 0x080a, 11205901b04Schristos SIG_ALG_RSA_PSS_PSS_SHA512 => 0x080b, 11305901b04Schristos SIG_ALG_RSA_PKCS1_SHA1 => 0x0201, 11405901b04Schristos SIG_ALG_ECDSA_SHA1 => 0x0203, 11505901b04Schristos SIG_ALG_DSA_SHA1 => 0x0202, 11605901b04Schristos SIG_ALG_DSA_SHA256 => 0x0402, 11705901b04Schristos SIG_ALG_DSA_SHA384 => 0x0502, 11805901b04Schristos SIG_ALG_DSA_SHA512 => 0x0602, 11905901b04Schristos OSSL_SIG_ALG_RSA_PKCS1_SHA224 => 0x0301, 12005901b04Schristos OSSL_SIG_ALG_DSA_SHA224 => 0x0302, 12105901b04Schristos OSSL_SIG_ALG_ECDSA_SHA224 => 0x0303 12205901b04Schristos}; 12305901b04Schristos 12405901b04Schristosuse constant { 12505901b04Schristos CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f, 12605901b04Schristos CIPHER_DHE_RSA_AES_128_SHA => 0x0033, 12705901b04Schristos CIPHER_ADH_AES_128_SHA => 0x0034, 12805901b04Schristos CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301, 12905901b04Schristos CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302 130162ae260Schristos}; 131162ae260Schristos 132033a4089Schristosuse constant { 133033a4089Schristos CLIENT => 0, 134033a4089Schristos SERVER => 1 135033a4089Schristos}; 136033a4089Schristos 137162ae260Schristosmy $payload = ""; 138162ae260Schristosmy $messlen = -1; 139162ae260Schristosmy $mt; 140162ae260Schristosmy $startoffset = -1; 141162ae260Schristosmy $server = 0; 142162ae260Schristosmy $success = 0; 143162ae260Schristosmy $end = 0; 144162ae260Schristosmy @message_rec_list = (); 145162ae260Schristosmy @message_frag_lens = (); 146162ae260Schristosmy $ciphersuite = 0; 14705901b04Schristosmy $successondata = 0; 14805901b04Schristosmy $alert; 149162ae260Schristos 150162ae260Schristossub clear 151162ae260Schristos{ 152162ae260Schristos $payload = ""; 153162ae260Schristos $messlen = -1; 154162ae260Schristos $startoffset = -1; 155162ae260Schristos $server = 0; 156162ae260Schristos $success = 0; 157162ae260Schristos $end = 0; 15805901b04Schristos $successondata = 0; 159162ae260Schristos @message_rec_list = (); 160162ae260Schristos @message_frag_lens = (); 16105901b04Schristos $alert = undef; 162162ae260Schristos} 163162ae260Schristos 164162ae260Schristos#Class method to extract messages from a record 165162ae260Schristossub get_messages 166162ae260Schristos{ 167162ae260Schristos my $class = shift; 168162ae260Schristos my $serverin = shift; 169162ae260Schristos my $record = shift; 170162ae260Schristos my @messages = (); 171162ae260Schristos my $message; 172162ae260Schristos 173162ae260Schristos @message_frag_lens = (); 174162ae260Schristos 175162ae260Schristos if ($serverin != $server && length($payload) != 0) { 176162ae260Schristos die "Changed peer, but we still have fragment data\n"; 177162ae260Schristos } 178162ae260Schristos $server = $serverin; 179162ae260Schristos 180162ae260Schristos if ($record->content_type == TLSProxy::Record::RT_CCS) { 181162ae260Schristos if ($payload ne "") { 182162ae260Schristos #We can't handle this yet 183162ae260Schristos die "CCS received before message data complete\n"; 184162ae260Schristos } 18505901b04Schristos if (!TLSProxy::Proxy->is_tls13()) { 186162ae260Schristos if ($server) { 18705901b04Schristos TLSProxy::Record->server_encrypting(1); 188162ae260Schristos } else { 18905901b04Schristos TLSProxy::Record->client_encrypting(1); 19005901b04Schristos } 191162ae260Schristos } 192162ae260Schristos } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) { 193162ae260Schristos if ($record->len == 0 || $record->len_real == 0) { 194162ae260Schristos print " Message truncated\n"; 195162ae260Schristos } else { 196162ae260Schristos my $recoffset = 0; 197162ae260Schristos 198162ae260Schristos if (length $payload > 0) { 199162ae260Schristos #We are continuing processing a message started in a previous 200162ae260Schristos #record. Add this record to the list associated with this 201162ae260Schristos #message 202162ae260Schristos push @message_rec_list, $record; 203162ae260Schristos 204162ae260Schristos if ($messlen <= length($payload)) { 205162ae260Schristos #Shouldn't happen 206162ae260Schristos die "Internal error: invalid messlen: ".$messlen 207162ae260Schristos ." payload length:".length($payload)."\n"; 208162ae260Schristos } 209162ae260Schristos if (length($payload) + $record->decrypt_len >= $messlen) { 210162ae260Schristos #We can complete the message with this record 211162ae260Schristos $recoffset = $messlen - length($payload); 212162ae260Schristos $payload .= substr($record->decrypt_data, 0, $recoffset); 213162ae260Schristos push @message_frag_lens, $recoffset; 214162ae260Schristos $message = create_message($server, $mt, $payload, 215162ae260Schristos $startoffset); 216162ae260Schristos push @messages, $message; 217162ae260Schristos 218162ae260Schristos $payload = ""; 219162ae260Schristos } else { 220162ae260Schristos #This is just part of the total message 221162ae260Schristos $payload .= $record->decrypt_data; 222162ae260Schristos $recoffset = $record->decrypt_len; 223162ae260Schristos push @message_frag_lens, $record->decrypt_len; 224162ae260Schristos } 225162ae260Schristos print " Partial message data read: ".$recoffset." bytes\n"; 226162ae260Schristos } 227162ae260Schristos 228162ae260Schristos while ($record->decrypt_len > $recoffset) { 229162ae260Schristos #We are at the start of a new message 230162ae260Schristos if ($record->decrypt_len - $recoffset < 4) { 231162ae260Schristos #Whilst technically probably valid we can't cope with this 232162ae260Schristos die "End of record in the middle of a message header\n"; 233162ae260Schristos } 234162ae260Schristos @message_rec_list = ($record); 235162ae260Schristos my $lenhi; 236162ae260Schristos my $lenlo; 237162ae260Schristos ($mt, $lenhi, $lenlo) = unpack('CnC', 238162ae260Schristos substr($record->decrypt_data, 239162ae260Schristos $recoffset)); 240162ae260Schristos $messlen = ($lenhi << 8) | $lenlo; 241162ae260Schristos print " Message type: $message_type{$mt}\n"; 242162ae260Schristos print " Message Length: $messlen\n"; 243162ae260Schristos $startoffset = $recoffset; 244162ae260Schristos $recoffset += 4; 245162ae260Schristos $payload = ""; 246162ae260Schristos 247162ae260Schristos if ($recoffset <= $record->decrypt_len) { 248162ae260Schristos #Some payload data is present in this record 249162ae260Schristos if ($record->decrypt_len - $recoffset >= $messlen) { 250162ae260Schristos #We can complete the message with this record 251162ae260Schristos $payload .= substr($record->decrypt_data, $recoffset, 252162ae260Schristos $messlen); 253162ae260Schristos $recoffset += $messlen; 254162ae260Schristos push @message_frag_lens, $messlen; 255162ae260Schristos $message = create_message($server, $mt, $payload, 256162ae260Schristos $startoffset); 257162ae260Schristos push @messages, $message; 258162ae260Schristos 259162ae260Schristos $payload = ""; 260162ae260Schristos } else { 261162ae260Schristos #This is just part of the total message 262162ae260Schristos $payload .= substr($record->decrypt_data, $recoffset, 263162ae260Schristos $record->decrypt_len - $recoffset); 264162ae260Schristos $recoffset = $record->decrypt_len; 265162ae260Schristos push @message_frag_lens, $recoffset; 266162ae260Schristos } 267162ae260Schristos } 268162ae260Schristos } 269162ae260Schristos } 270162ae260Schristos } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) { 271162ae260Schristos print " [ENCRYPTED APPLICATION DATA]\n"; 272162ae260Schristos print " [".$record->decrypt_data."]\n"; 27305901b04Schristos 27405901b04Schristos if ($successondata) { 27505901b04Schristos $success = 1; 27605901b04Schristos $end = 1; 27705901b04Schristos } 278162ae260Schristos } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) { 279162ae260Schristos my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data); 28005901b04Schristos print " [$alertlev, $alertdesc]\n"; 281162ae260Schristos #A CloseNotify from the client indicates we have finished successfully 282162ae260Schristos #(we assume) 283162ae260Schristos if (!$end && !$server && $alertlev == AL_LEVEL_WARN 284162ae260Schristos && $alertdesc == AL_DESC_CLOSE_NOTIFY) { 285162ae260Schristos $success = 1; 286162ae260Schristos } 28705901b04Schristos #Fatal or close notify alerts end the test 28805901b04Schristos if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) { 289162ae260Schristos $end = 1; 290162ae260Schristos } 29105901b04Schristos $alert = TLSProxy::Alert->new( 29205901b04Schristos $server, 29305901b04Schristos $record->encrypted, 29405901b04Schristos $alertlev, 29505901b04Schristos $alertdesc); 29605901b04Schristos } 297162ae260Schristos 298162ae260Schristos return @messages; 299162ae260Schristos} 300162ae260Schristos 301162ae260Schristos#Function to work out which sub-class we need to create and then 302162ae260Schristos#construct it 303162ae260Schristossub create_message 304162ae260Schristos{ 305162ae260Schristos my ($server, $mt, $data, $startoffset) = @_; 306162ae260Schristos my $message; 307162ae260Schristos 308162ae260Schristos #We only support ClientHello in this version...needs to be extended for 309162ae260Schristos #others 310162ae260Schristos if ($mt == MT_CLIENT_HELLO) { 311162ae260Schristos $message = TLSProxy::ClientHello->new( 312162ae260Schristos $server, 313162ae260Schristos $data, 314162ae260Schristos [@message_rec_list], 315162ae260Schristos $startoffset, 316162ae260Schristos [@message_frag_lens] 317162ae260Schristos ); 318162ae260Schristos $message->parse(); 319162ae260Schristos } elsif ($mt == MT_SERVER_HELLO) { 320162ae260Schristos $message = TLSProxy::ServerHello->new( 321162ae260Schristos $server, 322162ae260Schristos $data, 323162ae260Schristos [@message_rec_list], 324162ae260Schristos $startoffset, 325162ae260Schristos [@message_frag_lens] 326162ae260Schristos ); 327162ae260Schristos $message->parse(); 32805901b04Schristos } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) { 32905901b04Schristos $message = TLSProxy::EncryptedExtensions->new( 33005901b04Schristos $server, 33105901b04Schristos $data, 33205901b04Schristos [@message_rec_list], 33305901b04Schristos $startoffset, 33405901b04Schristos [@message_frag_lens] 33505901b04Schristos ); 33605901b04Schristos $message->parse(); 33705901b04Schristos } elsif ($mt == MT_CERTIFICATE) { 33805901b04Schristos $message = TLSProxy::Certificate->new( 33905901b04Schristos $server, 34005901b04Schristos $data, 34105901b04Schristos [@message_rec_list], 34205901b04Schristos $startoffset, 34305901b04Schristos [@message_frag_lens] 34405901b04Schristos ); 34505901b04Schristos $message->parse(); 346033a4089Schristos } elsif ($mt == MT_CERTIFICATE_REQUEST) { 347033a4089Schristos $message = TLSProxy::CertificateRequest->new( 348033a4089Schristos $server, 349033a4089Schristos $data, 350033a4089Schristos [@message_rec_list], 351033a4089Schristos $startoffset, 352033a4089Schristos [@message_frag_lens] 353033a4089Schristos ); 354033a4089Schristos $message->parse(); 35505901b04Schristos } elsif ($mt == MT_CERTIFICATE_VERIFY) { 35605901b04Schristos $message = TLSProxy::CertificateVerify->new( 35705901b04Schristos $server, 35805901b04Schristos $data, 35905901b04Schristos [@message_rec_list], 36005901b04Schristos $startoffset, 36105901b04Schristos [@message_frag_lens] 36205901b04Schristos ); 36305901b04Schristos $message->parse(); 364162ae260Schristos } elsif ($mt == MT_SERVER_KEY_EXCHANGE) { 365162ae260Schristos $message = TLSProxy::ServerKeyExchange->new( 366162ae260Schristos $server, 367162ae260Schristos $data, 368162ae260Schristos [@message_rec_list], 369162ae260Schristos $startoffset, 370162ae260Schristos [@message_frag_lens] 371162ae260Schristos ); 372162ae260Schristos $message->parse(); 373162ae260Schristos } elsif ($mt == MT_NEW_SESSION_TICKET) { 374162ae260Schristos $message = TLSProxy::NewSessionTicket->new( 375162ae260Schristos $server, 376162ae260Schristos $data, 377162ae260Schristos [@message_rec_list], 378162ae260Schristos $startoffset, 379162ae260Schristos [@message_frag_lens] 380162ae260Schristos ); 381162ae260Schristos $message->parse(); 382162ae260Schristos } else { 383162ae260Schristos #Unknown message type 384162ae260Schristos $message = TLSProxy::Message->new( 385162ae260Schristos $server, 386162ae260Schristos $mt, 387162ae260Schristos $data, 388162ae260Schristos [@message_rec_list], 389162ae260Schristos $startoffset, 390162ae260Schristos [@message_frag_lens] 391162ae260Schristos ); 392162ae260Schristos } 393162ae260Schristos 394162ae260Schristos return $message; 395162ae260Schristos} 396162ae260Schristos 397162ae260Schristossub end 398162ae260Schristos{ 399162ae260Schristos my $class = shift; 400162ae260Schristos return $end; 401162ae260Schristos} 402162ae260Schristossub success 403162ae260Schristos{ 404162ae260Schristos my $class = shift; 405162ae260Schristos return $success; 406162ae260Schristos} 407162ae260Schristossub fail 408162ae260Schristos{ 409162ae260Schristos my $class = shift; 410162ae260Schristos return !$success && $end; 411162ae260Schristos} 41205901b04Schristos 41305901b04Schristossub alert 41405901b04Schristos{ 41505901b04Schristos return $alert; 41605901b04Schristos} 41705901b04Schristos 418162ae260Schristossub new 419162ae260Schristos{ 420162ae260Schristos my $class = shift; 421162ae260Schristos my ($server, 422162ae260Schristos $mt, 423162ae260Schristos $data, 424162ae260Schristos $records, 425162ae260Schristos $startoffset, 426162ae260Schristos $message_frag_lens) = @_; 427162ae260Schristos 428162ae260Schristos my $self = { 429162ae260Schristos server => $server, 430162ae260Schristos data => $data, 431162ae260Schristos records => $records, 432162ae260Schristos mt => $mt, 433162ae260Schristos startoffset => $startoffset, 434fa9f2818Schristos message_frag_lens => $message_frag_lens, 435fa9f2818Schristos dupext => -1 436162ae260Schristos }; 437162ae260Schristos 438162ae260Schristos return bless $self, $class; 439162ae260Schristos} 440162ae260Schristos 441162ae260Schristossub ciphersuite 442162ae260Schristos{ 443162ae260Schristos my $class = shift; 444162ae260Schristos if (@_) { 445162ae260Schristos $ciphersuite = shift; 446162ae260Schristos } 447162ae260Schristos return $ciphersuite; 448162ae260Schristos} 449162ae260Schristos 450162ae260Schristos#Update all the underlying records with the modified data from this message 4510a05173cSchristos#Note: Only supports TLSv1.3 and ETM encryption 452162ae260Schristossub repack 453162ae260Schristos{ 454162ae260Schristos my $self = shift; 455162ae260Schristos my $msgdata; 456162ae260Schristos 457162ae260Schristos my $numrecs = $#{$self->records}; 458162ae260Schristos 459162ae260Schristos $self->set_message_contents(); 460162ae260Schristos 461162ae260Schristos my $lenhi; 462162ae260Schristos my $lenlo; 463162ae260Schristos 464162ae260Schristos $lenlo = length($self->data) & 0xff; 465162ae260Schristos $lenhi = length($self->data) >> 8; 466162ae260Schristos $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; 467162ae260Schristos 468162ae260Schristos if ($numrecs == 0) { 469162ae260Schristos #The message is fully contained within one record 470162ae260Schristos my ($rec) = @{$self->records}; 471162ae260Schristos my $recdata = $rec->decrypt_data; 472162ae260Schristos 473162ae260Schristos my $old_length; 474162ae260Schristos 475162ae260Schristos # We use empty message_frag_lens to indicates that pre-repacking, 476162ae260Schristos # the message wasn't present. The first fragment length doesn't include 477162ae260Schristos # the TLS header, so we need to check and compute the right length. 478162ae260Schristos if (@{$self->message_frag_lens}) { 479162ae260Schristos $old_length = ${$self->message_frag_lens}[0] + 480162ae260Schristos TLS_MESSAGE_HEADER_LENGTH; 481162ae260Schristos } else { 482162ae260Schristos $old_length = 0; 483162ae260Schristos } 484162ae260Schristos 485162ae260Schristos my $prefix = substr($recdata, 0, $self->startoffset); 486162ae260Schristos my $suffix = substr($recdata, $self->startoffset + $old_length); 487162ae260Schristos 488162ae260Schristos $rec->decrypt_data($prefix.($msgdata).($suffix)); 489162ae260Schristos # TODO(openssl-team): don't keep explicit lengths. 490162ae260Schristos # (If a length override is ever needed to construct invalid packets, 491162ae260Schristos # use an explicit override field instead.) 492162ae260Schristos $rec->decrypt_len(length($rec->decrypt_data)); 4930a05173cSchristos # Only support re-encryption for TLSv1.3 and ETM. 4940a05173cSchristos if ($rec->encrypted()) { 4950a05173cSchristos if (TLSProxy::Proxy->is_tls13()) { 49605901b04Schristos #Add content type (1 byte) and 16 tag bytes 49705901b04Schristos $rec->data($rec->decrypt_data 49805901b04Schristos .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); 4990a05173cSchristos } elsif ($rec->etm()) { 5000a05173cSchristos my $data = $rec->decrypt_data; 5010a05173cSchristos #Add padding 5020a05173cSchristos my $padval = length($data) % 16; 5030a05173cSchristos $padval = 15 - $padval; 5040a05173cSchristos for (0..$padval) { 5050a05173cSchristos $data .= pack("C", $padval); 5060a05173cSchristos } 5070a05173cSchristos 5080a05173cSchristos #Add MAC. Assumed to be 20 bytes 5090a05173cSchristos foreach my $macval (0..19) { 5100a05173cSchristos $data .= pack("C", $macval); 5110a05173cSchristos } 5120a05173cSchristos 5130a05173cSchristos if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) { 5140a05173cSchristos #Explicit IV 5150a05173cSchristos $data = ("\0"x16).$data; 5160a05173cSchristos } 5170a05173cSchristos $rec->data($data); 5180a05173cSchristos } else { 5190a05173cSchristos die "Unsupported encryption: No ETM"; 5200a05173cSchristos } 52105901b04Schristos } else { 522162ae260Schristos $rec->data($rec->decrypt_data); 52305901b04Schristos } 5240a05173cSchristos $rec->len(length($rec->data)); 525162ae260Schristos 526162ae260Schristos #Update the fragment len in case we changed it above 527162ae260Schristos ${$self->message_frag_lens}[0] = length($msgdata) 528162ae260Schristos - TLS_MESSAGE_HEADER_LENGTH; 529162ae260Schristos return; 530162ae260Schristos } 531162ae260Schristos 532162ae260Schristos #Note we don't currently support changing a fragmented message length 533162ae260Schristos my $recctr = 0; 534162ae260Schristos my $datadone = 0; 535162ae260Schristos foreach my $rec (@{$self->records}) { 536162ae260Schristos my $recdata = $rec->decrypt_data; 537162ae260Schristos if ($recctr == 0) { 538162ae260Schristos #This is the first record 539162ae260Schristos my $remainlen = length($recdata) - $self->startoffset; 540162ae260Schristos $rec->data(substr($recdata, 0, $self->startoffset) 541162ae260Schristos .substr(($msgdata), 0, $remainlen)); 542162ae260Schristos $datadone += $remainlen; 543162ae260Schristos } elsif ($recctr + 1 == $numrecs) { 544162ae260Schristos #This is the last record 545162ae260Schristos $rec->data(substr($msgdata, $datadone)); 546162ae260Schristos } else { 547162ae260Schristos #This is a middle record 548162ae260Schristos $rec->data(substr($msgdata, $datadone, length($rec->data))); 549162ae260Schristos $datadone += length($rec->data); 550162ae260Schristos } 551162ae260Schristos $recctr++; 552162ae260Schristos } 553162ae260Schristos} 554162ae260Schristos 555162ae260Schristos#To be overridden by sub-classes 556162ae260Schristossub set_message_contents 557162ae260Schristos{ 558162ae260Schristos} 559162ae260Schristos 560162ae260Schristos#Read only accessors 561162ae260Schristossub server 562162ae260Schristos{ 563162ae260Schristos my $self = shift; 564162ae260Schristos return $self->{server}; 565162ae260Schristos} 566162ae260Schristos 567162ae260Schristos#Read/write accessors 568162ae260Schristossub mt 569162ae260Schristos{ 570162ae260Schristos my $self = shift; 571162ae260Schristos if (@_) { 572162ae260Schristos $self->{mt} = shift; 573162ae260Schristos } 574162ae260Schristos return $self->{mt}; 575162ae260Schristos} 576162ae260Schristossub data 577162ae260Schristos{ 578162ae260Schristos my $self = shift; 579162ae260Schristos if (@_) { 580162ae260Schristos $self->{data} = shift; 581162ae260Schristos } 582162ae260Schristos return $self->{data}; 583162ae260Schristos} 584162ae260Schristossub records 585162ae260Schristos{ 586162ae260Schristos my $self = shift; 587162ae260Schristos if (@_) { 588162ae260Schristos $self->{records} = shift; 589162ae260Schristos } 590162ae260Schristos return $self->{records}; 591162ae260Schristos} 592162ae260Schristossub startoffset 593162ae260Schristos{ 594162ae260Schristos my $self = shift; 595162ae260Schristos if (@_) { 596162ae260Schristos $self->{startoffset} = shift; 597162ae260Schristos } 598162ae260Schristos return $self->{startoffset}; 599162ae260Schristos} 600162ae260Schristossub message_frag_lens 601162ae260Schristos{ 602162ae260Schristos my $self = shift; 603162ae260Schristos if (@_) { 604162ae260Schristos $self->{message_frag_lens} = shift; 605162ae260Schristos } 606162ae260Schristos return $self->{message_frag_lens}; 607162ae260Schristos} 608162ae260Schristossub encoded_length 609162ae260Schristos{ 610162ae260Schristos my $self = shift; 611162ae260Schristos return TLS_MESSAGE_HEADER_LENGTH + length($self->data); 612162ae260Schristos} 613fa9f2818Schristossub dupext 614fa9f2818Schristos{ 615fa9f2818Schristos my $self = shift; 616fa9f2818Schristos if (@_) { 617fa9f2818Schristos $self->{dupext} = shift; 618fa9f2818Schristos } 619fa9f2818Schristos return $self->{dupext}; 620fa9f2818Schristos} 62105901b04Schristossub successondata 62205901b04Schristos{ 62305901b04Schristos my $class = shift; 62405901b04Schristos if (@_) { 62505901b04Schristos $successondata = shift; 62605901b04Schristos } 62705901b04Schristos return $successondata; 62805901b04Schristos} 629162ae260Schristos1; 630