File Coverage

blib/lib/POE/Filter/SSL.pm
Criterion Covered Total %
statement 48 399 12.0
branch 0 254 0.0
condition 0 91 0.0
subroutine 9 45 20.0
pod 23 23 100.0
total 80 812 9.8


line stmt bran cond sub pod time code
1             package POE::Filter::SSL;
2              
3 1     1   58447 use strict;
  1         2  
  1         27  
4 1     1   395 use Net::SSLeay;
  1         18266  
  1         82  
5 1     1   607 use POE qw (Filter::HTTPD Filter::Stackable Wheel::ReadWrite);
  1         31882  
  1         7  
6 1     1   96326 use Scalar::Util qw(blessed);
  1         4  
  1         82  
7 1     1   20 use Carp qw(carp confess);
  1         3  
  1         185  
8 1     1   57 use POE;
  1         4  
  1         10  
9              
10 1     1   649 use vars qw($VERSION @ISA);
  1         4  
  1         275  
11             $VERSION = '0.36';
12             sub DOSENDBACK () { 1 }
13              
14             our $globalinfos;
15             my $debug = 0;
16              
17             my $PATCH = 18;
18             my $HANDSHAKE = 19;
19             my $EVENT_FLUSHED = 20;
20             my $EVENT_INPUT = 21;
21              
22             BEGIN {
23 1     1   6 eval {
24 1         9 require Net::SSLeay;
25 1         1800 Net::SSLeay->import( 1.30 );
26             };
27 1         2085 Net::SSLeay::load_error_strings();
28 1         104 Net::SSLeay::SSLeay_add_ssl_algorithms();
29 1         16 Net::SSLeay::randomize();
30              
31 1     1   10 no warnings 'redefine';
  1         4  
  1         2421  
32 1         1097 my $old_new = \&POE::Wheel::ReadWrite::new;
33 1         4 my $old_set_filter = \&POE::Wheel::ReadWrite::set_filter;
34 1         5 my $old_set_input_filter = \&POE::Wheel::ReadWrite::set_input_filter;
35 1         3 my $old_set_output_filter = \&POE::Wheel::ReadWrite::set_output_filter;
36 1         3 my $old_rw_put = \&POE::Wheel::ReadWrite::put;
37             *POE::Wheel::ReadWrite::put = sub {
38 0     0   0 my $self = shift;
39 0         0 my $unique_id = $self->[POE::Wheel::ReadWrite::UNIQUE_ID()];
40 0 0       0 if (defined($self->[$EVENT_FLUSHED])) {
41 0         0 $self->[POE::Wheel::ReadWrite::EVENT_FLUSHED] = $self->[$EVENT_FLUSHED];
42 0         0 $self->[$EVENT_FLUSHED] = undef;
43             }
44 0         0 $old_rw_put->($self, @_);
45 1         12 };
46             *POE::Wheel::ReadWrite::new = sub {
47 0     0   0 my $class = shift;
48 0         0 my %arg = @_;
49 0         0 my $self = $old_new->($class,%arg);
50 0         0 my $unique_id = $self->[POE::Wheel::ReadWrite::UNIQUE_ID];
51 0         0 $self->[$EVENT_INPUT] = $self->[POE::Wheel::ReadWrite::EVENT_INPUT];
52 0         0 $self->[POE::Wheel::ReadWrite::EVENT_INPUT] = ref($self) . "($unique_id) -> ssl handshake";
53 0         0 my $flushed_event = \$self->[POE::Wheel::ReadWrite::EVENT_FLUSHED];
54 0         0 my $temp_flushed_event = \$self->[$EVENT_FLUSHED];
55 0         0 my $temp_event_input = \$self->[$EVENT_INPUT];
56 0         0 my $filter_output = \$self->[POE::Wheel::ReadWrite::FILTER_OUTPUT];
57 0         0 my $driver = \$self->[POE::Wheel::ReadWrite::DRIVER_BOTH];
58 0         0 my $handle_output = \$self->[POE::Wheel::ReadWrite::HANDLE_OUTPUT];
59             $poe_kernel->state(
60             $self->[$HANDSHAKE] = ref($self) . "($unique_id) -> ssl handshake",
61             sub {
62 0 0   0   0 if (checkForDoSendback($_[ARG0])) {
63 0 0       0 unless (defined($$temp_flushed_event)) {
64 0         0 $$temp_flushed_event = $$flushed_event;
65 0         0 $$flushed_event = undef;
66             }
67 0         0 $$driver->put($$filter_output->put([$_[ARG0]]));
68 0         0 $poe_kernel->select_resume_write($$handle_output);
69             } else {
70 0         0 $poe_kernel->call($_[SESSION], $$temp_event_input, $_[ARG0], $_[ARG1]);
71             }
72             }
73 0         0 );
74             $poe_kernel->state(
75             $self->[$PATCH] = ref($self) . "($unique_id) -> ssl patch",
76             sub {
77 0     0   0 my $type = $_[ARG0];
78 0         0 my $self = $_[ARG1];
79 0 0       0 if ($_[HEAP]->{self}->{PreFilter}) {
80             $_[HEAP]->{self}->{"PreFilter".ref($self).$self->[POE::Wheel::ReadWrite::UNIQUE_ID()]} = $_[HEAP]->{self}->{PreFilter}->clone()
81 0 0       0 unless ($_[HEAP]->{self}->{"PreFilter".ref($self).$self->[POE::Wheel::ReadWrite::UNIQUE_ID()]});
82 0 0       0 if ($type eq "input") {
83             $old_set_input_filter->($self, POE::Filter::Stackable->new(
84             Filters => [
85 0         0 $_[HEAP]->{self}->{"PreFilter".ref($self).$self->[POE::Wheel::ReadWrite::UNIQUE_ID()]},
86             $self->get_input_filter()
87             ]
88             ));
89             } else {
90             $old_set_output_filter->($self, POE::Filter::Stackable->new(
91             Filters => [
92 0         0 $_[HEAP]->{self}->{"PreFilter".ref($self).$self->[POE::Wheel::ReadWrite::UNIQUE_ID()]},
93             $self->get_output_filter()
94             ]
95             ));
96             }
97             }
98             }
99 0         0 );
100 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "input" => $self);
101 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "output" => $self);
102 0         0 return $self;
103 1         12 };
104 1         4 my $old_destroy = \&POE::Wheel::ReadWrite::DESTROY;
105             *POE::Wheel::ReadWrite::DESTROY = sub {
106 0     0   0 my $self = shift;
107 0 0       0 if ($self->[$PATCH]) {
108 0         0 $poe_kernel->state($self->[$PATCH]);
109 0         0 $self->[$PATCH] = undef;
110             }
111 0 0       0 if ($self->[$HANDSHAKE]) {
112 0         0 $poe_kernel->state($self->[$HANDSHAKE]);
113 0         0 $self->[$HANDSHAKE] = undef;
114             }
115 0         0 return $old_destroy->($self, @_);
116 1         8 };
117             *POE::Wheel::ReadWrite::set_filter = sub {
118 0     0   0 my $self = shift;
119 0         0 my $new_filter = shift;
120 0         0 my $unique_id = $self->[POE::Wheel::ReadWrite::UNIQUE_ID()];
121 0         0 my $ret = $old_set_filter->($self, $new_filter, @_);
122 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "input" => $self);
123 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "output" => $self);
124 0         0 return $ret;
125 1         6 };
126             *POE::Wheel::ReadWrite::set_input_filter = sub {
127 0     0   0 my $self = shift;
128 0         0 my $new_filter = shift;
129 0         0 my $unique_id = $self->[POE::Wheel::ReadWrite::UNIQUE_ID()];
130 0         0 my $ret = $old_set_input_filter->($self, $new_filter, @_);
131 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "input" => $self);
132 0         0 return $ret;
133 1         9 };
134             *POE::Wheel::ReadWrite::set_output_filter = sub {
135 0     0   0 my $self = shift;
136 0         0 my $new_filter = shift;
137 0         0 my $unique_id = $self->[POE::Wheel::ReadWrite::UNIQUE_ID()];
138 0         0 my $ret = $old_set_output_filter->($self, $new_filter, @_);
139 0         0 $poe_kernel->yield(ref($self) . "($unique_id) -> ssl patch" => "output" => $self);
140 0         0 return $ret;
141 1         8 };
142             #my $old_get_one = \&POE::Filter::Stackable::get_one;
143             *POE::Filter::Stackable::get_one = sub {
144 0     0   0 my ($self) = @_;
145 0         0 my $return = [ ];
146 0         0 while (!@$return) {
147 0         0 my $exchanged = 0;
148 0         0 foreach my $filter (@{$self->[POE::Filter::Stackable::FILTERS]}) {
  0         0  
149             # If we have something to input to the next filter, do that.
150 0 0       0 if (@$return) {
151 0         0 $filter->get_one_start($return);
152 0         0 $exchanged++;
153             }
154             # Get what we can from the current filter.
155 0         0 $return = $filter->get_one();
156             # This is the only inserted line:
157 0 0 0     0 return $return if (checkForDoSendback($return) && ($return->[0] eq $filter));
158             }
159 0 0       0 last unless $exchanged;
160             }
161 0         0 return $return;
162 1         28 };
163 1         5 my $old_get_one_start = \&POE::Filter::Stackable::get_one_start;
164             *POE::Filter::Stackable::get_one_start = sub {
165 0     0   0 my $self = shift;
166 0 0       0 (exists($self->[POE::Filter::Stackable::FILTERS]->[0])) ? $old_get_one_start->($self, @_) : []
167 1         7 };
168 1         4 my $old_put = \&POE::Filter::Stackable::put;
169             *POE::Filter::Stackable::put = sub {
170 0     0   0 my $self = shift;
171 0         0 my $data = shift;
172 0         0 my $found = 0;
173 0 0       0 if (checkForDoSendback($data)) {
174 0         0 foreach my $filter (@{$self->[POE::Filter::Stackable::FILTERS]}) {
  0         0  
175 0 0       0 if ($data->[0] eq $filter) {
176 0         0 $found++;
177 0         0 last;
178             }
179             }
180             }
181 0 0       0 if ($found) {
182 0         0 my $ok = 0;
183 0         0 foreach my $filter (reverse @{$self->[POE::Filter::Stackable::FILTERS]}) {
  0         0  
184 0 0 0     0 next unless ($ok || (($filter eq $data->[0]) && checkForDoSendback($data)));
      0        
185 0         0 $ok++;
186 0         0 $data = $filter->put($data);
187 0 0       0 last unless @$data;
188             }
189 0         0 $data;
190             } else {
191 0         0 $old_put->($self, $data, @_);
192             }
193 1         8 };
194             *POE::Filter::HTTPD::get_pending = sub {
195 0     0     return undef;
196             }
197 1         5686 }
198              
199             require XSLoader;
200             XSLoader::load('POE::Filter::SSL', $VERSION);
201              
202             sub checkForDoSendback {
203 0     0 1   my $chunks = shift;
204 0 0 0       $chunks = $chunks->[0] if ((ref($chunks) eq "ARRAY") &&
205             (scalar(@$chunks)));
206 0 0 0       return 1 if (blessed($chunks) &&
      0        
207             ($chunks->can("DOSENDBACK")) &&
208             ($chunks->DOSENDBACK()));
209 0           return 0;
210             }
211              
212             sub PEMdataToX509 {
213 0     0 1   my $x509 = shift;
214 0           my $bio = dataToBio($x509);
215 0           my $x509result = undef;
216 0 0         die "Error using x509: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
217             unless ($x509result = Net::SSLeay::PEM_read_bio_X509($bio));
218 0           Net::SSLeay::BIO_free($bio);
219 0           return $x509result;
220             }
221              
222             sub PEMdataToEVP_PKEY {
223 0     0 1   my $ssl = shift;
224 0           my $crt = shift;
225 0           my $bio = dataToBio($crt);
226 0           my $evp_pkey = undef;
227 0 0         die "Error using cacrt: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
228             unless ($evp_pkey = Net::SSLeay::PEM_read_bio_PrivateKey($bio));
229 0           Net::SSLeay::BIO_free($bio);
230 0           return $evp_pkey;
231             }
232              
233             sub CTX_add_client_CA {
234 0     0 1   my $ctx = shift;
235 0           my $x509 = shift;
236 0           my $ssl = shift;
237 0           my $err = Net::SSLeay::X509_STORE_add_cert(Net::SSLeay::CTX_get_cert_store($ctx), PEMdataToX509($x509));
238 0 0 0       die "Error using cacrt: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
239             if ($err && ($err != 1));
240 0           $err = Net::SSLeay::CTX_add_client_CA($ctx, PEMdataToX509($x509));
241 0 0 0       die "Error using cacrt: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
242             if ($err && ($err != 1));
243             }
244              
245             sub dataToBio {
246 0     0 1   my $data = shift;
247 0           my $bio = Net::SSLeay::BIO_new(Net::SSLeay::BIO_s_mem());
248 0           my $sent = Net::SSLeay::BIO_write($bio, $data);
249 0 0         print "Wrote ".$sent." of ".length($data)." bytes.\n"
250             if $debug;
251 0 0         die "Cannot write to bio!"
252             if (($sent) != length($data));
253 0           return $bio;
254             }
255              
256             sub new {
257 0     0 1   my $type = shift;
258 0           my $params = {@_};
259 0           my $self = bless({}, $type);
260 0           $self->{buffer} = '';
261 0   0       $self->{debug} = $params->{debug} || 0;
262             $self->{cacrl} = $params->{cacrl}
263 0 0         if $self->{cacrl};
264 0   0       $self->{client} = $params->{client} || 0;
265 0           $self->{errorhandler} = $params->{errorhandler};
266 0           $self->{params} = $params;
267              
268             $self->{context} =
269             ($params->{tls} || $params->{tls1_2}) ?
270             ($params->{tls1_2} ?
271 0 0 0       Net::SSLeay::CTX_tlsv1_2_new() :
    0          
272             Net::SSLeay::CTX_tlsv1_new()) :
273             Net::SSLeay::CTX_new();
274              
275             Net::SSLeay::CTX_set_options($self->{context}, 0x00400000) # SSL_OP_CIPHER_SERVER_PREFERENCE # Beim Apache: SSLHonorCipherOrder
276 0 0 0       if ((!$self->{client}) && (!$params->{"nohonor"}));
277              
278 0           my $err = undef;
279 0 0         if ($params->{chain}) {
280 0           $err = Net::SSLeay::CTX_use_certificate_chain_file($self->{context}, $params->{chain});
281 0 0 0       die "Error using chain: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
282             if ($err && ($err != 1));
283             } else {
284 0 0         if ($params->{keymem}) {
285 0           $err = Net::SSLeay::CTX_use_PrivateKey($self->{context}, PEMdataToEVP_PKEY($self->{ssl}, $params->{keymem}));
286             print "Loaded keymem(".length($params->{keymem})." Bytes) with result ".$err."\n"
287 0 0         if $self->{debug};
288             } else {
289 0           $err = Net::SSLeay::CTX_use_PrivateKey_file($self->{context}, $params->{key}, &Net::SSLeay::FILETYPE_PEM);
290             print "Loaded key from file ".$params->{key}." with result ".$err."\n"
291 0 0         if $self->{debug};
292             }
293 0 0 0       die "Error using keymem: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
294             if ($err && ($err != 1));
295 0 0         if ($params->{crtmem}) {
296 0           my $crt = PEMdataToX509($params->{crtmem});
297 0           $err = Net::SSLeay::CTX_use_certificate($self->{context}, $crt);
298             print "Loaded crtmem(".length($params->{crtmem})." Bytes/".$crt.") with result ".$err."\n"
299 0 0         if $self->{debug};
300             } else {
301             # TODO:XXX:FIXME: Errorchecking!
302 0           $err = Net::SSLeay::CTX_use_certificate_file($self->{context}, $params->{crt}, &Net::SSLeay::FILETYPE_PEM);
303             print "Loaded crt from file ".$params->{crt}." with result ".$err."\n"
304 0 0         if $self->{debug};
305             }
306 0 0 0       die "Error using crtmem: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
307             if ($err && ($err != 1));
308             }
309              
310 0           $err = undef;
311 0 0 0       if ($params->{cacrt}||
312             $params->{cacrtmem}) {
313 0 0         if ($params->{cacrtmem}) {
314 0 0         if (ref($params->{cacrtmem}) eq "ARRAY") {
315 0           foreach my $curcert (@{$params->{cacrtmem}}) {
  0            
316 0           $err = CTX_add_client_CA($self->{context}, $curcert, $self->{ssl});
317             last
318 0 0         unless $err;
319             }
320             } else {
321 0           $err = CTX_add_client_CA($self->{context}, $params->{cacrtmem}, $self->{ssl});
322             print "Loaded cacrtmem(".length($params->{cacrtmem})." Bytes) with result ".$err."\n"
323 0 0         if $self->{debug};
324             }
325             } else {
326 0           $err = Net::SSLeay::CTX_load_verify_locations($self->{context}, $params->{cacrt}, '');
327             print "Loaded cacrt from file ".$params->{cacrt}." with result ".$err."\n"
328 0 0         if $self->{debug};
329 0 0 0       $err = Net::SSLeay::CTX_set_client_CA_list($self->{context}, Net::SSLeay::load_client_CA_file($params->{cacrt}))
330             unless ($err && ($err == 1));
331             print "Set client cacrt from file ".$params->{cacrt}." with result ".$err."\n"
332 0 0         if $self->{debug};
333             }
334 0 0 0       $err = Net::SSLeay::CTX_set_verify_depth($self->{context}, $params->{caverifydepth} || 5)
      0        
335             unless ($err && ($err == 1));
336             }
337 0 0 0       die "Error using cacrt: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
338             if ($err && ($err != 1));
339              
340 0           $err = undef;
341             $err = Net::SSLeay::CTX_set_cipher_list($self->{context}, $params->{cipher})
342 0 0         if ($params->{cipher});
343 0 0 0       die "Error setting cipher: ".Net::SSLeay::ERR_error_string(ERR_get_error())
344             if ($err && ($err != 1));
345              
346 0           $err = undef;
347 0 0         $self->{rbio} = Net::SSLeay::BIO_new(Net::SSLeay::BIO_s_mem())
348             or die("Error creating r BIO: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()));
349 0 0         $self->{wbio} = Net::SSLeay::BIO_new(Net::SSLeay::BIO_s_mem())
350             or die("Error creating w BIO: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()));
351 0           $self->{ssl} = Net::SSLeay::new($self->{context});
352 0           $err = Net::SSLeay::set_bio($self->{ssl}, $self->{rbio}, $self->{wbio});
353 0 0 0       die "Error setting r/w BIOs: ".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
354             if ($err && ($err != 1));
355              
356 0 0 0       if ($params->{dhcert} ||
357             $params->{dhcertmem}) {
358 0           my $dhbio = undef;
359 0 0         if ($params->{dhcertmem}) {
360 0           $dhbio = dataToBio($params->{dhcertmem});
361             } else {
362             die "Cannot open dhcert file!"
363 0 0 0       unless ((-s $params->{dhcert}) && ($dhbio = Net::SSLeay::BIO_new_file($params->{dhcert}, "r")));
364             }
365             # TODO:XXX:FIXME: Errorchecking!
366 0           my $dhret = Net::SSLeay::PEM_read_bio_DHparams($dhbio);
367             print "Loaded dhcert with result ".$err."\n"
368 0 0         if $self->{debug};
369 0           Net::SSLeay::BIO_free($dhbio);
370             die "Couldn't set DH parameters!"
371 0 0         if (SSL_set_tmp_dh($self->{ssl}, $dhret) < 0);
372             print "Set dhcert params with result ".$err."\n"
373 0 0         if $self->{debug};
374             #die "Couldn't set CTX DH parameters!"
375             # if (SSL_CTX_set_tmp_dh($self->{context}, $dhret) < 0);
376             # TODO:XXX:FIXME: Errorchecking!
377 0           my $rsa = Net::SSLeay::RSA_generate_key(2048, 73);
378             #die "Couldn't set RSA key!"
379             # if (!Net::SSLeay::set_tmp_rsa($self->{ssl}, $rsa));
380             die "Couldn't set RSA key!"
381 0 0         if (!SSL_CTX_set_tmp_rsa($self->{context}, $rsa));
382             print "Set dhrsa with result ".$err."\n"
383 0 0         if $self->{debug};
384 0           Net::SSLeay::RSA_free($rsa);
385             }
386 0           my $orfilter = &Net::SSLeay::VERIFY_PEER;
387             $orfilter |= &Net::SSLeay::VERIFY_CLIENT_ONCE
388 0 0         if $params->{clientcert};
389             $orfilter |= &Net::SSLeay::VERIFY_FAIL_IF_NO_PEER_CERT
390 0 0         if $params->{blockbadclientcert};
391             # TODO:XXX:FIXME: Errorchecking!
392 0           Net::SSLeay::set_verify($self->{ssl}, $orfilter, \&VERIFY);
393 0           Net::SSLeay::CTX_set_verify($self->{context}, $orfilter, \&VERIFY);
394 0 0         print "Set verify ".($params->{blockbadclientcert} ? "FORCE" : "")." ".$orfilter."\n"
    0          
395             if $debug;
396 0 0         if ($params->{sni}) {
397 0           my $err = Net::SSLeay::set_tlsext_host_name($self->{ssl}, $params->{sni});
398             print "Set sni with result ".$err."\n"
399 0 0         if $self->{debug};
400 0 0 0       die "Error setting sni:".Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error())
401             if ($err && ($err != 1));
402             }
403            
404 0           $globalinfos = [0, 0, []];
405              
406 0           $self
407             }
408              
409             sub VERIFY {
410 0     0 1   my ($ok, $x509_store_ctx) = @_;
411 0 0         print "VERIFY ".$ok."!\n" if $debug;
412 0 0         $globalinfos->[0] = $ok ? 1 : 2 if ($globalinfos->[0] != 2);
    0          
413 0           $globalinfos->[1]++;
414             # TODO:XXX:FIXME: Chainlength check
415             #X509_STORE_CTX_set_error($x509_store_ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG)
416             # if (X509_STORE_CTX_get_error_depth(ctx) > uuu);
417             # TODO:XXX:FIXME: No globalconfig
418             # ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
419             # mydata = SSL_get_ex_data(ssl, mydata_index);
420 0 0         if (my $x = Net::SSLeay::X509_STORE_CTX_get_current_cert($x509_store_ctx)) {
421 0           push(@{$globalinfos->[2]},[Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($x)),
  0            
422             Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_issuer_name($x)),
423             X509_get_serialNumber($x),
424             Net::SSLeay::X509_STORE_CTX_get_error($x509_store_ctx)]);
425             }
426 0           return 1; # $ok; # 1=accept cert, 0=reject
427             }
428              
429             sub clone {
430 0     0 1   my $self = shift;
431 0           return POE::Filter::SSL->new(%{$self->{params}});
  0            
432             }
433              
434             sub get_one_start {
435 0     0 1   my ($self, $data) = @_;
436 0 0         print "GETONESTART: NETWORK -> SSL -> POE: ".hexdump(join("", @$data))."\n" if $debug;
437 0 0         $self->writeToSSLBIO(join("", @$data), $self->{accepted} ? 0 : 1);
438 0           []
439             }
440              
441             sub get_one {
442 0     0 1   my $self = shift;
443 0 0         print "GETONE: BEGIN\n" if $debug;
444 0           my @return = ();
445 0 0 0       push(@return, $self) if ($self->doSSL() || $self->{buffer});
446 0           my $data = Net::SSLeay::read($self->{ssl});
447 0 0         push(@return, $data) if $data;
448 0 0         print "GETONE: END: ".scalar(@return)."\n" if $debug;
449 0           [@return]
450             }
451              
452             sub get {
453 0 0   0 1   print "GET: BEGIN\n" if $debug;
454 0           my ($self, $chunks) = @_;
455 0           my @return = ();
456             #print "GET:\n" if $debug;
457 0 0 0       push(@return, $self) if ($self->doSSL() || $self->{buffer});
458 0           foreach my $data (@$chunks) {
459 0 0         print "GET: NETWORK -> SSL -> POE: ".join("", @$data)."\n" if $debug;
460 0           $self->writeToSSLBIO(join("", @$data));
461 0           my $data = Net::SSLeay::read($self->{ssl});
462 0 0         print "GET: Read ".length($data)." bytes.\n" if $debug;
463 0           push(@return, $data);
464             }
465 0           [@return]
466             }
467              
468             sub put {
469 0     0 1   my ($self, $chunks) = @_;
470 0 0         print "PUT: BEGIN\n" if $debug;
471 0           my @return = ();
472 0           $self->doSSL();
473 0 0         if ($self->{accepted}) {
474 0 0         if (defined($self->{sendbuf})) {
475 0           foreach my $cdata (@{$self->{sendbuf}}) {
  0            
476 0           $self->writeToSSL($cdata);
477             }
478 0           delete($self->{sendbuf});
479             }
480             }
481 0           foreach my $data (@$chunks) {
482 0 0         next if (ref($data) eq "POE::Filter::SSL");
483 0 0         print "PUT: POE -> SSL -> NETWORK: ".$data."\r\n" if $debug;
484 0 0         if ($self->{accepted}) {
485 0           $self->writeToSSL($data);
486             } else {
487 0 0         push(@{$self->{sendbuf}}, $data) if ($data);
  0            
488             }
489             }
490 0 0         push(@return, $self->{buffer}) if $self->{buffer};
491 0           $self->{buffer} = '';
492 0           [@return]
493             }
494              
495             sub writeToSSL {
496 0     0 1   my $self = shift;
497 0           my $data = shift;
498 0 0         if ((my $sent = Net::SSLeay::write($self->{ssl}, $data)) != length($data)) {
499 0           my $err2 = Net::SSLeay::get_error($self->{ssl}, $sent);
500             #die("PUT: Not all data given to SSL(".$err2."): ".$sent." != ".length($data)) if ($sent);
501             }
502 0           $self->doSSL();
503             }
504              
505             sub writeToSSLBIO {
506 0     0 1   my $self = shift;
507 0           my $data = shift;
508 0           my $nodoSSL = shift;
509 0 0         if ((my $sent = Net::SSLeay::BIO_write($self->{rbio}, $data)) != length($data)) {
510 0           my $err2 = Net::SSLeay::get_error($self->{ssl}, $sent);
511             #die("GET: Not all data given to BIO SSL(".$err2."): ".$sent." != ".length($data)) if ($sent);
512             }
513 0 0         $self->doSSL() unless $nodoSSL;
514             }
515              
516             sub get_pending {
517 0     0 1   return undef;
518             }
519              
520             sub doSSL {
521 0     0 1   my $self = shift;
522 0           my $ret = 0;
523 0 0         print "SSLing..." if $debug;
524 0 0         unless ($self->{accepted}) {
525             my $err = $self->{client} ?
526             Net::SSLeay::connect($self->{ssl}) :
527 0 0         Net::SSLeay::accept($self->{ssl});
528 0 0         if ($err == 1) {
529 0           $self->{infos} = [((@$globalinfos)[0..2])];
530 0           $globalinfos = [0, 0, []];
531 0           $self->{accepted}++;
532 0           $ret++;
533             } else {
534 0           my $errtext = $!;
535 0           my $err2 = Net::SSLeay::get_error($self->{ssl}, $err);
536 0 0         unless ($err2 == Net::SSLeay::ERROR_WANT_READ()) {
537 0 0         my $tmp = "POE::Filter::SSL: ".($self->{client} ? "connect" : "accept").": ";
538 0           my $err3 = undef;
539 0 0         if ($err3 = Net::SSLeay::ERR_get_error()) {
540 0           $tmp .= Net::SSLeay::ERR_error_string($err3)."(".$err3.", ".$err2.")";
541             } else {
542 0           $tmp .= "No error (return=".$err2.")";
543             }
544 0 0         if (defined($self->{errorhandler})) {
545 0 0         if (ref($self->{errorhandler}) eq "CODE") {
    0          
    0          
    0          
    0          
546             $self->{errorhandler}($self, {
547             ssl => $self->{ssl},
548 0           msg => $tmp,
549             ret => $err,
550             get_error => $err2,
551             error => $err3,
552             });
553             } elsif(lc($self->{errorhandler}) eq "ignore") {
554             } elsif(lc($self->{errorhandler}) eq "carp") {
555 0           carp($tmp);
556             } elsif(lc($self->{errorhandler}) eq "confess") {
557 0           confess($tmp);
558             } elsif(lc($self->{errorhandler}) eq "carponetime") {
559             carp($tmp)
560 0 0 0       unless $self->{errorstat}->{$err||"-"}->{$err2||"-"}->{$err3||"-"}++;
      0        
      0        
561             }
562             } else {
563 0           carp($tmp);
564             }
565             $ret++
566 0 0         unless $self->{accepted}++;
567             }
568             }
569             }
570 0           while (my $data = Net::SSLeay::BIO_read($self->{wbio})) {
571 0           $self->{buffer} .= $data;
572             }
573 0 0         print $ret."\n" if $debug;
574 0           return $ret;
575             }
576              
577             sub getCipher {
578 0     0 1   my $self = shift;
579 0           return Net::SSLeay::get_cipher($self->{ssl});
580             }
581              
582             sub clientCertExists {
583 0     0 1   my $self = shift;
584 0   0       return ((ref($self->{infos}) eq "ARRAY") && ($self->{infos}->[1]));
585             }
586              
587             sub clientCertValid {
588 0     0 1   my $self = shift;
589 0           my $valid = 1;
590 0 0         if (defined($self->{cacrl})) {
591 0 0         $valid = $self->clientCertNotOnCRL($self->{cacrl}) ? 1 : 0;
592             }
593 0 0 0       return $self->clientCertExists() ? (($self->{infos}->[0] ne "2") && scalar(@{$self->{infos}->[2]}) && $valid) : undef;
594             }
595              
596             sub clientCertIds {
597 0     0 1   my $self = shift;
598 0 0         return $self->clientCertExists ? @{$self->{infos}->[2]} : undef;
  0            
599             }
600              
601             sub clientCertNotOnCRL {
602 0     0 1   my $self = shift;
603 0           my $crlfilename = shift;
604 0           my @certids = $self->clientCertIds();
605 0 0         if (scalar(@certids)) {
606 0           my $found = 0;
607 0           my $badcrls = 0;
608 0           my $jump = 0;
609 0 0         print("----- SSL Infos BEGIN ---------------"."\n") if $self->{debug};
610 0           foreach (@{$self->{infos}->[2]}) {
  0            
611 0           my $crlstatus = verify_serial_against_crl_file($crlfilename, $_->[2]);
612 0 0         $badcrls++ if $crlstatus;
613 0 0         $crlstatus = $crlstatus ? "INVALID (".($crlstatus !~ m,^CRL:, ? $self->hexdump($crlstatus) : $crlstatus).")" : "VALID";
    0          
614 0           my $t = (" " x $jump++);
615 0 0         if (ref($_) eq "ARRAY") {
616 0 0         if ($self->{debug}){
617 0 0         print(" ".$t." |---[ Subcertificate ]---\n") if $t;
618 0           print(" ".$t." | Subject Name: ".$_->[0]."\n");
619 0           print(" ".$t." | Issuer Name : ".$_->[1]."\n");
620 0           print(" ".$t." | Serial : ".$self->hexdump($_->[2])."\n");
621 0           print(" ".$t." | CRL Status : ".$crlstatus."\n");
622             }
623             } else {
624 0 0         print(" NOCERTINFOS!"."\n") if $self->{debug};
625 0           return 0;
626             }
627             }
628 0 0         print("----- SSL Infos END -----------------"."\n") if $self->{debug};
629 0 0         return 1 unless $badcrls;
630             }
631 0           return 0;
632             }
633              
634             sub handshakeDone {
635 0     0 1   my $self = shift;
636 0           my $params = {@_};
637 0   0       return ($self->{accepted} && (($params->{ignorebuf}) || ((!$self->{sendbuf}) && (!$self->{buffer})))) || 0;
638             }
639              
640             sub DESTROY {
641 0     0     my $self = shift;
642             Net::SSLeay::free($self->{ssl})
643 0 0         if $self->{ssl};
644             Net::SSLeay::CTX_free($self->{context})
645 0 0         if $self->{context};
646             #Net::SSLeay::BIO_free($self->{bio}) # CTX_free automatically frees BIO!!!
647             # if $self->{bio};
648             }
649              
650 0     0 1   sub hexdump { my $self = shift; join ':', map { sprintf "%02X", $_ } unpack "C*", $_[0]; }
  0            
  0            
651              
652             1;
653              
654             __END__