File Coverage

blib/lib/POE/Component/SSLify/NonBlock/ServerHandle.pm
Criterion Covered Total %
statement 12 108 11.1
branch 0 82 0.0
condition n/a
subroutine 4 17 23.5
pod 3 3 100.0
total 19 210 9.0


line stmt bran cond sub pod time code
1             # Declare our package
2             package POE::Component::SSLify::NonBlock::ServerHandle;
3 1     1   10 use strict; use warnings;
  1     1   1  
  1         31  
  1         5  
  1         1  
  1         26  
4            
5             # Initialize our version
6 1     1   5 use vars qw( $VERSION );
  1         2  
  1         55  
7             $VERSION = (qw$LastChangedRevision: 10 $)[1];
8            
9             # Import the SSL death routines
10 1     1   1147 use Net::SSLeay qw( die_now die_if_ssl_error );
  1         20240  
  1         2263  
11            
12             our $globalinfos;
13             our $getserial = 0;
14            
15             # Ties the socket
16             sub TIEHANDLE {
17 0     0     my ( $class, $socket, $ctx, $params ) = @_;
18            
19 0           my $self = bless {
20             'ctx' => $ctx,
21             'socket' => $socket,
22             'fileno' => fileno( $socket ),
23             'acceptstate' => 0,
24             'crypting' => 0,
25             'debug' => $params->{debug},
26             'params' => $params
27             }, $class;
28            
29 0 0         unless ($params->{starttls}) {
30 0           $self->dobeginSSL();
31 0 0         return undef unless $self->HANDLESSL();
32             }
33 0           return $self;
34             }
35            
36             sub dobeginSSL {
37 0     0 1   my $self = shift;
38 0 0         return if ($self->{crypting}++);
39            
40 0 0         $self->{ssl} = Net::SSLeay::new( $self->{ctx} ) or die_now( "Failed to create SSL $!" );
41 0           Net::SSLeay::set_fd( $self->{ssl}, $self->{fileno} );
42            
43 0 0         if ($self->{params}->{clientcertrequest}) {
44 0           my $orfilter = &Net::SSLeay::VERIFY_PEER
45             | &Net::SSLeay::VERIFY_CLIENT_ONCE;
46 0 0         $orfilter |= &Net::SSLeay::VERIFY_FAIL_IF_NO_PEER_CERT unless $self->{params}->{noblockbadclientcert};
47 0           Net::SSLeay::set_verify ($self->{ssl}, $orfilter, \&VERIFY);
48             }
49            
50             # BAD!
51             #my $err = Net::SSLeay::accept( $ssl ) and die_if_ssl_error( 'ssl accept' );
52            
53 0           $globalinfos = [0, 0, []];
54             }
55            
56             # Verifys client certificates
57             sub VERIFY {
58 0     0 1   my ($ok, $x509_store_ctx) = @_;
59             #print "VERIFY!\n";
60 0 0         $globalinfos->[0] = $ok ? 1 : 2 if ($globalinfos->[0] != 2);
    0          
61 0           $globalinfos->[1]++;
62 0 0         if (my $x = Net::SSLeay::X509_STORE_CTX_get_current_cert($x509_store_ctx)) {
63 0 0         push(@{$globalinfos->[2]},[Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($x)),
  0            
64             Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_issuer_name($x)),
65             ($getserial ? Net::SSLeay::X509_get_serialNumber($x) : undef)]);
66             }
67 0           return 1; # $ok; # 1=accept cert, 0=reject
68             }
69            
70             # Process input for OpenSSL
71             sub HANDLESSL {
72 0     0 1   my $self = shift;
73 0           my $rv = Net::SSLeay::accept($self->{ssl});
74 0           $self->{acceptstate} = 0;
75 0 0         $rv == 0 ? $self->{acceptstate} = 0 : $rv > 0 ? $self->{acceptstate} = 3 : 1;
    0          
76 0 0         if ($self->{acceptstate}) {
77 0 0         print "HANDLEACCEPT:SERVER:A:".$self->{acceptstate}.":\n"
78             if ($self->{debug});
79 0 0         if ($self->{acceptstate} > 2) {
80 0           $self->{infos} = [((@$globalinfos)[0..2])];
81 0           $globalinfos = [0, 0, []];
82             }
83 0           return $self->{acceptstate};
84             }
85 0           my $err = Net::SSLeay::get_error($self->{ssl},$rv);
86 0 0         $self->{acceptstate} = $err == Net::SSLeay::ERROR_WANT_READ() ? 1 :
    0          
87             $err == Net::SSLeay::ERROR_WANT_WRITE() ? 2 : 3;
88 0 0         print "HANDLEACCEPT:SERVER:B:".$self->{acceptstate}.":\n"
89             if ($self->{debug});
90 0           return $self->{acceptstate};
91             }
92            
93             # Read something from the socket
94             sub READ {
95             # Get ourself!
96 0     0     my $self = shift;
97 0           my( $buf, $len, $offset ) = \( @_ );
98            
99 0 0         if ($self->{crypting}) {
100             # Get the pointers to buffer, length, and the offset
101            
102 0 0         return -1 unless exists($self->{'acceptstate'});
103            
104 0 0         if ($self->{'acceptstate'} < 3) {
105 0           $self->{'acceptstate'} = $self->HANDLESSL();
106 0 0         if ($self->{'acceptstate'} < 3) {
107 0 0         return -1 unless $self->{'acceptstate'};
108             # Currently we can't read cause we're in handshake!
109 0 0         print "Currently we can't read cause we're in handshake!\n"
110             if ($self->{debug});
111 0           $$buf = "";
112 0           return -2;
113             }
114             }
115            
116             # If we have no offset, replace the buffer with some input
117 0 0         if ( ! defined $$offset ) {
118 0           $$buf = Net::SSLeay::read( $self->{'ssl'}, $$len );
119            
120             # Are we done?
121 0 0         if ( defined $$buf ) {
122 0           return length( $$buf );
123             } else {
124             # Nah, clear the buffer too...
125 0           $$buf = "";
126 0           return;
127             }
128             }
129            
130             # Now, actually read the data
131 0 0         defined( my $read = Net::SSLeay::read( $self->{'ssl'}, $$len ) ) or return undef;
132            
133             # Figure out the buffer and offset
134 0           my $buf_len = length( $$buf );
135            
136             # If our offset is bigger, pad the buffer
137 0 0         if ( $$offset > $buf_len ) {
138 0           $$buf .= chr( 0 ) x ( $$offset - $buf_len );
139             }
140            
141             # Insert what we just read into the buffer
142 0           substr( $$buf, $$offset ) = $read;
143            
144             # All done!
145 0           return length( $read );
146             } else {
147 0 0         return sysread( $self->{'socket'}, $$buf,
    0          
148             (defined($len) ? $$len : undef),
149             (defined($offset) ? $$offset : undef) );
150             }
151             }
152            
153             # Write some stuff to the socket
154             sub WRITE {
155             # Get ourself + buffer + length + offset to write
156 0     0     my( $self, $buf, $len, $offset ) = @_;
157            
158 0 0         if ($self->{crypting}) {
159             # If we have nothing to offset, then start from the beginning
160 0 0         if ( ! defined $offset ) {
161 0           $offset = 0;
162             }
163            
164 0 0         return -1 unless exists($self->{'acceptstate'});
165            
166 0 0         if ($self->{'acceptstate'} < 3) {
167 0           $self->{'acceptstate'} = $self->HANDLESSL();
168 0 0         if ($self->{'acceptstate'} < 3) {
169 0 0         return -1 unless $self->{'acceptstate'};
170             # Currently we can't read cause we're in handshake!
171 0 0         print "Currently we can't read cause we're in handshake!\n"
172             if ($self->{debug});
173 0           return -2;
174             }
175             }
176            
177             # We count the number of characters written to the socket
178 0           my $wrote_len = Net::SSLeay::write( $self->{'ssl'}, substr( $buf, $offset, $len ) );
179            
180             # Did we get an error or number of bytes written?
181             # Net::SSLeay::write() returns the number of bytes written, or -1 on error.
182             #if ( $wrote_len < 0 ) {
183             # The normal syswrite() POE uses expects 0 here.
184             # return 0;
185             #} else {
186             # All done!
187 0           return $wrote_len;
188             #}
189             } else {
190 0           return syswrite( $self->{'socket'}, $buf, $len, $offset );
191             }
192             }
193            
194             # Sets binmode on the socket
195             # Thanks to RT #27117
196             sub BINMODE {
197 0     0     my $self = shift;
198 0 0         if (@_) {
199 0           my $mode = shift;
200 0           binmode $self->{'socket'}, $mode;
201             } else {
202 0           binmode $self->{'socket'};
203             }
204             }
205            
206             # Closes the socket
207             sub CLOSE {
208 0     0     my $self = shift;
209 0 0         if ( defined $self->{'socket'} ) {
210 0           Net::SSLeay::free( $self->{'ssl'} );
211 0           close( $self->{'socket'} );
212 0           undef $self->{'socket'};
213            
214             # do we need to do CTX_free?
215 0 0         if ( exists $self->{'client'} ) {
216 0           Net::SSLeay::CTX_free( $self->{'ctx'} );
217             }
218             }
219            
220 0           return 1;
221             }
222            
223             # Add DESTROY handler
224             sub DESTROY {
225 0     0     my $self = shift;
226            
227             # Did we already CLOSE?
228 0 0         if ( defined $self->{'socket'} ) {
229             # Guess not...
230 0           $self->CLOSE();
231             }
232             }
233            
234             sub FILENO {
235 0     0     my $self = shift;
236 0           return $self->{'fileno'};
237             }
238            
239             # Not implemented TIE's
240             sub READLINE {
241 0     0     die 'Not Implemented';
242             }
243            
244             sub PRINT {
245 0     0     die 'Not Implemented';
246             }
247            
248             # Returns our hash
249             sub _get_self {
250 0     0     my $self = shift;
251 0           return $self;
252             }
253            
254             # End of module
255             1;
256            
257             __END__