IO::Socket::SSL fails with IIS 8.5 - perl

Following script runs successfully when run with Perl CLI ( Windows). But when run through IIS 8.5, it fails.
use IO::Socket::SSL;
print <<EOP;
Content-type: text/html
<html><body>
<h1>Hello world</h1>
EOP
print "</body></html>\n";
Error message is
502 - Web server received an invalid response while acting as a
gateway or proxy server.
When "use IO::Socket::SSL" line is deleted, it is successfully executed.
With "use IO::Socket", it is too successfully executed.
Is there something wrong with my IIS / CGI configuration?
Thank you for your help.

I added directory containing libcrypto-1_1-x64__.dll file into system PATH and rebooted the machine. It solved my issue.

Related

Soap perl and ssl certificate changed

I have a perl code that sends SOAP request through SOAP::Lite like this:
eval
{
$sresp = SOAP::Lite
->uri('http://machine/key')
->proxy('https://usr:pwd#website.com/addr/addr/remotescript.pl')
->remotescript_pl_function(#parms, $gmtime);
};
if ($#)
{
print $#;
}
After existing certificate for *.website.com has been replaced I am not getting valid responses anymore, I am getting
500 Can\'t connect to website.com:443 at localscript.pl line 123.
If I enable
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
everything works. But I would like to verify the SSL hostname, how can I do that, or track down the problem? (I am a little lost in this proxying).
I have c++ code with libcurl that goes along the same lines and works well. Entering https://website.com into browser works fine. Entering http://machine (machine is on local network) works.
edit 1:
Both perl -MIO::Socket::SSL=debug4 yourscript.pl and analyze-ssl.pl from p5-ssl-tools show error message 1416F086 which lead me to information that SSL certificate has "Chain issues" that have to be fixed in certificate installation.
edit 2:
After fix of the certificate is the error gone! Perfect, solved!
Here is solution mentioned in comments by Corion and Steffen Ullrich:
Running either:
https://github.com/noxxi/p5-ssl-tools script analyze-ssl.pl
perl -MIO::Socket::SSL=debug4 yourscript.pl
displayed same error: SSL connect attempt failed error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed. This pointed me to: telegram bot SSL error: SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed} where I found that I too have "Chain issues Incomplete".
After fixing certificate the error is gone.

LWP Won't Run in CGI Script

I have a CGI script to load publications from BibBase:
#!/usr/bin/perl
use LWP::UserAgent;
my $url = 'https://bibbase.org/show?bib=http://www.example.com/pubs.bib';
my $ua = LWP::UserAgent->new;
my $can_accept = HTTP::Message::decodable;
my $response = $ua->get($url, 'Accept-Encoding' => $can_accept);
print "Content-type: text/html\n\n";
print $response->decoded_content;
(This is copied from BibBase with the exception that the URL is hard-coded.)
I have three webservers running RHEL7 and Apache 2.4 that are configured the same way by Puppet. On all three I can run the script on the command line and get the expected results:
[root#server1 cgi-bin]# ./bibbase_proxy2.cgi | head
Content-type: text/html
<img src="//bibbase.org/img/ajax-loader.gif" id="spinner" style="display: none;" alt="Loading.." />
<div id="bibbase">
<script type="text/javascript">
var bibbase = {
params: {"bib":"http://www.example.com/pubs.bib","host":"bibbase.org"},
When I try to run the script with CGI, I get three different results:
Server1
Unrecognised protocol tcp at /usr/share/perl5/LWP/Protocol/http.pm line 31.
Server2
Can't connect to bibbase.org:443 System error at /usr/share/perl5/LWP/Protocol/http.pm line 51.
Server3
No http output and the error log says AH01215: Out of memory!.
I can't find anything different between the three servers and I can't figure out why the script works fine on the command line and doesn't work when run as a CGI.
I have selinux in permissive mode and it is logging the outgoing request, so I know the script gets that far:
type=AVC msg=audit(1532465859.921:331235): avc: denied { name_connect } for pid=161178 comm="perl" dest=80 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket
For testing, I have set selinux to disabled and restarted the server.
SE-Linux denied the TCP connection.
avc: denied { name_connect }
The default access controls for networking by SELinux are based on the labels assigned to TCP and UDP ports and sockets. For instance, the TCP port 80 is labeled with http_port_t (and class tcp_socket). Access towards this port is then governed through SELinux access controls, such as name_connect and name_bind.
When an application is connecting to a port, the name_connect permission is checked. However, when an application binds to the port, the name_bind permission is checked.
Permissive mode or not, Perl is acting like it was denied a TCP connection. Unrecognised protocol tcp means getprotobyname("tcp") failed inside IO::Socket::IP. That's very, very unusual. One of the ways that can happen is via exactly that SELinux denial.
I'm no SELinux expert, but according to RedHat and Gentoo some SELinux aware applications will ignore the global permissive setting and go it alone. RHEL 7 Apache appears to be one of them. It appears to have its own domain which must be set permissive.
On all three I can run the script on the command line and get the expected results:
There's two reasons for that, and they both have to do with users.
When you run the program you're running as your own user with your own configuration, permissions, and environment variables. In fact, you ran it as root which usually bypasses restrictions. When it runs on the server it runs as a different user, probably the web server user with severe restrictions.
In order to do a realistic test, you need to run it as the same user the web server will. You can use sudo -u for this. For example, if the user is apache...
sudo -u apache ./bibbase_proxy2.cgi
BTW Do not test software as root! Not only is it not going to give you sensible results, but if there's a bug in the software there are no safeguards preventing it from wrecking your system.
The second problem is #!/usr/bin/env perl. That means to run whatever perl is in your PATH. PATH will be different for different users. Running ./bibbase_proxy2.cgi may run with one Perl on the command line and a different one via the web server.
In a server environment, use a hard coded path to Perl like #!/usr/bin/perl.
We tested by rewriting the same script in Python and PHP. Both of them showed error which pointed us in the right direction.
Python urllib2 produced the error
<class 'urllib2.URLError'>: <urlopen error [Errno 16] Device or resource busy>
args = (error(16, 'Device or resource busy'),)
errno = None
filename = None
message = ''
reason = error(16, 'Device or resource busy')
strerror = None
PHP (run as CGI) wouldn't even start:
[Wed Jul 25 15:24:52.988582 2018] [cgi:error] [pid 10369] [client 172.28.6.200:44387] AH01215: PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/curl.so' - libssh2.so.1: failed to map segment from shared object: Cannot allocate memory in Unknown on line 0
[Wed Jul 25 15:24:52.988980 2018] [cgi:error] [pid 10369] [client 172.28.6.200:44387] AH01215: PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/dba.so' - libtokyocabinet.so.9: failed to map segment from shared object: Cannot allocate memory in Unknown on line 0
---- Similar lines for all extensions. ----
It appears that RLimitMEM blocks access to shared memory and that is required for opening sockets. I can't find any documentation, but removing that line makes it work.

Perl https proxy problems

I can't seem to get https through a proxy.
Example:
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->proxy('https', 'https://proxy:8080');
# $ua->proxy(['https'], 'https://proxy:8080'); # Fails
# $ua->env_proxy; # This also fails.
my $response = $ua->get('https://aws.amazon.com/cloudwatch/');
if ($response->is_success) {
print $response->decoded_content; # or whatever
}
else {
die $response->status_line;
}
Result:
500 Can't connect to aws.amazon.com:443 (timeout) at test.pl line 17.
But if I try the same proxy with curl (also wget) it works just fine.
$ curl --head --proxy https://proxy:8080 https://aws.amazon.com/cloudwatch/
HTTP/1.1 200 Connection established
HTTP/1.1 200 OK
Server: Server
Date: Thu, 08 Dec 2016 16:42:01 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 214187
Perl versions
$ perl -MLWP -le "print(LWP->VERSION)"
6.15
$ perl --version
This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi
I also tried with and without these:
export HTTPS_VERSION=3
export PERL_NET_HTTPS_SSL_SOCKET_CLASS="Net::SSL"
export PERL_LWP_ENV_PROXY=1
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
My actual goal here is to get aws-scripts-mon working on a machine behind a proxy but it also uses LWP::UserAgent so if I get this working then that will probably also.
Added info
It turns out that if I change to http by
$ua->proxy('http', 'http://proxy:8080'); and accesses a http url then it works just fine. The problem is that I need this to work with https.
The error from mon-put-instance-data.pl is:
./mon-put-instance-data.pl --mem-util --disk-space-util --disk-path=/
ERROR: Failed to call CloudWatch: HTTP 500. Message: Can't connect to monitoring.eu-west-1.amazonaws.com:443 (timeout)
LWP::Protocol::https::Socket: connect: timeout at /usr/local/share/perl5/LWP/Protocol/http.pm line 47.
Try LWP::Protocol::connect found in https://stackoverflow.com/a/17787133/44620
use LWP::UserAgent;
$ua = LWP::UserAgent->new();
$ua->proxy('https', 'connect://proxyhost.domain:3128/');
$ua->get('https://www.somesslsite.com');
$ua->proxy('https', 'https://proxy:8080');
LWP does not support the use of HTTP proxies which are accessed using HTTPS. But my guess is that your proxy does not gets access with HTTPS at all, i.e. it gets accessed with HTTP even though it proxies HTTPS requests(*). Thus the code should instead use a http:// URL to access the proxy and not a https:// URL:
$ua->proxy('https', 'http://proxy:8080/');
Note that this only works in the usual setup, i.e. with IO::Socket::SSL installed on the system and used by LWP. Especially with setting PERL_NET_HTTPS_SSL_SOCKET_CLASS to Net::SSL or explicitly importing Net::SSL into the program the obsolete Crypt::SSLeay will be used where proxy handling is completely different.
(*) Even though the proxy will be accessed by HTTP and not HTTPS the connection is still encrypted. This is done by the client requesting the proxy to create a tunnel to the original target using the CONNECT method and then doing end-to-end SSL inside this tunnel. While there are a some proxies and some clients which support to be accessed by HTTPS too this would essentially mean to build an SSL connection between client and proxy and inside this SSL connection another SSL connection between client and final target, i.e. double encryption.

Unable to connect to JIRA over HTTPS server using the Perl JIRA::Client::Automated

I do not use a proxy.
Here is my code:
use JIRA::Client::Automated;
my $jira = JIRA::Client::Automated->new(https://myserver.com, "user", "password");
And the error response is:
Unable to GET /jira/rest/api/latest/issue/DCS-51191: 500 Can't connect
to myserver.com:443 Can't connect to myserver.com:443
Bad file descriptor at
C:/Users/Fred/applis_portables/Strawberry_Perl/perl/vendor/lib/LWP/Protocol/http.pm
line 47.
at createPage2.pl line 16.
Thank you for your help.
It seems that there is a self signed certificate on JIRA server. To bypass, I added following code:
my $jira_ua = $jira->ua();
$jira_ua->ssl_opts( verify_hostname => 0 );
The error doesn't look like a JIRA::Client::Automated error. It's generated by LWP::UserAgent and usually means exactly what is shown.
Do you have a self signed certificate on your server?
Did you try to open that URL in in your browser? https://myserver.com:443 (exactly as you provide it to the module).
Try using curl from your webserver:
curl -vvv https://myserver.com/jira/rest/api/latest/issue/DCS-51191
Maybe it's just a missing www. prefix in your server URL?

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.