File Coverage

blib/lib/Protocol/TLS/Server.pm
Criterion Covered Total %
statement 53 74 71.6
branch 2 6 33.3
condition 1 3 33.3
subroutine 13 15 86.6
pod 0 2 0.0
total 69 100 69.0


line stmt bran cond sub pod time code
1             package Protocol::TLS::Server;
2 2     2   26917 use strict;
  2         4  
  2         83  
3 2     2   12 use warnings;
  2         3  
  2         49  
4 2     2   9 use Carp;
  2         5  
  2         156  
5 2     2   915 use MIME::Base64;
  2         794  
  2         124  
6 2     2   540 use Protocol::TLS::Trace qw(tracer bin2hex);
  2         9  
  2         109  
7 2     2   569 use Protocol::TLS::Utils qw(load_cert load_priv_key);
  2         4  
  2         107  
8 2     2   678 use Protocol::TLS::Context;
  2         4  
  2         54  
9 2     2   730 use Protocol::TLS::Connection;
  2         5  
  2         79  
10             use Protocol::TLS::Constants
11 2     2   12 qw(cipher_type const_name :versions :ciphers :c_types :end_types :hs_types :state_types :alert_desc);
  2         6  
  2         2622  
12              
13             sub new {
14 2     2 0 1030 my ( $class, %opts ) = @_;
15 2         13 my $self = bless { %opts, sid => {} }, $class;
16 2         11 $self->{cert} = load_cert( $opts{cert_file} );
17 2         8 $self->{key} = load_priv_key( $opts{key_file} );
18 2         11 $self;
19             }
20              
21             sub new_connection {
22 1     1 0 3 my ( $self, %opts ) = @_;
23 1         10 my $ctx = Protocol::TLS::Context->new( type => SERVER );
24 1         4 $ctx->{key} = $self->{key};
25 1         5 $ctx->{cert} = $self->{cert};
26             $ctx->{proposed} = {
27 1         8 ciphers => [
28             TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_NULL_SHA256,
29             TLS_RSA_WITH_NULL_SHA,
30             ],
31             tls_version => TLS_v12,
32             compression => [0],
33             };
34 1         10 my $con = Protocol::TLS::Connection->new($ctx);
35              
36             $ctx->{on_change_state} = sub {
37 3     3   6 my ( $ctx, $prev_state, $new_state ) = @_;
38 3         13 tracer->debug( "State changed from "
39             . const_name( 'state_types', $prev_state ) . " to "
40             . const_name( 'state_types', $new_state )
41             . "\n" );
42 1         9 };
43              
44 1 50       5 if ( exists $opts{on_data} ) {
45 0         0 $ctx->{on_data} = $opts{on_data};
46             }
47              
48             $ctx->state_cb(
49             STATE_HS_START,
50             sub {
51 1     1   2 my $ctx = shift;
52 1         11 my $p = $ctx->{pending};
53 1         3 my $sp = $p->{securityParameters};
54 1         3 my $sid = $p->{session_id};
55              
56             # Resume session
57 1 50 33     8 if ( $sid ne '' && exists $self->{sid}->{$sid} ) {
58 0         0 my $s = $self->{sid}->{$sid};
59 0         0 $p->{tls_version} = $s->{tls_version};
60 0         0 $p->{cipher} = $s->{cipher};
61             $sp->{$_} = $s->{securityParameters}->{$_}
62 0         0 for keys %{ $s->{securityParameters} };
  0         0  
63              
64             # save sid as proposed
65 0         0 $ctx->{proposed}->{session_id} = $sid;
66 0         0 tracer->debug( "Resume session: " . bin2hex($sid) );
67              
68             $ctx->enqueue(
69             [
70             CTYPE_HANDSHAKE,
71             HSTYPE_SERVER_HELLO,
72             {
73             tls_version => $p->{tls_version},
74             server_random => $sp->{server_random},
75             session_id => $sid,
76             cipher => $p->{cipher},
77             compression => $sp->{CompressionMethod}
78             }
79 0         0 ]
80             );
81 0         0 $ctx->enqueue( [CTYPE_CHANGE_CIPHER_SPEC],
82             [ CTYPE_HANDSHAKE, HSTYPE_FINISHED, $ctx->finished ] );
83             }
84              
85             # New session
86             else {
87 1         5 $sid = $p->{session_id} = $ctx->crypto->random(32);
88             $ctx->enqueue(
89             [
90             CTYPE_HANDSHAKE,
91             HSTYPE_SERVER_HELLO,
92             {
93             tls_version => $p->{tls_version},
94             server_random => $sp->{server_random},
95             session_id => $sid,
96             cipher => $p->{cipher},
97             compression => $sp->{CompressionMethod}
98             }
99             ],
100 1         35 [ CTYPE_HANDSHAKE, HSTYPE_CERTIFICATE, $ctx->{cert} ],
101             [ CTYPE_HANDSHAKE, HSTYPE_SERVER_HELLO_DONE ]
102             );
103             }
104             }
105 1         8 );
106              
107             $ctx->state_cb( STATE_HS_FULL,
108             sub {
109 0     0   0 my $ctx = shift;
110 0         0 $ctx->enqueue( [CTYPE_CHANGE_CIPHER_SPEC],
111             [ CTYPE_HANDSHAKE, HSTYPE_FINISHED, $ctx->finished ] );
112             }
113 1         7 );
114              
115             $ctx->state_cb( STATE_OPEN,
116             sub {
117 0     0   0 my $ctx = shift;
118 0         0 my $p = $ctx->{pending};
119              
120             # add sid to server's cache
121 0         0 $self->{sid}->{ $p->{session_id} } = $ctx->copy_pending;
122 0         0 tracer->debug( "Saved sid: " . bin2hex( $p->{session_id} ) );
123 0         0 $ctx->{session_id} = $p->{session_id};
124 0         0 $ctx->{tls_version} = $p->{tls_version};
125 0         0 $ctx->clear_pending;
126              
127             # Handle callbacks
128 0 0       0 if ( exists $opts{on_handshake_finish} ) {
129 0         0 $opts{on_handshake_finish}->($ctx);
130             }
131             }
132 1         7 );
133              
134 1         4 $con;
135             }
136              
137             1
138             __END__