| 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__ |