Which is the default certificate location Perl LWP module refer for SSL certificate? - perl

check_wmi_plus is a Perl based Windows monitoring tool. For monitoring, it has to communicate through WMIC server (a web application).
When the WMIC server is hosted over HTTP its works fine..., but not on HTTPS
In the check_wmi_plus.conf, there is an option to enter wmic_url, entered the configuration as below, but its not working
$wmic_server_uri='https://192.168.59.90/wmic';
In the check_wmi_plus.conf file I could not see an option to provide the SSL certificate path..
From the code I could see that it uses the Perl LWP module,
my $req = HTTP::Request->new( 'POST', $wmic_server_uri );
$req->header( 'Content-Type' => 'application/json' );^M
$req->content( $json );
my $ua = new LWP::UserAgent;
my $res = $ua->request($req);
Which is the default certificate location Perl LWP module refer for SSL certificate?

You can set the SSL certs directory to whatever you like by specifying some environment variables:
PERL_LWP_SSL_CA_FILE
PERL_LWP_SSL_CA_PATH
The file and/or directory where the trusted Certificate Authority certificates is located. See LWP::UserAgent for details.
In LWP::UserAgent, you can use ssl_opts to set these values.
Otherwise, IO::Socket::SSL or Net::SSLeay, which do the real work, are going to get those values from your openssl installation. That answer depends on the platform and installation options so there is no one answer. There's some good strategies in How to find out the path for OpenSSL trusted certificates?

Related

Mojo::UserAgent certificate verify failed

I want to access a website where the certificate cannot be verified (hostname not correct and I cannot change/update the certificate on the server which my application point). I'm using Mojo::UserAgent to get request. So how would go about ignoring this and continues to connect to the website?
I've seen that there is not an option.
I don't want to use LWP::UserAgent.
I've done it using WWW::Curl and WWW::Curl::Easy but I want to clean the code using Mojo::UserAgent (as used in my entire application).
hostname not correct ... So how would go about ignoring this and continues to connect to the website?
It is a very bad idea just to abandon any kind of validation just because the hostname does not match the certificate. Why do you use TLS at all?
A much better way is to know up front which certificate you expect and verify that you exactly get this one. This can easily be done with the option SSL_fingerprint. Unfortunately Mojo::UserAgent does not offer a way to set connection specific arguments, so you need to set it immediately before the connection and back before you do other connections:
use IO::Socket::SSL 1.980;
IO::Socket::SSL::set_client_defaults(
SSL_fingerprint => "sha256$55a5dfaaf..."
);
... use Mojo::UserAgent to connect ..
IO::Socket::SSL::set_client_defaults(); # set back
For more information about to use this option and how to get the fingerprint see Certificate error in Perl.
Another way in case only the hostname is bad would be to use the SSL_verifycn_name option to specify the hostname you expect inside the certificate.
IO::Socket::SSL::set_client_defaults(
SSL_verifycn_name => 'foo.example.com',
);
Another way could be done with the set_args_filter_hack function which is intended to deal with modules which set strange defaults or which don't let the user set its own values:
my $hostname = undef;
IO::Socket::SSL::set_args_filter_hack(
sub {
my ($is_server,$args) = #_;
$args->{SSL_verifycn_name} = $hostname if $hostname;
}
);
...
$hostname = 'foo.example.com';
... do something with Mojo::UserAgent ...
$hostname = undef;
This way you can adapt the settings for each SSL handshake.
For more information see the documentation of IO::Socket::SSL, especially the part about the common usage errors. This part also documents what you should do instead of disabling any kind of validation if some part of the certificate is wrong.
'SSL connect attempt failed error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol'
curl ... SSL connection using TLS_RSA_WITH_RC4_128_MD5
My guess is what you are facing here is unrelated to the certificate validation. Given that this server is using a very old cipher RC4-MD5 I will assume that the server can only handle SSL 3.0. This version is disabled since a while for security reasons in IO::Socket::SSL. To explicitly use this insecure version temporarily:
IO::Socket::SSL::set_client_defaults(
SSL_version => 'SSLv3'
);
Mojo::UserAgent uses IO::Socket::SSL for SSL/TLS support, so you can disable server certificate verification using
IO::Socket::SSL::set_defaults(
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
);
This is an old question, but Mojolicious is alive and kicking. As such I've battled with this recently. Directly from the documents:
my $bool = $ua->insecure;
$ua = $ua->insecure($bool);
Do not require a valid TLS certificate to access HTTPS/WSS sites, defaults to the value of the MOJO_INSECURE environment variable.
# Disable TLS certificate verification for testing
say $ua->insecure(1)->get('https://127.0.0.1:3000')->result->code;
In my application $bool is set from a configuration file, so I can switch it back on, where we need it.

