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 8 use strict; 9 10 package TLSProxy::Message; 11 12 use TLSProxy::Alert; 13 14 use constant DTLS_MESSAGE_HEADER_LENGTH => 12; 15 use constant TLS_MESSAGE_HEADER_LENGTH => 4; 16 17 #Message types 18 use 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 38 use constant { 39 AL_LEVEL_WARN => 1, 40 AL_LEVEL_FATAL => 2 41 }; 42 43 #Alert descriptions 44 use 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 56 my %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 75 use 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 111 use 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 138 use 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 146 use constant { 147 CLIENT => 0, 148 SERVER => 1 149 }; 150 151 my $payload = ""; 152 my $messlen = -1; 153 my $mt; 154 my $startoffset = -1; 155 my $server = 0; 156 my $success = 0; 157 my $end = 0; 158 my @message_rec_list = (); 159 my @message_frag_lens = (); 160 my $ciphersuite = 0; 161 my $successondata = 0; 162 my $alert; 163 164 sub 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 179 sub 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 340 sub 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 503 sub end 504 { 505 my $class = shift; 506 return $end; 507 } 508 sub success 509 { 510 my $class = shift; 511 return $success; 512 } 513 sub fail 514 { 515 my $class = shift; 516 return !$success && $end; 517 } 518 519 sub alert 520 { 521 return $alert; 522 } 523 524 sub 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 555 sub 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 566 sub 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 679 sub set_message_contents 680 { 681 } 682 683 #Read only accessors 684 sub server 685 { 686 my $self = shift; 687 return $self->{server}; 688 } 689 690 #Read/write accessors 691 sub mt 692 { 693 my $self = shift; 694 if (@_) { 695 $self->{mt} = shift; 696 } 697 return $self->{mt}; 698 } 699 sub msgseq 700 { 701 my $self = shift; 702 if (@_) { 703 $self->{msgseq} = shift; 704 } 705 return $self->{msgseq}; 706 } 707 sub msgfrag 708 { 709 my $self = shift; 710 if (@_) { 711 $self->{msgfrag} = shift; 712 } 713 return $self->{msgfrag}; 714 } 715 sub msgfragoffs 716 { 717 my $self = shift; 718 if (@_) { 719 $self->{msgfragoffs} = shift; 720 } 721 return $self->{msgfragoffs}; 722 } 723 sub data 724 { 725 my $self = shift; 726 if (@_) { 727 $self->{data} = shift; 728 } 729 return $self->{data}; 730 } 731 sub records 732 { 733 my $self = shift; 734 if (@_) { 735 $self->{records} = shift; 736 } 737 return $self->{records}; 738 } 739 sub startoffset 740 { 741 my $self = shift; 742 if (@_) { 743 $self->{startoffset} = shift; 744 } 745 return $self->{startoffset}; 746 } 747 sub message_frag_lens 748 { 749 my $self = shift; 750 if (@_) { 751 $self->{message_frag_lens} = shift; 752 } 753 return $self->{message_frag_lens}; 754 } 755 sub 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 } 762 sub dupext 763 { 764 my $self = shift; 765 if (@_) { 766 $self->{dupext} = shift; 767 } 768 return $self->{dupext}; 769 } 770 sub successondata 771 { 772 my $class = shift; 773 if (@_) { 774 $successondata = shift; 775 } 776 return $successondata; 777 } 778 1; 779