Perl IO::Socket::SSL with web server hang - perl

I've got a problem when using IO::Socket::SSL.
Everything works fine under normal operation but I had an issue where the web server (IIS) locked up and Perl got stuck, even after the web server became active again.
I'm running the Perl script as an exe under Windows and I can't actually see the program running as it is hidden - here is the code:
sub api_action
{
$api_action = $_[0];
use IO::Socket::SSL;
$EOL = "\015\012";
$BLANK = $EOL x 2;
$remote = IO::Socket::SSL->new( Proto => "tcp",
PeerAddr => "api.xxxxx",
PeerPort => "443",
SSL_verify_mode => SSL_VERIFY_NONE,
verify_hostname => 0,
Timeout => 120,
);
unless ($remote) { print "cannot connect to API\n"; return "ERROR"
}
$remote->autoflush(1);
print $remote "GET /API/?action=$api_action" . $BLANK;
return <$remote>;
close $remote;
}
My thought is that it has made the initial connection, but is still waiting for a return from the GET command. I would have thought setting the Timeout would just cause it to return the error but it doesn't look like it works.
Any ideas on where I'm going wrong or what I've missed?

You actually send this to the server inside the SSL connection:
GET /path\r\n
\r\n
This is no valid HTTP/1.0 or HTTP/1.1 request but a HTTP/0.9 request. Since HTTP/0.9 is obsolete since 20 years I would not expect to IIS still support this old protocol so it might just show unexpected behavior when confronted with such a request. A proper HTTP/1.0 request would look like this:
GET /path HTTP/1.0\r\n
Host: www.example.com\r\n
\r\n
For more information on how to send proper requests and how to properly deal with the response see the HTTP/1.0 and HTTP/1.1 standards.
Apart from that:
SSL_verify_mode => SSL_VERIFY_NONE,
verify_hostname => 0,
verify_hostname has no meaning in IO::Socket::SSL. You probably saw this with LWP::UserAgent and it is only relevant there.
Everything works fine under normal operation but I had an issue where the web server (IIS) locked up and Perl got stuck, even after the web server became active again.
Unfortunately this is not usable as an error description because it is unclear what you consider as "locked up" and "active again" but essentially if the server behaves erratically then the client might be affected by this.
Currently your are dealing with the request by reading until end of TCP connection. If the server behaves erratically and will not close this connection then you will wait forever.
Note, that the timeout you set might only be relevant for the initial connect and not for further reads. And it might not even work properly on Windows depending on the version of IO::Socket::SSL you use. You might instead add a alarm(60) or similar to make sure that the client does not wait forever on a broken server or you might try to work with non-blocking sockets to deal with the issue.

Related

IO::Socket::SSL - establishing client connection

As per the documentation of IO::Socket::SSL (PERL) I understand that if I want to just send command to specific server-program that running on port 9999 on my host, Ican do it this way:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
# Something about certificates?
$cl->syswrite("Command");
close($cl);
}
But the error I get is: "SSL connect attempt failed with unknown error error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol at blabla.cgi line 888"
The server initialized thi way (in another pl program):
use IO::Socket::SSL;
use Net::WebSocket::Server;
my $CON={};
my #crt=&SSLCerts(); die 'E101' if(#crt==0);
my $ssl=IO::Socket::SSL->new(
Listen => 10000,
Timeout => 45,
LocalPort => 9999,
Proto => 'tcp',
SSL_cert_file => "$EF::Base/ssl/certs/$crt[0][0].crt",
SSL_key_file => "$EF::Base/ssl/keys/$crt[1][0].key"
) or die "E102: $!";
Net::WebSocket::Server->new(
listen => $ssl,
silence_max=> 3600,
tick_period => 5,
on_tick => sub {
# Empty for now
},
on_connect => sub {
my($serv,$conn)=#_; my($cid,$sid);
$conn->on(
handshake => sub {
my($cnc,$hdk)=#_;
my $nsn=$hdk->req->resource_name;
$cid=substr($nsn,4,index($nsn,'&L=')-4);
$CON->{$cid}=$cnc; # Register incomming connection
},
binary => sub {
# Handle incomming message from the client
},
disconnect => sub {
delete $CON->{$cid};
}
);
}
)->start;
Typical Websocket client that is connecting from the browser via "wss://" connects without any trouble.... The server MUST be SSL...
Here I am just trying to do the same from within perl.
What I am doing wrong? Nothing mentioned about certificates in client, only in server - the server is working fine. Maybe configuration? I have purchased SSL certificates and I use them for the server that running ok on that port.
The host is Linux (CentOS - if it matters).
... SSL23_GET_SERVER_HELLO:unknown protocol
This is the kind of error you get if the client tries to do a SSL handshake and the server responds with something which is not SSL. Typically this happens if you connect to a server which is not (properly) SSL enabled (at least not on this port) or requires some plain text to upgrade to SSL (like in case of SMTP STARTTLS and similar).
This kind of error has usually nothing to do with certificates.
This kind of error can only happen if you try to do an SSL handshake on an already established SSL socket but the server does not expect this. This seems to happen in your case:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
...
The SSL connection is already being established by IO::Socket::SSL->new. This is the same with IO::Socket::INET or similar: if the target is given it will already connect inside new and an additional connect or connect_SSL should not be done. This is also reflected in the documentation and examples.
Since version 2.045 (released 02/2017) IO::Socket::SSL will simply ignore a connect_SSL if the SSL handshake is already done. You are likely using an older version of IO::Socket::SSL where connect_SSL will start a new handshake even if the TLS handshake was already finished. This handshake inside the TLS connection will result in the strange error you see.