Perl script using WWW::Mechanize to connect to https site just started failing

I have a Perl script that uses WWW::Mechanize to connect to a site over
https, and that script just stopped working the other day. The status
and error message I get back are 500 and "Can't connect to
jobs.illinois.edu:443". The URL I'm trying to connect to is
https://jobs.illinois.edu/. I can connect from my browser (Firefox).
My platform is Linux -- up-to-date Arch Linux. I can also connect
(using WWW::Mechanize) to other https sites.
I tried using LWP::UserAgent, and the behavior is the same.
I'm using ssl_opts => { SSL_version => 'TLSv1' }; I don't remember why
I added that -- it may have been necessary to get it working at some
point.
Any ideas on how to fix this, or how I might get more information as
to what the problem is? Are there other ssl options I can try?
I have a feeling there was some slight configuration change on the
site that led to this problem -- maybe some SSL-protocol version
change or something like that. (I don't think I updated anything
on my machine inbetween the times it worked and stopped working.)
Thanks.
Here's sample code that fails:
#!/usr/bin/perl
use strict;
use warnings;
use constant AJB_URL => 'https://jobs.illinois.edu/academic-job-board';
use WWW::Mechanize;
my $mech = WWW::Mechanize->new( ssl_opts => { SSL_version => 'TLSv1' } );
$mech->get( AJB_URL );
It returns:
Error GETing https://jobs.illinois.edu/academic-job-board: Can't connect to jobs.illinois.edu:443 at ./test2.pl line 12.
... that script just stopped working the other day.
Which in most cases is caused by server-side or client-side changes. But I assume that you did not make any changes on the client side.
Calling your code with perl -MIO::Socket::SSL=debug4... gives:
DEBUG: ...SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Looking at the SSLLabs report you see two trust paths, where one requires an extra download. The root-CA "USERTrust RSA Certification Authority" for the first trust path is not installed on my system (Ubuntu 14.04), and I guess it is not installed on yours (no information about your OS is known, so just guessing). This means the second trust chain will be used and the relevant Root-CA "AddTrust External CA Root" is also installed on my system. Unfortunately this trust chain is missing an intermediate certificate ("Extra download"), so the verification fails.
To fix the problem, find the missing root-CA which should match the fingerprint 2b8f1b57330dbba2d07a6c51f70ee90ddab9ad8e and use it:
$ENV{PERL_LWP_SSL_CA_FILE} = '2b8f1b57330dbba2d07a6c51f70ee90ddab9ad8e.pem';
Looking at the certificate you see that it was issued on 22 May 2015, i.e. three days ago. This explains why the problem happened just now.

Process x509 client certificates in Perl

