File Coverage

blib/lib/POE/Filter/SSL.pm
Criterion Covered Total %
statement 48 381 12.6
branch 0 258 0.0
condition 0 113 0.0
subroutine 10 41 24.3
pod 23 23 100.0
total 81 816 9.9


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