File Coverage

blib/lib/Protocol/TLS/Protection.pm
Criterion Covered Total %
statement 47 57 82.4
branch 23 30 76.6
condition 8 12 66.6
subroutine 6 6 100.0
pod 0 2 0.0
total 84 107 78.5


line stmt bran cond sub pod time code
1             package Protocol::TLS::Protection;
2 2     2   10 use strict;
  2         4  
  2         57  
3 2     2   10 use warnings;
  2         5  
  2         56  
4 2     2   11 use Protocol::TLS::Constants qw(:end_types :alert_desc const_name);
  2         4  
  2         588  
5 2     2   13 use Protocol::TLS::Trace qw(tracer bin2hex);
  2         4  
  2         1797  
6              
7             sub decode {
8 20     20 0 55 my ( $ctx, $type, $version, $buf_ref, $buf_offset, $length ) = @_;
9 20         63 my $sp = $ctx->{current_decode}->{securityParameters};
10 20         47 my $kb = $ctx->{current_decode}->{key_block};
11              
12 20         90 my $crypto = $ctx->crypto;
13 20         33 my $res;
14              
15             my ( $mkey, $ckey, $iv ) =
16             !defined $sp ? ()
17             : $sp->{connectionEnd} == SERVER ? (
18             $kb->{client_write_MAC_key},
19             $kb->{client_write_encryption_key},
20             $kb->{client_write_IV}
21             )
22             : (
23             $kb->{server_write_MAC_key},
24             $kb->{server_write_encryption_key},
25             $kb->{server_write_IV}
26 20 50       407 );
    100          
27              
28 20 100 66     117 if ( defined $ckey && length $ckey ) {
29 9 50       37 if ( $length < $sp->{fixed_iv_length} + $sp->{block_length} ) {
30 0         0 tracer->debug("too short ciphertext: $length\n");
31 0         0 return undef;
32             }
33 9         28 my $iv = substr $$buf_ref, $buf_offset, $sp->{fixed_iv_length};
34             $res = $crypto->CBC_decode(
35             $sp->{BulkCipherAlgorithm},
36             $ckey, $iv,
37             substr $$buf_ref,
38             $buf_offset + $sp->{fixed_iv_length},
39             $length - $sp->{fixed_iv_length}
40 9         83 );
41 9         538 my $pad_len = unpack 'C', substr $res, -1, 1;
42 9 50       40 if ( $pad_len >= $length + 1 + $sp->{mac_length} ) {
43 0         0 tracer->error("Padding length $pad_len too long");
44 0         0 return undef;
45             }
46              
47             # TODO: check padding
48 9         42 my $pad = substr $res, -$pad_len - 1, $pad_len + 1, '';
49             }
50              
51 20 100 66     99 if ( defined $mkey && length $mkey ) {
52 9 50       26 unless ( defined $res ) {
53 0         0 $res = substr $$buf_ref, $buf_offset, $length;
54             }
55              
56 9         31 my $mac = substr $res, -$sp->{mac_length}, $sp->{mac_length}, '';
57              
58 9         28 my $seq = $ctx->{seq_read}++;
59             my $mac_orig = $crypto->MAC(
60 9         87 $sp->{MACAlgorithm}, $mkey,
61              
62             # TODO: seq may overflow int32
63             pack( 'N2Cn2', 0, $seq, $type, $version, length $res ) . $res
64             );
65 9 50       502 if ( $mac ne $mac_orig ) {
66 0         0 tracer->error("error in comparing MAC\n");
67 0         0 tracer->debug( const_name( "c_types", $type )
68             . " <- type of broken packet.\nLength: $length\n"
69             . "mkey: "
70             . bin2hex($mkey) . "\n" . "mac: "
71             . bin2hex($mac) . "\n"
72             . "mac_orig: "
73             . bin2hex($mac_orig)
74             . "\n" );
75 0         0 $ctx->error(BAD_RECORD_MAC);
76 0         0 return undef;
77             }
78             }
79              
80 20 100       133 $res ? $res : substr $$buf_ref, $buf_offset, $length;
81             }
82              
83             sub encode {
84 20     20 0 54 my ( $ctx, $version, $type, $payload ) = @_;
85 20         49 my $sp = $ctx->{current_encode}->{securityParameters};
86 20         39 my $kb = $ctx->{current_encode}->{key_block};
87 20         71 my $crypto = $ctx->crypto;
88              
89             my ( $mkey, $ckey, $iv ) =
90             !defined $sp ? ()
91             : $sp->{connectionEnd} == CLIENT ? (
92             $kb->{client_write_MAC_key},
93             $kb->{client_write_encryption_key},
94             $kb->{client_write_IV}
95             )
96             : (
97             $kb->{server_write_MAC_key},
98             $kb->{server_write_encryption_key},
99             $kb->{server_write_IV}
100 20 50       98 );
    100          
101              
102 20         55 my ( $mac, $res ) = ('') x 2;
103              
104 20 100 66     108 if ( defined $mkey && length $mkey ) {
105 9         19 my $seq = $ctx->{seq_write}++;
106 9         72 $mac = $crypto->MAC( $sp->{MACAlgorithm}, $mkey,
107             pack( 'N2Cn2', 0, $seq, $type, $version, length $payload )
108             . $payload );
109             }
110              
111 20 100 66     488 if ( defined $ckey && length $ckey ) {
112 9 50       35 if ( $sp->{CipherType} eq 'block' ) {
113             my $pad_len =
114             $sp->{block_length} -
115 9         31 ( ( length($payload) + length($mac) + 1 ) % $sp->{block_length} );
116 9         44 my $iv = $crypto->random( $sp->{fixed_iv_length} );
117             $res = $iv
118             . $crypto->CBC_encode( $sp->{BulkCipherAlgorithm},
119 9         260 $ckey, $iv,
120             $payload . $mac . pack( 'C', $pad_len ) x ( $pad_len + 1 ) );
121             }
122             else {
123 0         0 die "Cipher type $sp->{CipherType} not implemented";
124             }
125             }
126              
127 20 100       516 $res ? $res : $payload . $mac;
128             }
129              
130             1