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