I am working with Web::ID and have some questions.
From the FAQ for Web::ID:
How can I use WebID in Perl?
[...]
Otherwise, you need to use Web::ID directly. Assuming you've configured your web server to request a client certificate from the browser, and you've managed to get that client certificate into Perl in PEM format, then it's just:
my $webid = Web::ID->new(certificate => $pem);
my $uri = $webid->uri;
And you have the URI.
Anyway I'm stuck at the .. get that client certificate into Perl .. part.
I can see the client certificate is being passed along to the script by examining the %ENVenvironment variable. But I am still unsure how to actually process it in the way that Web::ID does... like examine the SAN.
According to the documentation of mod_ssl you will find the PEM encoded client certificate in the environment variable SSL_CLIENT_CERT, so all you need is to call
my $webid = Web::ID->new(certificate => $ENV{SSL_CLIENT_CERT});
However, Apache does not set the SSL_CLIENT_CERT environment variable by default. This is for performance reasons - setting a whole bunch of environment variables before spawning your Perl script (via mod_perl, or CGI, or whatever) is wasteful if your Perl script doesn't use them, so it only sets a small set of environment variables by default. You need to configure Apache correctly to tell it you want ALL DA STUFFZ. In particular you want something like this in .htaccess, or your virtual host config, or server config file:
SSLOptions +StdEnvVars +ExportCertData
While you're at it, you also want to make sure Apache is configured to ask clients to present a certificate. For that you want something like:
SSLVerifyClient optional_no_ca
All this is kind of covered in the documentation for Web::ID but not especially thoroughly.

Installing a new ca certificate for Perl 5.14.2 LWP on Ubuntu 12.04

I am getting the following error trying to connect to a specific https website using LWP:
LWP::Protocol::https::Socket: SSL connect attempt failed with unknown errorerror:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed at /usr/local/share/perl/5.14.2/LWP/Protocol/http.pm line 51.
I tried with wget and got:
ERROR: cannot verify [domain]'s certificate, issued by `/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=********':
Unable to locally verify the issuer's authority.
I googled around and discovered that I probably had to install the godaddy root ca cert. I figured out how to do that (download certificates, put in /usr/share/ca-certificates and run update-ca-certificates). I also learnt how to use openssl s_client in the process.
Now that the certificate is installed, wget works, but LWP still fails with the same error and so does openssl s_client:
# openssl s_client -connect [domain]:443
CONNECTED(00000003)
depth=0 O = [domain], OU = Domain Control Validated, CN = [domain]
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = [domain], OU = Domain Control Validated, CN = [domain]
verify error:num=27:certificate not trusted
verify return:1
depth=0 O = [domain], OU = Domain Control Validated, CN = [domain]
verify error:num=21:unable to verify the first certificate
verify return:1
I have no idea where to go next to get this working. Any suggestions?
EDIT: SOLVED Here is a simple script that describes what worked after mikew's suggestion:
#!/usr/bin/perl
use LWP::UserAgent;
$URL="[domain]";
my $ua = LWP::UserAgent->new(ssl_opts => { SSL_ca_path=>'/etc/ssl/certs'});
my $response = $ua->get($URL);
For a more specific answer, we'd need to know how you are instantiating your LWP object.
But what you probably need to know about is the SSL_ca_file and SSL_ca_path options for ssl_opts in the LWP constructor. Without one of these set, it assumes the Mozilla_CA is the CA to to use to verify websites.
See LWP::Protocol::https
And LWP::UserAgent, ssl_opts constructor option.
If you are using something like lwp-download and not actually instantiating the LWP::UserAgent object yourself, then you need to set the PERL_LWP_SSL_CA_FILE environment variable to point to your certificate authority or set PERL_LWP_SSL_CA_PATH to your CA path. You can just set these instead of passing in to ssl_opts as well.
If you aren't particularly worried about doing all this verification and like to live dangerously, you can set verify_hostname => 0 for ssl_opts or set PERL_LWP_VERIFY_HOSTNAME environment variable to 0.
And as noted in the documentation, LWP 5.837 and earlier had verify_hostname off by default, whereas later versions default to it being on

How can I determine which SSL client certificate a connection is using in mod_perl?

I am writing a web service in Perl that will run under SSL (HTTPS) with client certificates.
How can I determine which certificate is being used by the client in the current connection so I can filter out unwanted ones?
Note: the web service is being run as a mod_perl script.
Found the answer on PerlMonks:
Use the Apache::SSLLookup module
sub handler {
my $r = Apache::SSLLookup->new(shift);
my $request_is_over_ssl = $r->is_https;
my $certificate = $r->lookup_var('SSL_CLIENT_CERT');
...
}
mod_ssl environment reference here.