1*a7148ab3SEnji Cooper# Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved. 2e0c4386eSCy Schubert# 3e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License"). You may not use 4e0c4386eSCy Schubert# this file except in compliance with the License. You can obtain a copy 5e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at 6e0c4386eSCy Schubert# https://www.openssl.org/source/license.html 7e0c4386eSCy Schubert 8e0c4386eSCy Schubertuse strict; 9e0c4386eSCy Schubert 10e0c4386eSCy Schubertpackage TLSProxy::Message; 11e0c4386eSCy Schubert 12e0c4386eSCy Schubertuse TLSProxy::Alert; 13e0c4386eSCy Schubert 14e0c4386eSCy Schubertuse constant TLS_MESSAGE_HEADER_LENGTH => 4; 15e0c4386eSCy Schubert 16e0c4386eSCy Schubert#Message types 17e0c4386eSCy Schubertuse constant { 18e0c4386eSCy Schubert MT_HELLO_REQUEST => 0, 19e0c4386eSCy Schubert MT_CLIENT_HELLO => 1, 20e0c4386eSCy Schubert MT_SERVER_HELLO => 2, 21e0c4386eSCy Schubert MT_NEW_SESSION_TICKET => 4, 22e0c4386eSCy Schubert MT_ENCRYPTED_EXTENSIONS => 8, 23e0c4386eSCy Schubert MT_CERTIFICATE => 11, 24e0c4386eSCy Schubert MT_SERVER_KEY_EXCHANGE => 12, 25e0c4386eSCy Schubert MT_CERTIFICATE_REQUEST => 13, 26e0c4386eSCy Schubert MT_SERVER_HELLO_DONE => 14, 27e0c4386eSCy Schubert MT_CERTIFICATE_VERIFY => 15, 28e0c4386eSCy Schubert MT_CLIENT_KEY_EXCHANGE => 16, 29e0c4386eSCy Schubert MT_FINISHED => 20, 30e0c4386eSCy Schubert MT_CERTIFICATE_STATUS => 22, 31e0c4386eSCy Schubert MT_NEXT_PROTO => 67 32e0c4386eSCy Schubert}; 33e0c4386eSCy Schubert 34e0c4386eSCy Schubert#Alert levels 35e0c4386eSCy Schubertuse constant { 36e0c4386eSCy Schubert AL_LEVEL_WARN => 1, 37e0c4386eSCy Schubert AL_LEVEL_FATAL => 2 38e0c4386eSCy Schubert}; 39e0c4386eSCy Schubert 40e0c4386eSCy Schubert#Alert descriptions 41e0c4386eSCy Schubertuse constant { 42e0c4386eSCy Schubert AL_DESC_CLOSE_NOTIFY => 0, 43e0c4386eSCy Schubert AL_DESC_UNEXPECTED_MESSAGE => 10, 44e0c4386eSCy Schubert AL_DESC_ILLEGAL_PARAMETER => 47, 45e0c4386eSCy Schubert AL_DESC_NO_RENEGOTIATION => 100 46e0c4386eSCy Schubert}; 47e0c4386eSCy Schubert 48e0c4386eSCy Schubertmy %message_type = ( 49e0c4386eSCy Schubert MT_HELLO_REQUEST, "HelloRequest", 50e0c4386eSCy Schubert MT_CLIENT_HELLO, "ClientHello", 51e0c4386eSCy Schubert MT_SERVER_HELLO, "ServerHello", 52e0c4386eSCy Schubert MT_NEW_SESSION_TICKET, "NewSessionTicket", 53e0c4386eSCy Schubert MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", 54e0c4386eSCy Schubert MT_CERTIFICATE, "Certificate", 55e0c4386eSCy Schubert MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange", 56e0c4386eSCy Schubert MT_CERTIFICATE_REQUEST, "CertificateRequest", 57e0c4386eSCy Schubert MT_SERVER_HELLO_DONE, "ServerHelloDone", 58e0c4386eSCy Schubert MT_CERTIFICATE_VERIFY, "CertificateVerify", 59e0c4386eSCy Schubert MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange", 60e0c4386eSCy Schubert MT_FINISHED, "Finished", 61e0c4386eSCy Schubert MT_CERTIFICATE_STATUS, "CertificateStatus", 62e0c4386eSCy Schubert MT_NEXT_PROTO, "NextProto" 63e0c4386eSCy Schubert); 64e0c4386eSCy Schubert 65e0c4386eSCy Schubertuse constant { 66e0c4386eSCy Schubert EXT_SERVER_NAME => 0, 67e0c4386eSCy Schubert EXT_MAX_FRAGMENT_LENGTH => 1, 68e0c4386eSCy Schubert EXT_STATUS_REQUEST => 5, 69e0c4386eSCy Schubert EXT_SUPPORTED_GROUPS => 10, 70e0c4386eSCy Schubert EXT_EC_POINT_FORMATS => 11, 71e0c4386eSCy Schubert EXT_SRP => 12, 72e0c4386eSCy Schubert EXT_SIG_ALGS => 13, 73e0c4386eSCy Schubert EXT_USE_SRTP => 14, 74e0c4386eSCy Schubert EXT_ALPN => 16, 75e0c4386eSCy Schubert EXT_SCT => 18, 76e0c4386eSCy Schubert EXT_PADDING => 21, 77e0c4386eSCy Schubert EXT_ENCRYPT_THEN_MAC => 22, 78e0c4386eSCy Schubert EXT_EXTENDED_MASTER_SECRET => 23, 79e0c4386eSCy Schubert EXT_SESSION_TICKET => 35, 80e0c4386eSCy Schubert EXT_KEY_SHARE => 51, 81e0c4386eSCy Schubert EXT_PSK => 41, 82e0c4386eSCy Schubert EXT_SUPPORTED_VERSIONS => 43, 83e0c4386eSCy Schubert EXT_COOKIE => 44, 84e0c4386eSCy Schubert EXT_PSK_KEX_MODES => 45, 85e0c4386eSCy Schubert EXT_POST_HANDSHAKE_AUTH => 49, 86e0c4386eSCy Schubert EXT_SIG_ALGS_CERT => 50, 87e0c4386eSCy Schubert EXT_RENEGOTIATE => 65281, 88e0c4386eSCy Schubert EXT_NPN => 13172, 89e0c4386eSCy Schubert EXT_CRYPTOPRO_BUG_EXTENSION => 0xfde8, 90e0c4386eSCy Schubert EXT_UNKNOWN => 0xfffe, 91e0c4386eSCy Schubert #Unknown extension that should appear last 92e0c4386eSCy Schubert EXT_FORCE_LAST => 0xffff 93e0c4386eSCy Schubert}; 94e0c4386eSCy Schubert 95e0c4386eSCy Schubert# SignatureScheme of TLS 1.3 from: 96e0c4386eSCy Schubert# https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme 97e0c4386eSCy Schubert# We have to manually grab the SHA224 equivalents from the old registry 98e0c4386eSCy Schubertuse constant { 99e0c4386eSCy Schubert SIG_ALG_RSA_PKCS1_SHA256 => 0x0401, 100e0c4386eSCy Schubert SIG_ALG_RSA_PKCS1_SHA384 => 0x0501, 101e0c4386eSCy Schubert SIG_ALG_RSA_PKCS1_SHA512 => 0x0601, 102e0c4386eSCy Schubert SIG_ALG_ECDSA_SECP256R1_SHA256 => 0x0403, 103e0c4386eSCy Schubert SIG_ALG_ECDSA_SECP384R1_SHA384 => 0x0503, 104e0c4386eSCy Schubert SIG_ALG_ECDSA_SECP521R1_SHA512 => 0x0603, 105e0c4386eSCy Schubert SIG_ALG_RSA_PSS_RSAE_SHA256 => 0x0804, 106e0c4386eSCy Schubert SIG_ALG_RSA_PSS_RSAE_SHA384 => 0x0805, 107e0c4386eSCy Schubert SIG_ALG_RSA_PSS_RSAE_SHA512 => 0x0806, 108e0c4386eSCy Schubert SIG_ALG_ED25519 => 0x0807, 109e0c4386eSCy Schubert SIG_ALG_ED448 => 0x0808, 110e0c4386eSCy Schubert SIG_ALG_RSA_PSS_PSS_SHA256 => 0x0809, 111e0c4386eSCy Schubert SIG_ALG_RSA_PSS_PSS_SHA384 => 0x080a, 112e0c4386eSCy Schubert SIG_ALG_RSA_PSS_PSS_SHA512 => 0x080b, 113e0c4386eSCy Schubert SIG_ALG_RSA_PKCS1_SHA1 => 0x0201, 114e0c4386eSCy Schubert SIG_ALG_ECDSA_SHA1 => 0x0203, 115e0c4386eSCy Schubert SIG_ALG_DSA_SHA1 => 0x0202, 116e0c4386eSCy Schubert SIG_ALG_DSA_SHA256 => 0x0402, 117e0c4386eSCy Schubert SIG_ALG_DSA_SHA384 => 0x0502, 118e0c4386eSCy Schubert SIG_ALG_DSA_SHA512 => 0x0602, 119e0c4386eSCy Schubert OSSL_SIG_ALG_RSA_PKCS1_SHA224 => 0x0301, 120e0c4386eSCy Schubert OSSL_SIG_ALG_DSA_SHA224 => 0x0302, 121e0c4386eSCy Schubert OSSL_SIG_ALG_ECDSA_SHA224 => 0x0303 122e0c4386eSCy Schubert}; 123e0c4386eSCy Schubert 124e0c4386eSCy Schubertuse constant { 125e0c4386eSCy Schubert CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f, 126e0c4386eSCy Schubert CIPHER_DHE_RSA_AES_128_SHA => 0x0033, 127e0c4386eSCy Schubert CIPHER_ADH_AES_128_SHA => 0x0034, 128e0c4386eSCy Schubert CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301, 129e0c4386eSCy Schubert CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302 130e0c4386eSCy Schubert}; 131e0c4386eSCy Schubert 132e0c4386eSCy Schubertuse constant { 133e0c4386eSCy Schubert CLIENT => 0, 134e0c4386eSCy Schubert SERVER => 1 135e0c4386eSCy Schubert}; 136e0c4386eSCy Schubert 137e0c4386eSCy Schubertmy $payload = ""; 138e0c4386eSCy Schubertmy $messlen = -1; 139e0c4386eSCy Schubertmy $mt; 140e0c4386eSCy Schubertmy $startoffset = -1; 141e0c4386eSCy Schubertmy $server = 0; 142e0c4386eSCy Schubertmy $success = 0; 143e0c4386eSCy Schubertmy $end = 0; 144e0c4386eSCy Schubertmy @message_rec_list = (); 145e0c4386eSCy Schubertmy @message_frag_lens = (); 146e0c4386eSCy Schubertmy $ciphersuite = 0; 147e0c4386eSCy Schubertmy $successondata = 0; 148e0c4386eSCy Schubertmy $alert; 149e0c4386eSCy Schubert 150e0c4386eSCy Schubertsub clear 151e0c4386eSCy Schubert{ 152e0c4386eSCy Schubert $payload = ""; 153e0c4386eSCy Schubert $messlen = -1; 154e0c4386eSCy Schubert $startoffset = -1; 155e0c4386eSCy Schubert $server = 0; 156e0c4386eSCy Schubert $success = 0; 157e0c4386eSCy Schubert $end = 0; 158e0c4386eSCy Schubert $successondata = 0; 159e0c4386eSCy Schubert @message_rec_list = (); 160e0c4386eSCy Schubert @message_frag_lens = (); 161e0c4386eSCy Schubert $alert = undef; 162e0c4386eSCy Schubert} 163e0c4386eSCy Schubert 164e0c4386eSCy Schubert#Class method to extract messages from a record 165e0c4386eSCy Schubertsub get_messages 166e0c4386eSCy Schubert{ 167e0c4386eSCy Schubert my $class = shift; 168e0c4386eSCy Schubert my $serverin = shift; 169e0c4386eSCy Schubert my $record = shift; 170e0c4386eSCy Schubert my @messages = (); 171e0c4386eSCy Schubert my $message; 172e0c4386eSCy Schubert 173e0c4386eSCy Schubert @message_frag_lens = (); 174e0c4386eSCy Schubert 175e0c4386eSCy Schubert if ($serverin != $server && length($payload) != 0) { 176e0c4386eSCy Schubert die "Changed peer, but we still have fragment data\n"; 177e0c4386eSCy Schubert } 178e0c4386eSCy Schubert $server = $serverin; 179e0c4386eSCy Schubert 180e0c4386eSCy Schubert if ($record->content_type == TLSProxy::Record::RT_CCS) { 181e0c4386eSCy Schubert if ($payload ne "") { 182e0c4386eSCy Schubert #We can't handle this yet 183e0c4386eSCy Schubert die "CCS received before message data complete\n"; 184e0c4386eSCy Schubert } 185e0c4386eSCy Schubert if (!TLSProxy::Proxy->is_tls13()) { 186e0c4386eSCy Schubert if ($server) { 187e0c4386eSCy Schubert TLSProxy::Record->server_encrypting(1); 188e0c4386eSCy Schubert } else { 189e0c4386eSCy Schubert TLSProxy::Record->client_encrypting(1); 190e0c4386eSCy Schubert } 191e0c4386eSCy Schubert } 192e0c4386eSCy Schubert } elsif ($record->content_type == TLSProxy::Record::RT_HANDSHAKE) { 193e0c4386eSCy Schubert if ($record->len == 0 || $record->len_real == 0) { 194e0c4386eSCy Schubert print " Message truncated\n"; 195e0c4386eSCy Schubert } else { 196e0c4386eSCy Schubert my $recoffset = 0; 197e0c4386eSCy Schubert 198e0c4386eSCy Schubert if (length $payload > 0) { 199e0c4386eSCy Schubert #We are continuing processing a message started in a previous 200e0c4386eSCy Schubert #record. Add this record to the list associated with this 201e0c4386eSCy Schubert #message 202e0c4386eSCy Schubert push @message_rec_list, $record; 203e0c4386eSCy Schubert 204e0c4386eSCy Schubert if ($messlen <= length($payload)) { 205e0c4386eSCy Schubert #Shouldn't happen 206e0c4386eSCy Schubert die "Internal error: invalid messlen: ".$messlen 207e0c4386eSCy Schubert ." payload length:".length($payload)."\n"; 208e0c4386eSCy Schubert } 209e0c4386eSCy Schubert if (length($payload) + $record->decrypt_len >= $messlen) { 210e0c4386eSCy Schubert #We can complete the message with this record 211e0c4386eSCy Schubert $recoffset = $messlen - length($payload); 212e0c4386eSCy Schubert $payload .= substr($record->decrypt_data, 0, $recoffset); 213e0c4386eSCy Schubert push @message_frag_lens, $recoffset; 214e0c4386eSCy Schubert $message = create_message($server, $mt, $payload, 215e0c4386eSCy Schubert $startoffset); 216e0c4386eSCy Schubert push @messages, $message; 217e0c4386eSCy Schubert 218e0c4386eSCy Schubert $payload = ""; 219e0c4386eSCy Schubert } else { 220e0c4386eSCy Schubert #This is just part of the total message 221e0c4386eSCy Schubert $payload .= $record->decrypt_data; 222e0c4386eSCy Schubert $recoffset = $record->decrypt_len; 223e0c4386eSCy Schubert push @message_frag_lens, $record->decrypt_len; 224e0c4386eSCy Schubert } 225e0c4386eSCy Schubert print " Partial message data read: ".$recoffset." bytes\n"; 226e0c4386eSCy Schubert } 227e0c4386eSCy Schubert 228e0c4386eSCy Schubert while ($record->decrypt_len > $recoffset) { 229e0c4386eSCy Schubert #We are at the start of a new message 230e0c4386eSCy Schubert if ($record->decrypt_len - $recoffset < 4) { 231e0c4386eSCy Schubert #Whilst technically probably valid we can't cope with this 232e0c4386eSCy Schubert die "End of record in the middle of a message header\n"; 233e0c4386eSCy Schubert } 234e0c4386eSCy Schubert @message_rec_list = ($record); 235e0c4386eSCy Schubert my $lenhi; 236e0c4386eSCy Schubert my $lenlo; 237e0c4386eSCy Schubert ($mt, $lenhi, $lenlo) = unpack('CnC', 238e0c4386eSCy Schubert substr($record->decrypt_data, 239e0c4386eSCy Schubert $recoffset)); 240e0c4386eSCy Schubert $messlen = ($lenhi << 8) | $lenlo; 241e0c4386eSCy Schubert print " Message type: $message_type{$mt}\n"; 242e0c4386eSCy Schubert print " Message Length: $messlen\n"; 243e0c4386eSCy Schubert $startoffset = $recoffset; 244e0c4386eSCy Schubert $recoffset += 4; 245e0c4386eSCy Schubert $payload = ""; 246e0c4386eSCy Schubert 247e0c4386eSCy Schubert if ($recoffset <= $record->decrypt_len) { 248e0c4386eSCy Schubert #Some payload data is present in this record 249e0c4386eSCy Schubert if ($record->decrypt_len - $recoffset >= $messlen) { 250e0c4386eSCy Schubert #We can complete the message with this record 251e0c4386eSCy Schubert $payload .= substr($record->decrypt_data, $recoffset, 252e0c4386eSCy Schubert $messlen); 253e0c4386eSCy Schubert $recoffset += $messlen; 254e0c4386eSCy Schubert push @message_frag_lens, $messlen; 255e0c4386eSCy Schubert $message = create_message($server, $mt, $payload, 256e0c4386eSCy Schubert $startoffset); 257e0c4386eSCy Schubert push @messages, $message; 258e0c4386eSCy Schubert 259e0c4386eSCy Schubert $payload = ""; 260e0c4386eSCy Schubert } else { 261e0c4386eSCy Schubert #This is just part of the total message 262e0c4386eSCy Schubert $payload .= substr($record->decrypt_data, $recoffset, 263e0c4386eSCy Schubert $record->decrypt_len - $recoffset); 264e0c4386eSCy Schubert $recoffset = $record->decrypt_len; 265e0c4386eSCy Schubert push @message_frag_lens, $recoffset; 266e0c4386eSCy Schubert } 267e0c4386eSCy Schubert } 268e0c4386eSCy Schubert } 269e0c4386eSCy Schubert } 270e0c4386eSCy Schubert } elsif ($record->content_type == TLSProxy::Record::RT_APPLICATION_DATA) { 271e0c4386eSCy Schubert print " [ENCRYPTED APPLICATION DATA]\n"; 272e0c4386eSCy Schubert print " [".$record->decrypt_data."]\n"; 273e0c4386eSCy Schubert 274e0c4386eSCy Schubert if ($successondata) { 275e0c4386eSCy Schubert $success = 1; 276e0c4386eSCy Schubert $end = 1; 277e0c4386eSCy Schubert } 278e0c4386eSCy Schubert } elsif ($record->content_type == TLSProxy::Record::RT_ALERT) { 279e0c4386eSCy Schubert my ($alertlev, $alertdesc) = unpack('CC', $record->decrypt_data); 280e0c4386eSCy Schubert print " [$alertlev, $alertdesc]\n"; 281e0c4386eSCy Schubert #A CloseNotify from the client indicates we have finished successfully 282e0c4386eSCy Schubert #(we assume) 283e0c4386eSCy Schubert if (!$end && !$server && $alertlev == AL_LEVEL_WARN 284e0c4386eSCy Schubert && $alertdesc == AL_DESC_CLOSE_NOTIFY) { 285e0c4386eSCy Schubert $success = 1; 286e0c4386eSCy Schubert } 287e0c4386eSCy Schubert #Fatal or close notify alerts end the test 288e0c4386eSCy Schubert if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) { 289e0c4386eSCy Schubert $end = 1; 290e0c4386eSCy Schubert } 291e0c4386eSCy Schubert $alert = TLSProxy::Alert->new( 292e0c4386eSCy Schubert $server, 293e0c4386eSCy Schubert $record->encrypted, 294e0c4386eSCy Schubert $alertlev, 295e0c4386eSCy Schubert $alertdesc); 296e0c4386eSCy Schubert } 297e0c4386eSCy Schubert 298e0c4386eSCy Schubert return @messages; 299e0c4386eSCy Schubert} 300e0c4386eSCy Schubert 301e0c4386eSCy Schubert#Function to work out which sub-class we need to create and then 302e0c4386eSCy Schubert#construct it 303e0c4386eSCy Schubertsub create_message 304e0c4386eSCy Schubert{ 305e0c4386eSCy Schubert my ($server, $mt, $data, $startoffset) = @_; 306e0c4386eSCy Schubert my $message; 307e0c4386eSCy Schubert 308e0c4386eSCy Schubert #We only support ClientHello in this version...needs to be extended for 309e0c4386eSCy Schubert #others 310e0c4386eSCy Schubert if ($mt == MT_CLIENT_HELLO) { 311e0c4386eSCy Schubert $message = TLSProxy::ClientHello->new( 312e0c4386eSCy Schubert $server, 313e0c4386eSCy Schubert $data, 314e0c4386eSCy Schubert [@message_rec_list], 315e0c4386eSCy Schubert $startoffset, 316e0c4386eSCy Schubert [@message_frag_lens] 317e0c4386eSCy Schubert ); 318e0c4386eSCy Schubert $message->parse(); 319e0c4386eSCy Schubert } elsif ($mt == MT_SERVER_HELLO) { 320e0c4386eSCy Schubert $message = TLSProxy::ServerHello->new( 321e0c4386eSCy Schubert $server, 322e0c4386eSCy Schubert $data, 323e0c4386eSCy Schubert [@message_rec_list], 324e0c4386eSCy Schubert $startoffset, 325e0c4386eSCy Schubert [@message_frag_lens] 326e0c4386eSCy Schubert ); 327e0c4386eSCy Schubert $message->parse(); 328e0c4386eSCy Schubert } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) { 329e0c4386eSCy Schubert $message = TLSProxy::EncryptedExtensions->new( 330e0c4386eSCy Schubert $server, 331e0c4386eSCy Schubert $data, 332e0c4386eSCy Schubert [@message_rec_list], 333e0c4386eSCy Schubert $startoffset, 334e0c4386eSCy Schubert [@message_frag_lens] 335e0c4386eSCy Schubert ); 336e0c4386eSCy Schubert $message->parse(); 337e0c4386eSCy Schubert } elsif ($mt == MT_CERTIFICATE) { 338e0c4386eSCy Schubert $message = TLSProxy::Certificate->new( 339e0c4386eSCy Schubert $server, 340e0c4386eSCy Schubert $data, 341e0c4386eSCy Schubert [@message_rec_list], 342e0c4386eSCy Schubert $startoffset, 343e0c4386eSCy Schubert [@message_frag_lens] 344e0c4386eSCy Schubert ); 345e0c4386eSCy Schubert $message->parse(); 346e0c4386eSCy Schubert } elsif ($mt == MT_CERTIFICATE_REQUEST) { 347e0c4386eSCy Schubert $message = TLSProxy::CertificateRequest->new( 348e0c4386eSCy Schubert $server, 349e0c4386eSCy Schubert $data, 350e0c4386eSCy Schubert [@message_rec_list], 351e0c4386eSCy Schubert $startoffset, 352e0c4386eSCy Schubert [@message_frag_lens] 353e0c4386eSCy Schubert ); 354e0c4386eSCy Schubert $message->parse(); 355e0c4386eSCy Schubert } elsif ($mt == MT_CERTIFICATE_VERIFY) { 356e0c4386eSCy Schubert $message = TLSProxy::CertificateVerify->new( 357e0c4386eSCy Schubert $server, 358e0c4386eSCy Schubert $data, 359e0c4386eSCy Schubert [@message_rec_list], 360e0c4386eSCy Schubert $startoffset, 361e0c4386eSCy Schubert [@message_frag_lens] 362e0c4386eSCy Schubert ); 363e0c4386eSCy Schubert $message->parse(); 364e0c4386eSCy Schubert } elsif ($mt == MT_SERVER_KEY_EXCHANGE) { 365e0c4386eSCy Schubert $message = TLSProxy::ServerKeyExchange->new( 366e0c4386eSCy Schubert $server, 367e0c4386eSCy Schubert $data, 368e0c4386eSCy Schubert [@message_rec_list], 369e0c4386eSCy Schubert $startoffset, 370e0c4386eSCy Schubert [@message_frag_lens] 371e0c4386eSCy Schubert ); 372e0c4386eSCy Schubert $message->parse(); 373e0c4386eSCy Schubert } elsif ($mt == MT_NEW_SESSION_TICKET) { 374e0c4386eSCy Schubert $message = TLSProxy::NewSessionTicket->new( 375e0c4386eSCy Schubert $server, 376e0c4386eSCy Schubert $data, 377e0c4386eSCy Schubert [@message_rec_list], 378e0c4386eSCy Schubert $startoffset, 379e0c4386eSCy Schubert [@message_frag_lens] 380e0c4386eSCy Schubert ); 381e0c4386eSCy Schubert $message->parse(); 382*a7148ab3SEnji Cooper } elsif ($mt == MT_NEXT_PROTO) { 383*a7148ab3SEnji Cooper $message = TLSProxy::NextProto->new( 384*a7148ab3SEnji Cooper $server, 385*a7148ab3SEnji Cooper $data, 386*a7148ab3SEnji Cooper [@message_rec_list], 387*a7148ab3SEnji Cooper $startoffset, 388*a7148ab3SEnji Cooper [@message_frag_lens] 389*a7148ab3SEnji Cooper ); 390*a7148ab3SEnji Cooper $message->parse(); 391e0c4386eSCy Schubert } else { 392e0c4386eSCy Schubert #Unknown message type 393e0c4386eSCy Schubert $message = TLSProxy::Message->new( 394e0c4386eSCy Schubert $server, 395e0c4386eSCy Schubert $mt, 396e0c4386eSCy Schubert $data, 397e0c4386eSCy Schubert [@message_rec_list], 398e0c4386eSCy Schubert $startoffset, 399e0c4386eSCy Schubert [@message_frag_lens] 400e0c4386eSCy Schubert ); 401e0c4386eSCy Schubert } 402e0c4386eSCy Schubert 403e0c4386eSCy Schubert return $message; 404e0c4386eSCy Schubert} 405e0c4386eSCy Schubert 406e0c4386eSCy Schubertsub end 407e0c4386eSCy Schubert{ 408e0c4386eSCy Schubert my $class = shift; 409e0c4386eSCy Schubert return $end; 410e0c4386eSCy Schubert} 411e0c4386eSCy Schubertsub success 412e0c4386eSCy Schubert{ 413e0c4386eSCy Schubert my $class = shift; 414e0c4386eSCy Schubert return $success; 415e0c4386eSCy Schubert} 416e0c4386eSCy Schubertsub fail 417e0c4386eSCy Schubert{ 418e0c4386eSCy Schubert my $class = shift; 419e0c4386eSCy Schubert return !$success && $end; 420e0c4386eSCy Schubert} 421e0c4386eSCy Schubert 422e0c4386eSCy Schubertsub alert 423e0c4386eSCy Schubert{ 424e0c4386eSCy Schubert return $alert; 425e0c4386eSCy Schubert} 426e0c4386eSCy Schubert 427e0c4386eSCy Schubertsub new 428e0c4386eSCy Schubert{ 429e0c4386eSCy Schubert my $class = shift; 430e0c4386eSCy Schubert my ($server, 431e0c4386eSCy Schubert $mt, 432e0c4386eSCy Schubert $data, 433e0c4386eSCy Schubert $records, 434e0c4386eSCy Schubert $startoffset, 435e0c4386eSCy Schubert $message_frag_lens) = @_; 436e0c4386eSCy Schubert 437e0c4386eSCy Schubert my $self = { 438e0c4386eSCy Schubert server => $server, 439e0c4386eSCy Schubert data => $data, 440e0c4386eSCy Schubert records => $records, 441e0c4386eSCy Schubert mt => $mt, 442e0c4386eSCy Schubert startoffset => $startoffset, 443e0c4386eSCy Schubert message_frag_lens => $message_frag_lens, 444e0c4386eSCy Schubert dupext => -1 445e0c4386eSCy Schubert }; 446e0c4386eSCy Schubert 447e0c4386eSCy Schubert return bless $self, $class; 448e0c4386eSCy Schubert} 449e0c4386eSCy Schubert 450e0c4386eSCy Schubertsub ciphersuite 451e0c4386eSCy Schubert{ 452e0c4386eSCy Schubert my $class = shift; 453e0c4386eSCy Schubert if (@_) { 454e0c4386eSCy Schubert $ciphersuite = shift; 455e0c4386eSCy Schubert } 456e0c4386eSCy Schubert return $ciphersuite; 457e0c4386eSCy Schubert} 458e0c4386eSCy Schubert 459e0c4386eSCy Schubert#Update all the underlying records with the modified data from this message 460e0c4386eSCy Schubert#Note: Only supports TLSv1.3 and ETM encryption 461e0c4386eSCy Schubertsub repack 462e0c4386eSCy Schubert{ 463e0c4386eSCy Schubert my $self = shift; 464e0c4386eSCy Schubert my $msgdata; 465e0c4386eSCy Schubert 466e0c4386eSCy Schubert my $numrecs = $#{$self->records}; 467e0c4386eSCy Schubert 468e0c4386eSCy Schubert $self->set_message_contents(); 469e0c4386eSCy Schubert 470e0c4386eSCy Schubert my $lenhi; 471e0c4386eSCy Schubert my $lenlo; 472e0c4386eSCy Schubert 473e0c4386eSCy Schubert $lenlo = length($self->data) & 0xff; 474e0c4386eSCy Schubert $lenhi = length($self->data) >> 8; 475e0c4386eSCy Schubert $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; 476e0c4386eSCy Schubert 477e0c4386eSCy Schubert if ($numrecs == 0) { 478e0c4386eSCy Schubert #The message is fully contained within one record 479e0c4386eSCy Schubert my ($rec) = @{$self->records}; 480e0c4386eSCy Schubert my $recdata = $rec->decrypt_data; 481e0c4386eSCy Schubert 482e0c4386eSCy Schubert my $old_length; 483e0c4386eSCy Schubert 484e0c4386eSCy Schubert # We use empty message_frag_lens to indicates that pre-repacking, 485e0c4386eSCy Schubert # the message wasn't present. The first fragment length doesn't include 486e0c4386eSCy Schubert # the TLS header, so we need to check and compute the right length. 487e0c4386eSCy Schubert if (@{$self->message_frag_lens}) { 488e0c4386eSCy Schubert $old_length = ${$self->message_frag_lens}[0] + 489e0c4386eSCy Schubert TLS_MESSAGE_HEADER_LENGTH; 490e0c4386eSCy Schubert } else { 491e0c4386eSCy Schubert $old_length = 0; 492e0c4386eSCy Schubert } 493e0c4386eSCy Schubert 494e0c4386eSCy Schubert my $prefix = substr($recdata, 0, $self->startoffset); 495e0c4386eSCy Schubert my $suffix = substr($recdata, $self->startoffset + $old_length); 496e0c4386eSCy Schubert 497e0c4386eSCy Schubert $rec->decrypt_data($prefix.($msgdata).($suffix)); 498e0c4386eSCy Schubert # TODO(openssl-team): don't keep explicit lengths. 499e0c4386eSCy Schubert # (If a length override is ever needed to construct invalid packets, 500e0c4386eSCy Schubert # use an explicit override field instead.) 501e0c4386eSCy Schubert $rec->decrypt_len(length($rec->decrypt_data)); 502e0c4386eSCy Schubert # Only support re-encryption for TLSv1.3 and ETM. 503e0c4386eSCy Schubert if ($rec->encrypted()) { 504e0c4386eSCy Schubert if (TLSProxy::Proxy->is_tls13()) { 505e0c4386eSCy Schubert #Add content type (1 byte) and 16 tag bytes 506e0c4386eSCy Schubert $rec->data($rec->decrypt_data 507e0c4386eSCy Schubert .pack("C", TLSProxy::Record::RT_HANDSHAKE).("\0"x16)); 508e0c4386eSCy Schubert } elsif ($rec->etm()) { 509e0c4386eSCy Schubert my $data = $rec->decrypt_data; 510e0c4386eSCy Schubert #Add padding 511e0c4386eSCy Schubert my $padval = length($data) % 16; 512e0c4386eSCy Schubert $padval = 15 - $padval; 513e0c4386eSCy Schubert for (0..$padval) { 514e0c4386eSCy Schubert $data .= pack("C", $padval); 515e0c4386eSCy Schubert } 516e0c4386eSCy Schubert 517e0c4386eSCy Schubert #Add MAC. Assumed to be 20 bytes 518e0c4386eSCy Schubert foreach my $macval (0..19) { 519e0c4386eSCy Schubert $data .= pack("C", $macval); 520e0c4386eSCy Schubert } 521e0c4386eSCy Schubert 522e0c4386eSCy Schubert if ($rec->version() >= TLSProxy::Record::VERS_TLS_1_1) { 523e0c4386eSCy Schubert #Explicit IV 524e0c4386eSCy Schubert $data = ("\0"x16).$data; 525e0c4386eSCy Schubert } 526e0c4386eSCy Schubert $rec->data($data); 527e0c4386eSCy Schubert } else { 528e0c4386eSCy Schubert die "Unsupported encryption: No ETM"; 529e0c4386eSCy Schubert } 530e0c4386eSCy Schubert } else { 531e0c4386eSCy Schubert $rec->data($rec->decrypt_data); 532e0c4386eSCy Schubert } 533e0c4386eSCy Schubert $rec->len(length($rec->data)); 534e0c4386eSCy Schubert 535e0c4386eSCy Schubert #Update the fragment len in case we changed it above 536e0c4386eSCy Schubert ${$self->message_frag_lens}[0] = length($msgdata) 537e0c4386eSCy Schubert - TLS_MESSAGE_HEADER_LENGTH; 538e0c4386eSCy Schubert return; 539e0c4386eSCy Schubert } 540e0c4386eSCy Schubert 541e0c4386eSCy Schubert #Note we don't currently support changing a fragmented message length 542e0c4386eSCy Schubert my $recctr = 0; 543e0c4386eSCy Schubert my $datadone = 0; 544e0c4386eSCy Schubert foreach my $rec (@{$self->records}) { 545e0c4386eSCy Schubert my $recdata = $rec->decrypt_data; 546e0c4386eSCy Schubert if ($recctr == 0) { 547e0c4386eSCy Schubert #This is the first record 548e0c4386eSCy Schubert my $remainlen = length($recdata) - $self->startoffset; 549e0c4386eSCy Schubert $rec->data(substr($recdata, 0, $self->startoffset) 550e0c4386eSCy Schubert .substr(($msgdata), 0, $remainlen)); 551e0c4386eSCy Schubert $datadone += $remainlen; 552e0c4386eSCy Schubert } elsif ($recctr + 1 == $numrecs) { 553e0c4386eSCy Schubert #This is the last record 554e0c4386eSCy Schubert $rec->data(substr($msgdata, $datadone)); 555e0c4386eSCy Schubert } else { 556e0c4386eSCy Schubert #This is a middle record 557e0c4386eSCy Schubert $rec->data(substr($msgdata, $datadone, length($rec->data))); 558e0c4386eSCy Schubert $datadone += length($rec->data); 559e0c4386eSCy Schubert } 560e0c4386eSCy Schubert $recctr++; 561e0c4386eSCy Schubert } 562e0c4386eSCy Schubert} 563e0c4386eSCy Schubert 564e0c4386eSCy Schubert#To be overridden by sub-classes 565e0c4386eSCy Schubertsub set_message_contents 566e0c4386eSCy Schubert{ 567e0c4386eSCy Schubert} 568e0c4386eSCy Schubert 569e0c4386eSCy Schubert#Read only accessors 570e0c4386eSCy Schubertsub server 571e0c4386eSCy Schubert{ 572e0c4386eSCy Schubert my $self = shift; 573e0c4386eSCy Schubert return $self->{server}; 574e0c4386eSCy Schubert} 575e0c4386eSCy Schubert 576e0c4386eSCy Schubert#Read/write accessors 577e0c4386eSCy Schubertsub mt 578e0c4386eSCy Schubert{ 579e0c4386eSCy Schubert my $self = shift; 580e0c4386eSCy Schubert if (@_) { 581e0c4386eSCy Schubert $self->{mt} = shift; 582e0c4386eSCy Schubert } 583e0c4386eSCy Schubert return $self->{mt}; 584e0c4386eSCy Schubert} 585e0c4386eSCy Schubertsub data 586e0c4386eSCy Schubert{ 587e0c4386eSCy Schubert my $self = shift; 588e0c4386eSCy Schubert if (@_) { 589e0c4386eSCy Schubert $self->{data} = shift; 590e0c4386eSCy Schubert } 591e0c4386eSCy Schubert return $self->{data}; 592e0c4386eSCy Schubert} 593e0c4386eSCy Schubertsub records 594e0c4386eSCy Schubert{ 595e0c4386eSCy Schubert my $self = shift; 596e0c4386eSCy Schubert if (@_) { 597e0c4386eSCy Schubert $self->{records} = shift; 598e0c4386eSCy Schubert } 599e0c4386eSCy Schubert return $self->{records}; 600e0c4386eSCy Schubert} 601e0c4386eSCy Schubertsub startoffset 602e0c4386eSCy Schubert{ 603e0c4386eSCy Schubert my $self = shift; 604e0c4386eSCy Schubert if (@_) { 605e0c4386eSCy Schubert $self->{startoffset} = shift; 606e0c4386eSCy Schubert } 607e0c4386eSCy Schubert return $self->{startoffset}; 608e0c4386eSCy Schubert} 609e0c4386eSCy Schubertsub message_frag_lens 610e0c4386eSCy Schubert{ 611e0c4386eSCy Schubert my $self = shift; 612e0c4386eSCy Schubert if (@_) { 613e0c4386eSCy Schubert $self->{message_frag_lens} = shift; 614e0c4386eSCy Schubert } 615e0c4386eSCy Schubert return $self->{message_frag_lens}; 616e0c4386eSCy Schubert} 617e0c4386eSCy Schubertsub encoded_length 618e0c4386eSCy Schubert{ 619e0c4386eSCy Schubert my $self = shift; 620e0c4386eSCy Schubert return TLS_MESSAGE_HEADER_LENGTH + length($self->data); 621e0c4386eSCy Schubert} 622e0c4386eSCy Schubertsub dupext 623e0c4386eSCy Schubert{ 624e0c4386eSCy Schubert my $self = shift; 625e0c4386eSCy Schubert if (@_) { 626e0c4386eSCy Schubert $self->{dupext} = shift; 627e0c4386eSCy Schubert } 628e0c4386eSCy Schubert return $self->{dupext}; 629e0c4386eSCy Schubert} 630e0c4386eSCy Schubertsub successondata 631e0c4386eSCy Schubert{ 632e0c4386eSCy Schubert my $class = shift; 633e0c4386eSCy Schubert if (@_) { 634e0c4386eSCy Schubert $successondata = shift; 635e0c4386eSCy Schubert } 636e0c4386eSCy Schubert return $successondata; 637e0c4386eSCy Schubert} 638e0c4386eSCy Schubert1; 639