Skip Menu |

This queue is for tickets about the PlRPC CPAN distribution.

Report information
The Basics
Id: 30609
Status: open
Priority: 0/
Queue: PlRPC

People
Owner: Nobody in particular
Requestors: viper.xz [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: (no value)
Fixed in: (no value)



Subject: Two Phase Encryption does not work!
I noticed this bug when running benchmarks to determine the speed difference between using/not using encryption on RPC::PlServer. Summary: ------------------------------------------------ When RPC::PlServer->{'client'} is changed, RPC::PlServer::Comm-> {'cipher'} is not. When RPC::PlClient->{'client'} is changed, RPC::PlClient::Comm-> {'cipher'} is not. Hence Second Phase Encryption does NOT work at all. Full Description: ------------------------------------------------ RPC::PlServer::Comm is created from RPC::PlServer when the server is first setup, hence the value for RPC::PlServer::Comm->{'cipher'} and RPC::PlServer->{'cipher'} are the same. In RPC::PlServer::Accept $self->{'cipher'} is changed to match the user/client's cipher. However RPC::PlServer::Comm->{'cipher'} is NOT changed. Similarly, when RPC::PlClient->{'cipher'} is changed (as per the examples in t/crypt.t and DBI::Proxy) RPC::PlClient::Comm->{'cipher'} is not changed either. Neither Comm->{'cipher'} is modified at a later time, hence both Comm objects still use first phase encryption, even though it appears that it has been changed. i.e. Second phase encryption does not work AT ALL. Solutions: My current solution is as follows: ------------------------------------------------ 1. In RPC::PlClient add the method Cipher, which simply sets both $self->{'cipher'} and $self->{'comm'}->{'cipher'} (attached). This provides better encapsulation and prevents the user from having to know to set both ciphers when changing encryption. 2. In the implementation of the server (i.e. MyServer) override the Accept function to set the value of $self->{'comm'}->{'cipher'} to $self->{'cipher'} after the user authentication has been done (see attached example). A better (but requires more low level changes) method: ------------------------------------------------ 1. Still implement a Cipher method (as encapsulation is good) but only have it set $self->{'cipher'}. 2. Change $self->{'comm'}->{'cipher'} from an object reference, to a reference to a object reference. e.g. In RPC::PlServer::Comm::new you have: if (my $cipher = $attr->{'cipher'}){ $self->{'cipher'} = $cipher; } Changing to: $self->{'cipher'} = \$attr->{'cipher'} And then use: ${$self->{'cipher'}}->method (as the accessor) would make sure any changes to RPC::PlClient->{'cipher'} are automatically known by RPC::PlClient->{'comm'}->{'cipher'} as they share the same variable. Finally: ------------------------------------------------ It would be ideal if after login it were possible to disable authentication for a client (to increase speed). e.g. All clients log in using the cipher specified in MyServer->new (First Phase). When a user from another server logs in their cipher is set to their own (Second Phase). However, when 127.0.0.1 logs in, it is preferable that encryption is disabled (as this increases speed dramtically). I have implemented a workaround by setting the client 127.0.0.1's cipher to -1 (cipher must be a true value to be passed through Accept). At the end of Accept, the -1 is caught and then changed to undef (see example in Accept override (attached)). It would be great if this could be added to RPC::PlServer::Accept to allow a client to disable encryption for their session. e.g. In MyServer: $clients = [ { mask => '^127\.0\.0\.1$', users => ['localhost'], accept => 1, cipher => -1 }, ] At end of RPC::PlServer::Accept: $self->{'cipher'} = undef if ($self->{'cipher'} eq -1); 1;
Subject: rpc-plclient-cipher.txt
sub Cipher { my $self = shift; if (@_){ $self->{'cipher'} = $_[0]; $self->{'comm'}->{'cipher'} = $_[0] if ($self->{'comm'}); } $self->{'cipher'}; }
Subject: rpc-plserver-Accept-override.txt
sub Accept { my ($self) = @_; return 0 if (!$self->SUPER::Accept); # Disable Cipher $self->{'cipher'} = undef if ($self->{'cipher'} eq -1); # Move cipher into comm if ($self->{'cipher'} ne $self->{'comm'}->{'cipher'}){ $self->{'comm'}->{'cipher'} = $self->{'cipher'}; } 1; }
Hello. Sorry, my English is poor. I got this problem too. I think that this solutions are good but this is incomplete. cipher must be changed before login when different cipher was specified in <Host based authorization> and <User based authorization>. For example: http://search.cpan.org/~mnooning/PlRPC-0.2020/lib/RPC/PlServer.pm#CONFIGURATION_FILE Or: ------------------ clients => [ { mask => "^\Q111.222.333.444\E\$", cipher => Crypt::Blowfish->new(pack('H16', 'AAAAAAAAAAAAAAAA')), # Default key for 111.222.333.444 users => [ { name => 'USER1', cipher => Crypt::Blowfish->new(pack('H16', 'BBBBBBBBBBBBBBBB')), # Key for only USER1 from 111.222.333.444 }, { name => 'USER2', cipher => Crypt::Blowfish->new(pack('H16', 'CCCCCCCCCCCCCCCC')), # Key for only USER2 from 111.222.333.444 }, ], accept => 1, }, { mask => '.*', accept => 0 }, ], ------------------ 1. Client access to server. Server recognizes that client is 111.222.333.444 and changes a key into AAAAAAAAAAAAAAAA. 2. Client logs in to server by using USER1(and application, version ...). These information is encrypted by key AAAAAAAAAAAAAAAA. 3. Server decrypts these information by key AAAAAAAAAAAAAAAA, and recognizes that user is USER1 and changes a key into BBBBBBBBBBBBBBBB. Server changes a key before login and after login. I think that it is better to change Accept(). (patch-file attached) $self->{'cipher'} = $cipher; Change to: $self->{'cipher'} = $comm->{'cipher'} = $cipher; And client. I think that Cipher() is very flexible, and good. There are other solution. By default, the client needs only 2(max) keys. And the client knows both keys at start. Then, the client logs in by a key-A, and it can change a key into B if needed. (patch-file attached) The client uses 'cipher_host'(or 'cipher') till login is completed. And the client changes key into 'cipher_user' if it is specified. ------------------ my $client = eval { RPC::PlClient->new( peeraddr => '111.222.333.444', # peerport, application... cipher => Crypt::Blowfish->new(pack('H16', 'AAAAAAAAAAAAAAAA')), # or cipher_host cipher_user => Crypt::Blowfish->new(pack('H16', 'BBBBBBBBBBBBBBBB')), ) }; ------------------
--- PlClient.pm.org 2007-06-18 04:20:20.000000000 +0900 +++ PlClient.pm 2009-11-30 21:14:24.000000000 +0900 @@ -47,7 +47,7 @@ my $self = {@_}; bless($self, (ref($proto) || $proto)); - my $comm = $self->{'comm'} = RPC::PlClient::Comm->new($self); + my $comm = $self->{'comm'} = RPC::PlClient::Comm->new($self, cipher => $self->{'cipher_host'} || $self->{'cipher'}); my $app = $self->{'application'} or $self->Fatal("Missing application name"); my $version = $self->{'version'} or @@ -81,6 +81,10 @@ my $msg = defined($reply->[1]) ? $reply->[1] : ''; die "Refused by server: $msg" unless $reply->[0]; $self->Debug("Logged in, server replies: $msg"); + if ($user && (my $cipher = $self->{'cipher_user'})) { + $self->Debug("User encryption: %s", $cipher); + $comm->{'cipher'} = $cipher; + } return ($self, $msg) if wantarray; $self;
--- PlServer.pm.org 2007-06-18 04:20:30.000000000 +0900 +++ PlServer.pm 2009-11-30 20:07:56.000000000 +0900 @@ -138,7 +138,7 @@ if ($client = $self->{'client'}) { if (my $cipher = $client->{'cipher'}) { $self->Debug("Host encryption: %s", $cipher); - $self->{'cipher'} = $cipher; + $self->{'cipher'} = $comm->{'cipher'} = $cipher; } } @@ -174,7 +174,7 @@ if (my $au = $self->{'authorized_user'}) { if (ref($au) && (my $cipher = $au->{'cipher'})) { $self->Debug("User encryption: %s", $cipher); - $self->{'cipher'} = $cipher; + $self->{'cipher'} = $comm->{'cipher'} = $cipher; } }
This is new patch-file. cipher be disabled by 'cipher => undef'. e.g. localhost(127.0.0.1) or the user who does not send/receive important data. Only the specified user of enabled host becomes disabled.
--- PlClient.pm.org 2007-06-18 04:20:20.000000000 +0900 +++ PlClient.pm 2009-12-01 00:33:28.000000000 +0900 @@ -47,7 +47,7 @@ my $self = {@_}; bless($self, (ref($proto) || $proto)); - my $comm = $self->{'comm'} = RPC::PlClient::Comm->new($self); + my $comm = $self->{'comm'} = RPC::PlClient::Comm->new($self, cipher => $self->{cipher_host} || $self->{cipher}); my $app = $self->{'application'} or $self->Fatal("Missing application name"); my $version = $self->{'version'} or @@ -71,6 +71,7 @@ } $self->Debug("Connected to %s, port %s", $socket->peerhost(), $socket->peerport()); + $self->Debug('Default encryption: %s', $self->{cipher_host} || $self->{cipher} || 'none'); $self->Debug("Sending login message: %s, %s, %s, %s", $app, $version, $user, "x" x length($password)); $comm->Write($socket, [$app, $version, $user, $password]); @@ -81,6 +82,10 @@ my $msg = defined($reply->[1]) ? $reply->[1] : ''; die "Refused by server: $msg" unless $reply->[0]; $self->Debug("Logged in, server replies: $msg"); + if ($user && exists $self->{cipher_user}) { + $self->Debug('User encryption: %s', $self->{cipher_user} || 'none'); + $comm->{cipher} = $self->{cipher_user}; + } return ($self, $msg) if wantarray; $self;
--- PlServer.pm.org 2007-06-18 04:20:30.000000000 +0900 +++ PlServer.pm 2009-12-01 00:25:29.000000000 +0900 @@ -134,11 +134,13 @@ my $socket = $self->{'socket'}; my $comm = $self->{'comm'}; return 0 if (!$self->SUPER::Accept()); + $self->Debug('Default encryption: %s', $self->{cipher} || 'none'); + $comm->{cipher} = $self->{cipher}; # reset for single mode my $client; if ($client = $self->{'client'}) { - if (my $cipher = $client->{'cipher'}) { - $self->Debug("Host encryption: %s", $cipher); - $self->{'cipher'} = $cipher; + if (exists $client->{cipher}) { + $self->Debug('Host encryption: %s', $client->{cipher} || 'none'); + $self->{cipher} = $comm->{cipher} = $client->{cipher}; } } @@ -172,9 +174,9 @@ } $comm->Write($socket, (ref($result) ? $result : [1, "Welcome!"])); if (my $au = $self->{'authorized_user'}) { - if (ref($au) && (my $cipher = $au->{'cipher'})) { - $self->Debug("User encryption: %s", $cipher); - $self->{'cipher'} = $cipher; + if (ref($au) && exists $au->{cipher}) { + $self->Debug('User encryption: %s', $au->{cipher} || 'none'); + $self->{cipher} = $comm->{cipher} = $au->{cipher}; } }
Thank you for the patch, m-uchino. By the way, I am looking for someone to become the new owner of PLRPC and Net::Daemon. I accepted the baton a number of years ago because the then-owner had not upgraded for newer Windows versions, and we could not seem to contact him. Since then, I have not done much with this. The main work has been to fix what I could, and ask others for help when I could not fix things myself. It has seemed pretty stable the last few years. Any takers?