diff options
Diffstat (limited to 'util/perl/TLSProxy/Message.pm')
-rw-r--r-- | util/perl/TLSProxy/Message.pm | 187 |
1 files changed, 158 insertions, 29 deletions
diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index ce22187569..c5e822e90d 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -11,6 +11,7 @@ package TLSProxy::Message; use TLSProxy::Alert; +use constant DTLS_MESSAGE_HEADER_LENGTH => 12; use constant TLS_MESSAGE_HEADER_LENGTH => 4; #Message types @@ -18,6 +19,7 @@ use constant { MT_HELLO_REQUEST => 0, MT_CLIENT_HELLO => 1, MT_SERVER_HELLO => 2, + MT_HELLO_VERIFY_REQUEST => 3, MT_NEW_SESSION_TICKET => 4, MT_ENCRYPTED_EXTENSIONS => 8, MT_CERTIFICATE => 11, @@ -42,7 +44,9 @@ use constant { use constant { AL_DESC_CLOSE_NOTIFY => 0, AL_DESC_UNEXPECTED_MESSAGE => 10, + AL_DESC_BAD_RECORD_MAC => 20, AL_DESC_ILLEGAL_PARAMETER => 47, + AL_DESC_PROTOCOL_VERSION => 70, AL_DESC_NO_RENEGOTIATION => 100 }; @@ -50,6 +54,7 @@ my %message_type = ( MT_HELLO_REQUEST, "HelloRequest", MT_CLIENT_HELLO, "ClientHello", MT_SERVER_HELLO, "ServerHello", + MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest", MT_NEW_SESSION_TICKET, "NewSessionTicket", MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions", MT_CERTIFICATE, "Certificate", @@ -172,6 +177,7 @@ sub get_messages my $class = shift; my $serverin = shift; my $record = shift; + my $isdtls = shift; my @messages = (); my $message; @@ -216,8 +222,14 @@ sub get_messages $recoffset = $messlen - length($payload); $payload .= substr($record->decrypt_data, 0, $recoffset); push @message_frag_lens, $recoffset; - $message = create_message($server, $mt, $payload, - $startoffset); + if ($isdtls) { + # We must set $msgseq, $msgfrag, $msgfragoffs + die "Internal error: cannot handle partial dtls messages\n" + } + $message = create_message($server, $mt, + #$msgseq, $msgfrag, $msgfragoffs, + 0, 0, 0, + $payload, $startoffset, $isdtls); push @messages, $message; $payload = ""; @@ -232,21 +244,36 @@ sub get_messages while ($record->decrypt_len > $recoffset) { #We are at the start of a new message - if ($record->decrypt_len - $recoffset < 4) { + my $msgheaderlen = $isdtls ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; + if ($record->decrypt_len - $recoffset < $msgheaderlen) { #Whilst technically probably valid we can't cope with this die "End of record in the middle of a message header\n"; } @message_rec_list = ($record); my $lenhi; my $lenlo; - ($mt, $lenhi, $lenlo) = unpack('CnC', - substr($record->decrypt_data, - $recoffset)); + my $msgseq; + my $msgfrag; + my $msgfragoffs; + if ($isdtls) { + my $msgfraghi; + my $msgfraglo; + my $msgfragoffshi; + my $msgfragoffslo; + ($mt, $lenhi, $lenlo, $msgseq, $msgfraghi, $msgfraglo, $msgfragoffshi, $msgfragoffslo) = + unpack('CnCnnCnC', substr($record->decrypt_data, $recoffset)); + $msgfrag = ($msgfraghi << 8) | $msgfraglo; + $msgfragoffs = ($msgfragoffshi << 8) | $msgfragoffslo; + } else { + ($mt, $lenhi, $lenlo) = + unpack('CnC', substr($record->decrypt_data, $recoffset)); + } $messlen = ($lenhi << 8) | $lenlo; - print " Message type: $message_type{$mt}\n"; + print " Message type: $message_type{$mt}($mt)\n"; print " Message Length: $messlen\n"; $startoffset = $recoffset; - $recoffset += 4; + $recoffset += $msgheaderlen; $payload = ""; if ($recoffset <= $record->decrypt_len) { @@ -257,8 +284,9 @@ sub get_messages $messlen); $recoffset += $messlen; push @message_frag_lens, $messlen; - $message = create_message($server, $mt, $payload, - $startoffset); + $message = create_message($server, $mt, $msgseq, + $msgfrag, $msgfragoffs, + $payload, $startoffset, $isdtls); push @messages, $message; $payload = ""; @@ -307,14 +335,18 @@ sub get_messages #construct it sub create_message { - my ($server, $mt, $data, $startoffset) = @_; + my ($server, $mt, $msgseq, $msgfrag, $msgfragoffs, $data, $startoffset, $isdtls) = @_; my $message; #We only support ClientHello in this version...needs to be extended for #others if ($mt == MT_CLIENT_HELLO) { $message = TLSProxy::ClientHello->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -323,7 +355,24 @@ sub create_message $message->parse(); } elsif ($mt == MT_SERVER_HELLO) { $message = TLSProxy::ServerHello->new( + $isdtls, + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + $message->parse(); + } elsif ($mt == MT_HELLO_VERIFY_REQUEST) { + $message = TLSProxy::HelloVerifyRequest->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -332,7 +381,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_ENCRYPTED_EXTENSIONS) { $message = TLSProxy::EncryptedExtensions->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -341,7 +394,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE) { $message = TLSProxy::Certificate->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -350,7 +407,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE_REQUEST) { $message = TLSProxy::CertificateRequest->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -359,7 +420,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_CERTIFICATE_VERIFY) { $message = TLSProxy::CertificateVerify->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -368,7 +433,11 @@ sub create_message $message->parse(); } elsif ($mt == MT_SERVER_KEY_EXCHANGE) { $message = TLSProxy::ServerKeyExchange->new( + $isdtls, $server, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -376,19 +445,36 @@ sub create_message ); $message->parse(); } elsif ($mt == MT_NEW_SESSION_TICKET) { - $message = TLSProxy::NewSessionTicket->new( - $server, - $data, - [@message_rec_list], - $startoffset, - [@message_frag_lens] - ); + if ($isdtls) { + $message = TLSProxy::NewSessionTicket->new_dtls( + $server, + $msgseq, + $msgfrag, + $msgfragoffs, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + } else { + $message = TLSProxy::NewSessionTicket->new( + $server, + $data, + [@message_rec_list], + $startoffset, + [@message_frag_lens] + ); + } $message->parse(); } else { #Unknown message type $message = TLSProxy::Message->new( + $isdtls, $server, $mt, + $msgseq, + $msgfrag, + $msgfragoffs, $data, [@message_rec_list], $startoffset, @@ -423,18 +509,26 @@ sub alert sub new { my $class = shift; - my ($server, + my ($isdtls, + $server, $mt, + $msgseq, + $msgfrag, + $msgfragoffs, $data, $records, $startoffset, $message_frag_lens) = @_; my $self = { + isdtls => $isdtls, server => $server, data => $data, records => $records, mt => $mt, + msgseq => $msgseq, + msgfrag => $msgfrag, + msgfragoffs => $msgfragoffs, startoffset => $startoffset, message_frag_lens => $message_frag_lens, dupext => -1 @@ -463,12 +557,21 @@ sub repack $self->set_message_contents(); - my $lenhi; - my $lenlo; + my $lenlo = length($self->data) & 0xff; + my $lenhi = length($self->data) >> 8; - $lenlo = length($self->data) & 0xff; - $lenhi = length($self->data) >> 8; - $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; + if ($self->{isdtls}) { + my $msgfraghi = $self->msgfrag >> 8; + my $msgfraglo = $self->msgfrag & 0xff; + my $msgfragoffshi = $self->msgfragoffs >> 8; + my $msgfragoffslo = $self->msgfragoffs & 0xff; + + $msgdata = pack('CnCnnCnC', $self->mt, $lenhi, $lenlo, $self->msgseq, + $msgfraghi, $msgfraglo, + $msgfragoffshi, $msgfragoffslo).$self->data; + } else { + $msgdata = pack('CnC', $self->mt, $lenhi, $lenlo).$self->data; + } if ($numrecs == 0) { #The message is fully contained within one record @@ -476,13 +579,14 @@ sub repack my $recdata = $rec->decrypt_data; my $old_length; + my $msg_header_len = $self->{isdtls} ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; # We use empty message_frag_lens to indicates that pre-repacking, # the message wasn't present. The first fragment length doesn't include # the TLS header, so we need to check and compute the right length. if (@{$self->message_frag_lens}) { - $old_length = ${$self->message_frag_lens}[0] + - TLS_MESSAGE_HEADER_LENGTH; + $old_length = ${$self->message_frag_lens}[0] + $msg_header_len; } else { $old_length = 0; } @@ -529,8 +633,7 @@ sub repack $rec->len(length($rec->data)); #Update the fragment len in case we changed it above - ${$self->message_frag_lens}[0] = length($msgdata) - - TLS_MESSAGE_HEADER_LENGTH; + ${$self->message_frag_lens}[0] = length($msgdata) - $msg_header_len; return; } @@ -578,6 +681,30 @@ sub mt } return $self->{mt}; } +sub msgseq +{ + my $self = shift; + if (@_) { + $self->{msgseq} = shift; + } + return $self->{msgseq}; +} +sub msgfrag +{ + my $self = shift; + if (@_) { + $self->{msgfrag} = shift; + } + return $self->{msgfrag}; +} +sub msgfragoffs +{ + my $self = shift; + if (@_) { + $self->{msgfragoffs} = shift; + } + return $self->{msgfragoffs}; +} sub data { my $self = shift; @@ -613,7 +740,9 @@ sub message_frag_lens sub encoded_length { my $self = shift; - return TLS_MESSAGE_HEADER_LENGTH + length($self->data); + my $msg_header_len = $self->{isdtls} ? DTLS_MESSAGE_HEADER_LENGTH + : TLS_MESSAGE_HEADER_LENGTH; + return $msg_header_len + length($self->data); } sub dupext { |