1*97e3c585Schristos# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. 253060421Schristos# 3b0d17251Schristos# Licensed under the Apache License 2.0 (the "License"). You may not use 453060421Schristos# this file except in compliance with the License. You can obtain a copy 553060421Schristos# in the file LICENSE in the source distribution or at 653060421Schristos# https://www.openssl.org/source/license.html 753060421Schristos 853060421Schristosuse strict; 953060421Schristos 1053060421Schristospackage TLSProxy::Message; 1153060421Schristos 1213d40330Schristosuse TLSProxy::Alert; 1313d40330Schristos 1453060421Schristosuse constant TLS_MESSAGE_HEADER_LENGTH => 4; 1553060421Schristos 1653060421Schristos#Message types 1753060421Schristosuse constant { 1853060421Schristos MT_HELLO_REQUEST => 0, 1953060421Schristos MT_CLIENT_HELLO => 1, 2053060421Schristos MT_SERVER_HELLO => 2, 2153060421Schristos MT_NEW_SESSION_TICKET => 4, 2213d40330Schristos MT_ENCRYPTED_EXTENSIONS => 8, 2353060421Schristos MT_CERTIFICATE => 11, 2453060421Schristos MT_SERVER_KEY_EXCHANGE => 12, 2553060421Schristos MT_CERTIFICATE_REQUEST => 13, 2653060421Schristos MT_SERVER_HELLO_DONE => 14, 2753060421Schristos MT_CERTIFICATE_VERIFY => 15, 2853060421Schristos MT_CLIENT_KEY_EXCHANGE => 16, 2953060421Schristos MT_FINISHED => 20, 3053060421Schristos MT_CERTIFICATE_STATUS => 22, 3153060421Schristos MT_NEXT_PROTO => 67 3253060421Schristos}; 3353060421Schristos 3453060421Schristos#Alert levels 3553060421Schristosuse constant { 3653060421Schristos AL_LEVEL_WARN => 1, 3753060421Schristos AL_LEVEL_FATAL => 2 3853060421Schristos}; 3953060421Schristos 4053060421Schristos#Alert descriptions 4153060421Schristosuse constant { 4253060421Schristos AL_DESC_CLOSE_NOTIFY => 0, 4353060421Schristos AL_DESC_UNEXPECTED_MESSAGE => 10, 4413d40330Schristos AL_DESC_ILLEGAL_PARAMETER => 47, 4553060421Schristos AL_DESC_NO_RENEGOTIATION => 100 4653060421Schristos}; 4753060421Schristos 4853060421Schristosmy %message_type = ( 4953060421Schristos MT_HELLO_REQUEST, "HelloRequest", 5053060421Schristos MT_CLIENT_HELLO, "ClientHello", 5153060421Schristos MT_SERVER_HELLO, "ServerHello", 5253060421Schristos MT_NEW_SESSION_TICKET, "NewSessionTicket", 5313d40330Schristos MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", 5453060421Schristos MT_CERTIFICATE, "Certificate", 5553060421Schristos MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange", 5653060421Schristos MT_CERTIFICATE_REQUEST, "CertificateRequest", 5753060421Schristos MT_SERVER_HELLO_DONE, "ServerHelloDone", 5853060421Schristos MT_CERTIFICATE_VERIFY, "CertificateVerify", 5953060421Schristos MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange", 6053060421Schristos MT_FINISHED, "Finished", 6153060421Schristos MT_CERTIFICATE_STATUS, "CertificateStatus", 6253060421Schristos MT_NEXT_PROTO, "NextProto" 6353060421Schristos); 6453060421Schristos 6553060421Schristosuse constant { 6613d40330Schristos EXT_SERVER_NAME => 0, 6713d40330Schristos EXT_MAX_FRAGMENT_LENGTH => 1, 6853060421Schristos EXT_STATUS_REQUEST => 5, 6913d40330Schristos EXT_SUPPORTED_GROUPS => 10, 7013d40330Schristos EXT_EC_POINT_FORMATS => 11, 7113d40330Schristos EXT_SRP => 12, 7213d40330Schristos EXT_SIG_ALGS => 13, 7313d40330Schristos EXT_USE_SRTP => 14, 7413d40330Schristos EXT_ALPN => 16, 7513d40330Schristos EXT_SCT => 18, 7613d40330Schristos EXT_PADDING => 21, 7753060421Schristos EXT_ENCRYPT_THEN_MAC => 22, 7853060421Schristos EXT_EXTENDED_MASTER_SECRET => 23, 7953060421Schristos EXT_SESSION_TICKET => 35, 8013d40330Schristos EXT_KEY_SHARE => 51, 8113d40330Schristos EXT_PSK => 41, 8213d40330Schristos EXT_SUPPORTED_VERSIONS => 43, 8313d40330Schristos EXT_COOKIE => 44, 8413d40330Schristos EXT_PSK_KEX_MODES => 45, 8513d40330Schristos EXT_POST_HANDSHAKE_AUTH => 49, 8613d40330Schristos EXT_SIG_ALGS_CERT => 50, 8713d40330Schristos EXT_RENEGOTIATE => 65281, 8813d40330Schristos EXT_NPN => 13172, 89b88c74d5Schristos EXT_CRYPTOPRO_BUG_EXTENSION => 0xfde8, 9013d40330Schristos EXT_UNKNOWN => 0xfffe, 9113d40330Schristos #Unknown extension that should appear last 9213d40330Schristos EXT_FORCE_LAST => 0xffff 9313d40330Schristos}; 9413d40330Schristos 9513d40330Schristos# SignatureScheme of TLS 1.3 from: 9613d40330Schristos# https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme 9713d40330Schristos# We have to manually grab the SHA224 equivalents from the old registry 9813d40330Schristosuse constant { 9913d40330Schristos SIG_ALG_RSA_PKCS1_SHA256 => 0x0401, 10013d40330Schristos SIG_ALG_RSA_PKCS1_SHA384 => 0x0501, 10113d40330Schristos SIG_ALG_RSA_PKCS1_SHA512 => 0x0601, 10213d40330Schristos SIG_ALG_ECDSA_SECP256R1_SHA256 => 0x0403, 10313d40330Schristos SIG_ALG_ECDSA_SECP384R1_SHA384 => 0x0503, 10413d40330Schristos SIG_ALG_ECDSA_SECP521R1_SHA512 => 0x0603, 10513d40330Schristos SIG_ALG_RSA_PSS_RSAE_SHA256 => 0x0804, 10613d40330Schristos SIG_ALG_RSA_PSS_RSAE_SHA384 => 0x0805, 10713d40330Schristos SIG_ALG_RSA_PSS_RSAE_SHA512 => 0x0806, 10813d40330Schristos SIG_ALG_ED25519 => 0x0807, 10913d40330Schristos SIG_ALG_ED448 => 0x0808, 11013d40330Schristos SIG_ALG_RSA_PSS_PSS_SHA256 => 0x0809, 11113d40330Schristos SIG_ALG_RSA_PSS_PSS_SHA384 => 0x080a, 11213d40330Schristos SIG_ALG_RSA_PSS_PSS_SHA512 => 0x080b, 11313d40330Schristos SIG_ALG_RSA_PKCS1_SHA1 => 0x0201, 11413d40330Schristos SIG_ALG_ECDSA_SHA1 => 0x0203, 11513d40330Schristos SIG_ALG_DSA_SHA1 => 0x0202, 11613d40330Schristos SIG_ALG_DSA_SHA256 => 0x0402, 11713d40330Schristos SIG_ALG_DSA_SHA384 => 0x0502, 11813d40330Schristos SIG_ALG_DSA_SHA512 => 0x0602, 11913d40330Schristos OSSL_SIG_ALG_RSA_PKCS1_SHA224 => 0x0301, 12013d40330Schristos OSSL_SIG_ALG_DSA_SHA224 => 0x0302, 12113d40330Schristos OSSL_SIG_ALG_ECDSA_SHA224 => 0x0303 12213d40330Schristos}; 12313d40330Schristos 12413d40330Schristosuse constant { 12513d40330Schristos CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f, 12613d40330Schristos CIPHER_DHE_RSA_AES_128_SHA => 0x0033, 12713d40330Schristos CIPHER_ADH_AES_128_SHA => 0x0034, 12813d40330Schristos CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301, 12913d40330Schristos CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302 13053060421Schristos}; 13153060421Schristos 1324ce06407Schristosuse constant { 1334ce06407Schristos CLIENT => 0, 1344ce06407Schristos SERVER => 1 1354ce06407Schristos}; 1364ce06407Schristos 13753060421Schristosmy $payload = ""; 13853060421Schristosmy $messlen = -1; 13953060421Schristosmy $mt; 14053060421Schristosmy $startoffset = -1; 14153060421Schristosmy $server = 0; 14253060421Schristosmy $success = 0; 14353060421Schristosmy $end = 0; 14453060421Schristosmy @message_rec_list = (); 14553060421Schristosmy @message_frag_lens = (); 14653060421Schristosmy $ciphersuite = 0; 14713d40330Schristosmy $successondata = 0; 14813d40330Schristosmy $alert; 14953060421Schristos 15053060421Schristossub clear 15153060421Schristos{ 15253060421Schristos $payload = ""; 15353060421Schristos $messlen = -1; 15453060421Schristos $startoffset = -1; 15553060421Schristos $server = 0; 15653060421Schristos $success = 0; 15753060421Schristos $end = 0; 15813d40330Schristos $successondata = 0; 15953060421Schristos @message_rec_list = (); 16053060421Schristos @message_frag_lens = (); 16113d40330Schristos $alert = undef; 16253060421Schristos} 16353060421Schristos 16453060421Schristos#Class method to extract messages from a record 16553060421Schristossub get_messages 16653060421Schristos{ 16753060421Schristos my $class = shift; 16853060421Schristos my $serverin = shift; 16953060421Schristos my $record = shift; 17053060421Schristos my @messages = (); 17153060421Schristos my $message; 17253060421Schristos 17353060421Schristos @message_frag_lens = (); 17453060421Schristos 17553060421Schristos if ($serverin != $server && length($payload) != 0) { 17653060421Schristos die "Changed peer, but we still have fragment data\n"; 17753060421Schristos } 17853060421Schristos $server = $serverin; 17953060421Schristos 18053060421Schristos if ($record->content_type == TLSProxy::Record::RT_CCS) { 18153060421Schristos if ($payload ne "") { 18253060421Schristos #We can't handle this yet 18353060421Schristos die "CCS received before message data complete\n"; 18453060421Schristos } 18513d40330Schristos if (!TLSProxy::Proxy->is_tls13()) { 18653060421Schristos if ($server) { 18713d40330Schristos TLSProxy::Record->server_encrypting(1); 18853060421Schristos } else { 18913d40330Schristos TLSProxy::Record->client_encrypting(1); 19013d40330Schristos } 19153060421Schristos } 19253060421Schristos } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) { 19353060421Schristos if ($record->len == 0 || $record->len_real == 0) { 19453060421Schristos print " Message truncated\n"; 19553060421Schristos } else { 19653060421Schristos my $recoffset = 0; 19753060421Schristos 19853060421Schristos if (length $payload > 0) { 19953060421Schristos #We are continuing processing a message started in a previous 20053060421Schristos #record. Add this record to the list associated with this 20153060421Schristos #message 20253060421Schristos push @message_rec_list, $record; 20353060421Schristos 20453060421Schristos if ($messlen <= length($payload)) { 20553060421Schristos #Shouldn't happen 20653060421Schristos die "Internal error: invalid messlen: ".$messlen 20753060421Schristos ." payload length:".length($payload)."\n"; 20853060421Schristos } 20953060421Schristos if (length($payload) + $record->decrypt_len >= $messlen) { 21053060421Schristos #We can complete the message with this record 21153060421Schristos $recoffset = $messlen - length($payload); 21253060421Schristos $payload .= substr($record->decrypt_data, 0, $recoffset); 21353060421Schristos push @message_frag_lens, $recoffset; 21453060421Schristos $message = create_message($server, $mt, $payload, 21553060421Schristos $startoffset); 21653060421Schristos push @messages, $message; 21753060421Schristos 21853060421Schristos $payload = ""; 21953060421Schristos } else { 22053060421Schristos #This is just part of the total message 22153060421Schristos $payload .= $record->decrypt_data; 22253060421Schristos $recoffset = $record->decrypt_len; 22353060421Schristos push @message_frag_lens, $record->decrypt_len; 22453060421Schristos } 22553060421Schristos print " Partial message data read: ".$recoffset." bytes\n"; 22653060421Schristos } 22753060421Schristos 22853060421Schristos while ($record->decrypt_len > $recoffset) { 22953060421Schristos #We are at the start of a new message 23053060421Schristos if ($record->decrypt_len - $recoffset < 4) { 23153060421Schristos #Whilst technically probably valid we can't cope with this 23253060421Schristos die "End of record in the middle of a message header\n"; 23353060421Schristos } 23453060421Schristos @message_rec_list = ($record); 23553060421Schristos my $lenhi; 23653060421Schristos my $lenlo; 23753060421Schristos ($mt, $lenhi, $lenlo) = unpack('CnC', 23853060421Schristos substr($record->decrypt_data, 23953060421Schristos $recoffset)); 24053060421Schristos $messlen = ($lenhi << 8) | $lenlo; 24153060421Schristos print " Message type: $message_type{$mt}\n"; 24253060421Schristos print " Message Length: $messlen\n"; 24353060421Schristos $startoffset = $recoffset; 24453060421Schristos $recoffset += 4; 24553060421Schristos $payload = ""; 24653060421Schristos 24753060421Schristos if ($recoffset <= $record->decrypt_len) { 24853060421Schristos #Some payload data is present in this record 24953060421Schristos if ($record->decrypt_len - $recoffset >= $messlen) { 25053060421Schristos #We can complete the message with this record 25153060421Schristos $payload .= substr($record->decrypt_data, $recoffset, 25253060421Schristos $messlen); 25353060421Schristos $recoffset += $messlen; 25453060421Schristos push @message_frag_lens, $messlen; 25553060421Schristos $message = create_message($server, $mt, $payload, 25653060421Schristos $startoffset); 25753060421Schristos push @messages, $message; 25853060421Schristos 25953060421Schristos $payload = ""; 26053060421Schristos } else { 26153060421Schristos #This is just part of the total message 26253060421Schristos $payload .= substr($record->decrypt_data, $recoffset, 26353060421Schristos $record->decrypt_len - $recoffset); 26453060421Schristos $recoffset = $record->decrypt_len; 26553060421Schristos push @message_frag_lens, $recoffset; 26653060421Schristos } 26753060421Schristos } 26853060421Schristos } 26953060421Schristos } 27053060421Schristos } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) { 27153060421Schristos print " [ENCRYPTED APPLICATION DATA]\n"; 27253060421Schristos print " [".$record->decrypt_data."]\n"; 27313d40330Schristos 27413d40330Schristos if ($successondata) { 27513d40330Schristos $success = 1; 27613d40330Schristos $end = 1; 27713d40330Schristos } 27853060421Schristos } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) { 27953060421Schristos my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data); 28013d40330Schristos print " [$alertlev, $alertdesc]\n"; 28153060421Schristos #A CloseNotify from the client indicates we have finished successfully 28253060421Schristos #(we assume) 28353060421Schristos if (!$end && !$server && $alertlev == AL_LEVEL_WARN 28453060421Schristos && $alertdesc == AL_DESC_CLOSE_NOTIFY) { 28553060421Schristos $success = 1; 28653060421Schristos } 28713d40330Schristos #Fatal or close notify alerts end the test 28813d40330Schristos if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) { 28953060421Schristos $end = 1; 29053060421Schristos } 29113d40330Schristos $alert = TLSProxy::Alert->new( 29213d40330Schristos $server, 29313d40330Schristos $record->encrypted, 29413d40330Schristos $alertlev, 29513d40330Schristos $alertdesc); 29613d40330Schristos } 29753060421Schristos 29853060421Schristos return @messages; 29953060421Schristos} 30053060421Schristos 30153060421Schristos#Function to work out which sub-class we need to create and then 30253060421Schristos#construct it 30353060421Schristossub create_message 30453060421Schristos{ 30553060421Schristos my ($server, $mt, $data, $startoffset) = @_; 30653060421Schristos my $message; 30753060421Schristos 30853060421Schristos #We only support ClientHello in this version...needs to be extended for 30953060421Schristos #others 31053060421Schristos if ($mt == MT_CLIENT_HELLO) { 31153060421Schristos $message = TLSProxy::ClientHello->new( 31253060421Schristos $server, 31353060421Schristos $data, 31453060421Schristos [@message_rec_list], 31553060421Schristos $startoffset, 31653060421Schristos [@message_frag_lens] 31753060421Schristos ); 31853060421Schristos $message->parse(); 31953060421Schristos } elsif ($mt == MT_SERVER_HELLO) { 32053060421Schristos $message = TLSProxy::ServerHello->new( 32153060421Schristos $server, 32253060421Schristos $data, 32353060421Schristos [@message_rec_list], 32453060421Schristos $startoffset, 32553060421Schristos [@message_frag_lens] 32653060421Schristos ); 32753060421Schristos $message->parse(); 32813d40330Schristos } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) { 32913d40330Schristos $message = TLSProxy::EncryptedExtensions->new( 33013d40330Schristos $server, 33113d40330Schristos $data, 33213d40330Schristos [@message_rec_list], 33313d40330Schristos $startoffset, 33413d40330Schristos [@message_frag_lens] 33513d40330Schristos ); 33613d40330Schristos $message->parse(); 33713d40330Schristos } elsif ($mt == MT_CERTIFICATE) { 33813d40330Schristos $message = TLSProxy::Certificate->new( 33913d40330Schristos $server, 34013d40330Schristos $data, 34113d40330Schristos [@message_rec_list], 34213d40330Schristos $startoffset, 34313d40330Schristos [@message_frag_lens] 34413d40330Schristos ); 34513d40330Schristos $message->parse(); 3464ce06407Schristos } elsif ($mt == MT_CERTIFICATE_REQUEST) { 3474ce06407Schristos $message = TLSProxy::CertificateRequest->new( 3484ce06407Schristos $server, 3494ce06407Schristos $data, 3504ce06407Schristos [@message_rec_list], 3514ce06407Schristos $startoffset, 3524ce06407Schristos [@message_frag_lens] 3534ce06407Schristos ); 3544ce06407Schristos $message->parse(); 35513d40330Schristos } elsif ($mt == MT_CERTIFICATE_VERIFY) { 35613d40330Schristos $message = TLSProxy::CertificateVerify->new( 35713d40330Schristos $server, 35813d40330Schristos $data, 35913d40330Schristos [@message_rec_list], 36013d40330Schristos $startoffset, 36113d40330Schristos [@message_frag_lens] 36213d40330Schristos ); 36313d40330Schristos $message->parse(); 36453060421Schristos } elsif ($mt == MT_SERVER_KEY_EXCHANGE) { 36553060421Schristos $message = TLSProxy::ServerKeyExchange->new( 36653060421Schristos $server, 36753060421Schristos $data, 36853060421Schristos [@message_rec_list], 36953060421Schristos $startoffset, 37053060421Schristos [@message_frag_lens] 37153060421Schristos ); 37253060421Schristos $message->parse(); 37353060421Schristos } elsif ($mt == MT_NEW_SESSION_TICKET) { 37453060421Schristos $message = TLSProxy::NewSessionTicket->new( 37553060421Schristos $server, 37653060421Schristos $data, 37753060421Schristos [@message_rec_list], 37853060421Schristos $startoffset, 37953060421Schristos [@message_frag_lens] 38053060421Schristos ); 38153060421Schristos $message->parse(); 382*97e3c585Schristos } elsif ($mt == MT_NEXT_PROTO) { 383*97e3c585Schristos $message = TLSProxy::NextProto->new( 384*97e3c585Schristos $server, 385*97e3c585Schristos $data, 386*97e3c585Schristos [@message_rec_list], 387*97e3c585Schristos $startoffset, 388*97e3c585Schristos [@message_frag_lens] 389*97e3c585Schristos ); 390*97e3c585Schristos $message->parse(); 39153060421Schristos } else { 39253060421Schristos #Unknown message type 39353060421Schristos $message = TLSProxy::Message->new( 39453060421Schristos $server, 39553060421Schristos $mt, 39653060421Schristos $data, 39753060421Schristos [@message_rec_list], 39853060421Schristos $startoffset, 39953060421Schristos [@message_frag_lens] 40053060421Schristos ); 40153060421Schristos } 40253060421Schristos 40353060421Schristos return $message; 40453060421Schristos} 40553060421Schristos 40653060421Schristossub end 40753060421Schristos{ 40853060421Schristos my $class = shift; 40953060421Schristos return $end; 41053060421Schristos} 41153060421Schristossub success 41253060421Schristos{ 41353060421Schristos my $class = shift; 41453060421Schristos return $success; 41553060421Schristos} 41653060421Schristossub fail 41753060421Schristos{ 41853060421Schristos my $class = shift; 41953060421Schristos return !$success && $end; 42053060421Schristos} 42113d40330Schristos 42213d40330Schristossub alert 42313d40330Schristos{ 42413d40330Schristos return $alert; 42513d40330Schristos} 42613d40330Schristos 42753060421Schristossub new 42853060421Schristos{ 42953060421Schristos my $class = shift; 43053060421Schristos my ($server, 43153060421Schristos $mt, 43253060421Schristos $data, 43353060421Schristos $records, 43453060421Schristos $startoffset, 43553060421Schristos $message_frag_lens) = @_; 43653060421Schristos 43753060421Schristos my $self = { 43853060421Schristos server => $server, 43953060421Schristos data => $data, 44053060421Schristos records => $records, 44153060421Schristos mt => $mt, 44253060421Schristos startoffset => $startoffset, 443b88c74d5Schristos message_frag_lens => $message_frag_lens, 444b88c74d5Schristos dupext => -1 44553060421Schristos }; 44653060421Schristos 44753060421Schristos return bless $self, $class; 44853060421Schristos} 44953060421Schristos 45053060421Schristossub ciphersuite 45153060421Schristos{ 45253060421Schristos my $class = shift; 45353060421Schristos if (@_) { 45453060421Schristos $ciphersuite = shift; 45553060421Schristos } 45653060421Schristos return $ciphersuite; 45753060421Schristos} 45853060421Schristos 45953060421Schristos#Update all the underlying records with the modified data from this message 460c161c69cSchristos#Note: Only supports TLSv1.3 and ETM encryption 46153060421Schristossub repack 46253060421Schristos{ 46353060421Schristos my $self = shift; 46453060421Schristos my $msgdata; 46553060421Schristos 46653060421Schristos my $numrecs = $#{$self->records}; 46753060421Schristos 46853060421Schristos $self->set_message_contents(); 46953060421Schristos 47053060421Schristos my $lenhi; 47153060421Schristos my $lenlo; 47253060421Schristos 47353060421Schristos $lenlo = length($self->data) & 0xff; 47453060421Schristos $lenhi = length($self->data) >> 8; 47553060421Schristos $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; 47653060421Schristos 47753060421Schristos if ($numrecs == 0) { 47853060421Schristos #The message is fully contained within one record 47953060421Schristos my ($rec) = @{$self->records}; 48053060421Schristos my $recdata = $rec->decrypt_data; 48153060421Schristos 48253060421Schristos my $old_length; 48353060421Schristos 48453060421Schristos # We use empty message_frag_lens to indicates that pre-repacking, 48553060421Schristos # the message wasn't present. The first fragment length doesn't include 48653060421Schristos # the TLS header, so we need to check and compute the right length. 48753060421Schristos if (@{$self->message_frag_lens}) { 48853060421Schristos $old_length = ${$self->message_frag_lens}[0] + 48953060421Schristos TLS_MESSAGE_HEADER_LENGTH; 49053060421Schristos } else { 49153060421Schristos $old_length = 0; 49253060421Schristos } 49353060421Schristos 49453060421Schristos my $prefix = substr($recdata, 0, $self->startoffset); 49553060421Schristos my $suffix = substr($recdata, $self->startoffset + $old_length); 49653060421Schristos 49753060421Schristos $rec->decrypt_data($prefix.($msgdata).($suffix)); 49853060421Schristos # TODO(openssl-team): don't keep explicit lengths. 49953060421Schristos # (If a length override is ever needed to construct invalid packets, 50053060421Schristos # use an explicit override field instead.) 50153060421Schristos $rec->decrypt_len(length($rec->decrypt_data)); 502c161c69cSchristos # Only support re-encryption for TLSv1.3 and ETM. 503c161c69cSchristos if ($rec->encrypted()) { 504c161c69cSchristos if (TLSProxy::Proxy->is_tls13()) { 50513d40330Schristos #Add content type (1 byte) and 16 tag bytes 50613d40330Schristos $rec->data($rec->decrypt_data 50713d40330Schristos .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); 508c161c69cSchristos } elsif ($rec->etm()) { 509c161c69cSchristos my $data = $rec->decrypt_data; 510c161c69cSchristos #Add padding 511c161c69cSchristos my $padval = length($data) % 16; 512c161c69cSchristos $padval = 15 - $padval; 513c161c69cSchristos for (0..$padval) { 514c161c69cSchristos $data .= pack("C", $padval); 515c161c69cSchristos } 516c161c69cSchristos 517c161c69cSchristos #Add MAC. Assumed to be 20 bytes 518c161c69cSchristos foreach my $macval (0..19) { 519c161c69cSchristos $data .= pack("C", $macval); 520c161c69cSchristos } 521c161c69cSchristos 522c161c69cSchristos if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) { 523c161c69cSchristos #Explicit IV 524c161c69cSchristos $data = ("\0"x16).$data; 525c161c69cSchristos } 526c161c69cSchristos $rec->data($data); 527c161c69cSchristos } else { 528c161c69cSchristos die "Unsupported encryption: No ETM"; 529c161c69cSchristos } 53013d40330Schristos } else { 53153060421Schristos $rec->data($rec->decrypt_data); 53213d40330Schristos } 533c161c69cSchristos $rec->len(length($rec->data)); 53453060421Schristos 53553060421Schristos #Update the fragment len in case we changed it above 53653060421Schristos ${$self->message_frag_lens}[0] = length($msgdata) 53753060421Schristos - TLS_MESSAGE_HEADER_LENGTH; 53853060421Schristos return; 53953060421Schristos } 54053060421Schristos 54153060421Schristos #Note we don't currently support changing a fragmented message length 54253060421Schristos my $recctr = 0; 54353060421Schristos my $datadone = 0; 54453060421Schristos foreach my $rec (@{$self->records}) { 54553060421Schristos my $recdata = $rec->decrypt_data; 54653060421Schristos if ($recctr == 0) { 54753060421Schristos #This is the first record 54853060421Schristos my $remainlen = length($recdata) - $self->startoffset; 54953060421Schristos $rec->data(substr($recdata, 0, $self->startoffset) 55053060421Schristos .substr(($msgdata), 0, $remainlen)); 55153060421Schristos $datadone += $remainlen; 55253060421Schristos } elsif ($recctr + 1 == $numrecs) { 55353060421Schristos #This is the last record 55453060421Schristos $rec->data(substr($msgdata, $datadone)); 55553060421Schristos } else { 55653060421Schristos #This is a middle record 55753060421Schristos $rec->data(substr($msgdata, $datadone, length($rec->data))); 55853060421Schristos $datadone += length($rec->data); 55953060421Schristos } 56053060421Schristos $recctr++; 56153060421Schristos } 56253060421Schristos} 56353060421Schristos 56453060421Schristos#To be overridden by sub-classes 56553060421Schristossub set_message_contents 56653060421Schristos{ 56753060421Schristos} 56853060421Schristos 56953060421Schristos#Read only accessors 57053060421Schristossub server 57153060421Schristos{ 57253060421Schristos my $self = shift; 57353060421Schristos return $self->{server}; 57453060421Schristos} 57553060421Schristos 57653060421Schristos#Read/write accessors 57753060421Schristossub mt 57853060421Schristos{ 57953060421Schristos my $self = shift; 58053060421Schristos if (@_) { 58153060421Schristos $self->{mt} = shift; 58253060421Schristos } 58353060421Schristos return $self->{mt}; 58453060421Schristos} 58553060421Schristossub data 58653060421Schristos{ 58753060421Schristos my $self = shift; 58853060421Schristos if (@_) { 58953060421Schristos $self->{data} = shift; 59053060421Schristos } 59153060421Schristos return $self->{data}; 59253060421Schristos} 59353060421Schristossub records 59453060421Schristos{ 59553060421Schristos my $self = shift; 59653060421Schristos if (@_) { 59753060421Schristos $self->{records} = shift; 59853060421Schristos } 59953060421Schristos return $self->{records}; 60053060421Schristos} 60153060421Schristossub startoffset 60253060421Schristos{ 60353060421Schristos my $self = shift; 60453060421Schristos if (@_) { 60553060421Schristos $self->{startoffset} = shift; 60653060421Schristos } 60753060421Schristos return $self->{startoffset}; 60853060421Schristos} 60953060421Schristossub message_frag_lens 61053060421Schristos{ 61153060421Schristos my $self = shift; 61253060421Schristos if (@_) { 61353060421Schristos $self->{message_frag_lens} = shift; 61453060421Schristos } 61553060421Schristos return $self->{message_frag_lens}; 61653060421Schristos} 61753060421Schristossub encoded_length 61853060421Schristos{ 61953060421Schristos my $self = shift; 62053060421Schristos return TLS_MESSAGE_HEADER_LENGTH + length($self->data); 62153060421Schristos} 622b88c74d5Schristossub dupext 623b88c74d5Schristos{ 624b88c74d5Schristos my $self = shift; 625b88c74d5Schristos if (@_) { 626b88c74d5Schristos $self->{dupext} = shift; 627b88c74d5Schristos } 628b88c74d5Schristos return $self->{dupext}; 629b88c74d5Schristos} 63013d40330Schristossub successondata 63113d40330Schristos{ 63213d40330Schristos my $class = shift; 63313d40330Schristos if (@_) { 63413d40330Schristos $successondata = shift; 63513d40330Schristos } 63613d40330Schristos return $successondata; 63713d40330Schristos} 63853060421Schristos1; 639