File Coverage

blib/lib/POE/Filter/SSL.pm
Criterion Covered Total %
statement 48 411 11.6
branch 0 266 0.0
condition 0 109 0.0
subroutine 9 45 20.0
pod 23 23 100.0
total 80 854 9.3


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