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