Perl Webservice SSL Negotiation Failure

I am trying to call a web service using ssl. It gives following error:
500 SSL negotiation failed:
I searched forums and applied offered methods but none of them worked.
2 methods I applied are listed below:
1-) setting enviroment before call:
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
2-) passing parameter ssl_opts => [ SSL_verify_mode => 0 ] to proxy:
my $soap = SOAP::Lite
-> on_action( .... )
-> uri($uri)
-> proxy($proxy, ssl_opts => [ SSL_verify_mode => 0 ])
-> ns("http://schemas.xmlsoap.org/soap/envelope/","soapenv")
-> ns("http://tempuri.org/","tem");
$soap->serializer()->encodingStyle(undef);
Is there any solution for this?
... Connection reset by peer at /usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi/Net‌​/SSL.pm line 145
You are running a very old version of Perl (from 2004) together with an old version of the SSL libraries (i.e. Crypt::SSLeay instead of IO::Socket::SSL) and my guess is that this goes together with using a very old version of the OpenSSL libraries for TLS support. This combination means that there is no support for SNI, no support for TLS 1.2 and no support for ECDHE ciphers. Many modern servers need at least one of these things supported. But connection reset by peer could also mean that some firewall is blocking connections or that there is no server listening on the endpoint you've specified. Or it could mean that the server is expecting you to authorize with a client certificate. Hard to tell but with a packet capture of the connection one might provide more information. And, if the URL is publicly accessible publishing it would help too in debugging the problem.

500 SSL negotiation failed

