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