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