package POE::Filter::SSL; use strict; use warnings; use Crypt::MatrixSSL; use base qw( POE::Filter ); use bytes; use Carp qw( croak ); our $VERSION = '0.01'; sub DEBUG() { 0 } sub BUFFER_IN () { 0 } sub BUFFER_OUT () { 1 } sub KEY_FILE () { 2 } sub CERT_FILE () { 3 } sub MODE () { 4 } sub SSL () { 5 } sub OFFSET () { 6 } sub KEYS () { 7 } sub HANDSHAKE_FIN () { 8 } sub new { my $class = shift; croak "$class requires an even number of parameters" if @_ % 2; my %ops = @_; my $self = bless( [ '', # 0 BUFFER_IN '', # 1 BUFFER_OUT undef, # 2 KEY_FILE undef, # 3 CERT_FILE 0, # 4 MODE undef, # 5 SSL 0, # 6 OFFSET undef, # 7 KEYS undef, # 8 HANDSHAKE_FIN ], ref $class || $class ); $self->[ KEY_FILE ] = $ops{key_file} if ( $ops{key_file} ); $self->[ CERT_FILE ] = $ops{cert_file} if ( $ops{cert_file} ); matrixSslOpen() == 0 or die __PACKAGE__.'::matrixSslOpen'; matrixSslReadKeys( $self->[ KEYS ], $self->[ CERT_FILE ], $self->[ KEY_FILE ], undef, undef ) == 0 or die __PACKAGE__.'::matrixSslReadKeys'; # SSL_FLAGS_SERVER is imported matrixSslNewSession( $self->[ SSL ], $self->[ KEYS ], undef, $SSL_FLAGS_SERVER ) == 0 or die __PACKAGE__.'::matrixSslNewSession'; return $self; } sub get_one_start { my ($self, $blocks) = @_; $blocks = [ $blocks ] unless ( ref( $blocks ) ); my $out = join( '', @$blocks ); $self->[ BUFFER_IN ] .= $out; DEBUG && do { my @dump; while (length $out) { my $line = substr($out, 0, 16, ''); my $hexdump = unpack 'H*', $line; $hexdump =~ s/(..)/$1 /g; $line =~ tr[ -~][.]c; push(@dump, sprintf( "%04x %-47.47s - %s\n", $self->[ OFFSET ], $hexdump, $line ) ); $self->[ OFFSET ] += 16; } warn "start:".join('',@dump); }; return; } sub emits_oob { 1; } sub get_one { my $self = shift; my $oob = shift; die __PACKAGE__." can't be used without an OOB data ref, you nee the newest version of POE" unless ( ref $oob ); my $arr = []; my ( $out, $err ); while ( length $self->[ BUFFER_IN ] ) { my ( $alevel, $adesc ); my $data_out = ''; my $ret = matrixSslDecode( $self->[ SSL ], $self->[ BUFFER_IN ], $data_out, $err, $alevel, $adesc ); if ( $ret == $SSL_PROCESS_DATA ) { $self->[ MODE ] = 1; DEBUG && warn "ssl process"; push( @$arr, $data_out ); next; } else { DEBUG && warn "ssl oob data"; push( @$oob, bless( \$data_out, 'POE::OOB::put' ) ); return []; } if ( $ret == $SSL_SUCCESS || $ret == $SSL_SEND_RESPONSE ) { DEBUG && warn "ssl success, or send response"; #$self->[ HANDSHAKE_FIN ] ||= matrixSslHandshakeIsComplete( $self->[ SSL ] ); } elsif ( $ret == $SSL_ERROR ) { warn __PACKAGE__." Error: [$err] $SSL_alertDescription{ $err }"; last; } elsif ( $ret == $SSL_ALERT ) { warn sprintf( __PACKAGE__.": Alert! alertLevel: [%d] %s\n". " alertDescription: [%d] %s\n", $alevel, $SSL_alertLevel{ $alevel }, $adesc, $SSL_alertDescription{ $adesc } ); last; } elsif ( $ret == $SSL_PARTIAL ) { last; } else { warn __PACKAGE__.": Unexpected ret code [$ret]\n"; } } return $arr; } sub put { my ($self, $blocks) = @_; my $data = join( '', @$blocks ); $self->[ BUFFER_OUT ] .= $data; return [] unless ( $self->[ HANDSHAKE_FIN ] || $self->[ MODE ] ); my @out; while ( length $self->[ BUFFER_OUT ] ) { my $s = substr( $self->[ BUFFER_OUT ], 0, $SSL_MAX_PLAINTEXT_LEN, '' ); my $encoded = ''; matrixSslEncode( $self->[ SSL ], $s, $encoded ) >= 0 or die __PACKAGE__.' - matrixSslEncode Error'; push( @out, $encoded ); } return \@out; } sub get_pending { # FIXME return ''; } 1; __END__