I have a new-onset problem on my Windows XP Pro system, demonstrated by the Perl code below (which is, of course, a very cut down example from a much larger program).
It used to work until a few days ago, and I'm pulling my hair out trying to figure out what might have changed on the system to stop it working, and I'm hoping someone here might be able to give me some clues. (It still works fine on my Windows 8.1 system.)
The issue is that the code below (now) fails with "500 SSL negotiation failed".
use strict;
use warnings;
use HTTP::Request;
use LWP::UserAgent;
$ENV{HTTPS_DEBUG} = 1;
my $url = "https://secure.quksdns4.net:2087/";
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new (GET => $url);
my $res = $ua->request($req);
my $sts = $res->code;
my $hdr = $res->headers_as_string;
my $txt = $res->content;
print "\n".$sts."\n\n".$hdr."\n";
print $txt if ($sts == 500);
exit;
The output is:
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:error in SSLv2/v3 read server hello A
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL3 alert read:fatal:handshake failure
SSL_connect:failed in SSLv3 read server hello A
SSL_connect:before/connect initialization
SSL_connect:SSLv2 write client hello A
SSL_connect:error in SSLv2 read server hello A
500
Content-Type: text/plain
Client-Date: Sat, 25 Oct 2014 14:52:43 GMT
Client-Warning: Internal response
500 SSL negotiation failed:
Curiously however it works (albeit not very usefully!) if the port number (:2087) is removed.
Active Perl v5.8.8 (which I haven't changed in years), ssleay32 & libeay32 dlls are 0.9.8.1 (also unchanged in years), and while there's a few on the system those in C:\Perl\bin are the only ones in the path.
Any hints as to what might have changed to stop the above working gratefully received!
In short: I guess the peer just disabled SSL 3.0 (at least on port 2087) because of the POODLE attack and because you are still using really old software on an unsupported OS you still attempt to connect with SSL 3.0.
Edit: It looks like version 0.57 of Crypt::SSLeay (needed for LWP at this time) used already SSLv23 handshakes which should in theory be compatible with TLS 1.x. This can also be seen in the debug output (SSLv2/v3 write client hello). So I guess that the reasons might be at least one of the following:
You are using an openssl version without support for TLS1.0. You give as the version number 0.9.8.1, but this kind of version never existed. Either you mean 0.9.8l which looks similar (and supported TLS1.0) or you mean something completely different.
They not only removed SSL 3.0 from the peer, but also straightened the ciphers so that it now requires ciphers which your old OpenSSL does not support yet.
Or they not only require TLS 1.0+ but TLS 1.1+. But support for TLS1.1 is only included since OpenSSL version 1.0.1.

500 SSL read timeout error in LWP perl

I have a perl script which will post HTTP request to specified server URL (Say: http://some-ip/here_action_url ). My problem is, Sometimes I am getting the below error.
Error:
500 SSL read timeout.
Sample Code:
my $ua = new LWP::UserAgent;
$ua->timeout(30);
my $res = $ua->post( $url, { 'data' => $my_data } );
if(! $res->is_success ) {
# Error Logging
print $res->status_line."\n";
}
else {
$response_content = $res->content;
}
I read about the error. Most of the documents are saying that it is because of the response delay in server side.
I just want to confirm, whether this error is coming because of server response delay? (or) Can be the problem with my perl script?
If you get a result some of the time, and the error at other times, then it looks like your code is working.
If you alway get the 500 error, it indicates a connection problem. Would need to know more about the service you are trying to connect to, does it require certificates or other authentication (which may be needed for secure socket layer connection)

LWP refuses to connect via HTTPS

I am running the following Perl snippet on Debian using Perl v5.14.2 and libwww-perl v6.04-1
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new("GET", "https://google.com/");
my $rep = $ua->request($req);
print $rep->status_line;
This instantly returns "500 Can't connect to google.com:443". I have tried using LWP::Simple, Net::SSLeay, Crypt::SSLeay, etc. without any success.
Oddly enough, executing the same code on another Debian system running exactly the same Perl and LWP versions works.
So I thought, there is some error with the underlying system, but other applications - like cURL for any browser - are working fine.
Also, openssl s_client -connect google.com:443 returns Verify return code: 20 (unable to get local issuer certificate) on both systems.
Has anyone ever encountered this phenomenon and has a solution?
Instead of this:
$ua = LWP::UserAgent->new;
Try to use this:
$ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
FYI for others battling LWP 500 erors:
Some LWP 500 errors are apparently caused by another type of SSL problem (which isn't solved with the verify_hostname setting). Instead, LWP may be communicating with the HTTPS server, but the response is not what LWP expects. In my case, the solution was to force SSLv3, by the following means:
my %ssl_options = (SSL_version => 'SSLv3');
$ua = LWP::UserAgent->new(ssl_opts => \%ssl_options),
Also, for anyone trying to figure out what kind of 500 error you are getting, output this along with your error:
print $response->as_string;
For my problem (solved by setting SSLv3), my $response->as_string output included:
"SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert unexpected message LWP"
I'll also say that my code ran fine for years on an earlier version of Ubuntu. This problem only appeared once I upgraded Ubuntu. I've concluded that there are probably multiple ways that newer versions of LWP differ from older ones, so developers beware!
Good luck solving your LWP problem!
I had this issue on Windows Server 2003 with Strawberry Perl. The error 500 was a problem with IO::Socket::IP.
Performing a re-install of the module (in cpan, force install IO::Socket::IP) resolved the issue.