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