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   11 use strict;
  2         2  
  2         74  
3 2     2   10 use warnings;
  2         3  
  2         60  
4 2     2   17 use Protocol::TLS::Constants qw(:end_types :alert_desc const_name);
  2         3  
  2         545  
5 2     2   12 use Protocol::TLS::Trace qw(tracer bin2hex);
  2         3  
  2         1711  
6              
7             sub decode {
8 20     20 0 67 my ( $ctx, $type, $version, $buf_ref, $buf_offset, $length ) = @_;
9 20         53 my $sp = $ctx->{current_decode}->{securityParameters};
10 20         29 my $kb = $ctx->{current_decode}->{key_block};
11              
12 20         75 my $crypto = $ctx->crypto;
13 20         21 my $res;
14              
15 20 50       87 my ( $mkey, $ckey, $iv ) =
    100          
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             );
27              
28 20 100 66     83 if ( defined $ckey && length $ckey ) {
29 9 50       29 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         21 my $iv = substr $$buf_ref, $buf_offset, $sp->{fixed_iv_length};
34 9         60 $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             );
41 9         434 my $pad_len = unpack 'C', substr $res, -1, 1;
42 9 50       34 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         67 my $pad = substr $res, -$pad_len - 1, $pad_len + 1, '';
49             }
50              
51 20 100 66     85 if ( defined $mkey && length $mkey ) {
52 9 50       21 unless ( defined $res ) {
53 0         0 $res = substr $$buf_ref, $buf_offset, $length;
54             }
55              
56 9         23 my $mac = substr $res, -$sp->{mac_length}, $sp->{mac_length}, '';
57              
58 9         17 my $seq = $ctx->{seq_read}++;
59 9         60 my $mac_orig = $crypto->MAC(
60             $sp->{MACAlgorithm}, $mkey,
61              
62             # TODO: seq may overflow int32
63             pack( 'N2Cn2', 0, $seq, $type, $version, length $res ) . $res
64             );
65 9 50       404 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       113 $res ? $res : substr $$buf_ref, $buf_offset, $length;
81             }
82              
83             sub encode {
84 20     20 0 67 my ( $ctx, $version, $type, $payload ) = @_;
85 20         40 my $sp = $ctx->{current_encode}->{securityParameters};
86 20         30 my $kb = $ctx->{current_encode}->{key_block};
87 20         56 my $crypto = $ctx->crypto;
88              
89 20 50       89 my ( $mkey, $ckey, $iv ) =
    100          
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             );
101              
102 20         47 my ( $mac, $res ) = ('') x 2;
103              
104 20 100 66     110 if ( defined $mkey && length $mkey ) {
105 9         20 my $seq = $ctx->{seq_write}++;
106 9         66 $mac = $crypto->MAC( $sp->{MACAlgorithm}, $mkey,
107             pack( 'N2Cn2', 0, $seq, $type, $version, length $payload )
108             . $payload );
109             }
110              
111 20 100 66     504 if ( defined $ckey && length $ckey ) {
112 9 50       24 if ( $sp->{CipherType} eq 'block' ) {
113 9         29 my $pad_len =
114             $sp->{block_length} -
115             ( ( length($payload) + length($mac) + 1 ) % $sp->{block_length} );
116 9         31 my $iv = $crypto->random( $sp->{fixed_iv_length} );
117 9         201 $res = $iv
118             . $crypto->CBC_encode( $sp->{BulkCipherAlgorithm},
119             $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       382 $res ? $res : $payload . $mac;
128             }
129              
130             1