Skip to content

some SSL errors not reported properly #81

@bugfood

Description

@bugfood

When making HTTPS requests, there are some types of error that do not get reported in a way that allows for proper troubleshooting. For example:

500 Can't connect to localhost:8888

At a glance, this looks like some sort of networking issue--perhaps the service is not running. The problem in this example case, however, is that the CA certificate file is invalid; there's no way to know that from the error.

The error message is formed in LWP::Protocol::http, which calls the socket class new method and checks for errors. Error messages are expected to be in $@.
https://github.com/libwww-perl/libwww-perl/blob/1c1f28d/lib/LWP/Protocol/http.pm#L26-L49

I can tell that the errors are formed in IO::Socket::SSL, though, which exports and sets $SSL_ERROR instead of $@. I don't know the best way to fix this; either LWP should check $SSL_ERROR or something should set $@ instead. There are some levels of abstraction between LWP::Protocol::http and IO::Socket::SSL, but I got mixed up understanding the inheritance and I'm not exactly sure what is in the middle. I will provide an example program and a stack trace below.

#!/usr/bin/perl

use strict;
use warnings;

use HTTP::Request;
use LWP::UserAgent;
use IO::Socket::SSL;

my $ua = LWP::UserAgent->new;

my %ssl_opts = (
    # /etc/hostname is obviously not a CA cert; we use this to induce an
    # error from IO::Socket::SSL.
    SSL_ca_file => '/etc/hostname',
);

$ua->ssl_opts(%ssl_opts);

# There need not be a service on this port--we never get far enough to use it.
my $req = HTTP::Request->new(GET => 'https://localhost:8888');

my $resp = $ua->request($req);

print "\n\n";
print "error from LWP::UserAgent: ", $resp->status_line, "\n";

print "error from IO::Socket::SSL: ", $SSL_ERROR, "\n";

# Monkey-patch this method so we can get a stack trace.
sub IO::Socket::SSL::error {
    my ($self, $error) = @_;
    # The following line is new vs. the original IO::Socket::SSL::error.
    use Carp; Carp::cluck($error);
    my @err;
    while ( my $err = Net::SSLeay::ERR_get_error()) {
        push @err, Net::SSLeay::ERR_error_string($err);
        # The following line is modified to fully scope the DEBUG variable.
        $IO::Socket::SSL::DEBUG>=2 && DEBUG( $error."\n".$self->get_ssleay_error());
    }
    $error .= ' '.join(' ',@err) if @err;
    return $self->_internal_error($error,4) if $error;
    return;
}

The output is:

$ /tmp/test.pl
Subroutine IO::Socket::SSL::error redefined at /tmp/test.pl line 31.
Invalid certificate authority locations at /tmp/test.pl line 34.
	IO::Socket::SSL::error("IO::Socket::SSL", "Invalid certificate authority locations") called at /usr/share/perl5/IO/Socket/SSL.pm line 2648
	IO::Socket::SSL::SSL_Context::new("IO::Socket::SSL::SSL_Context", HASH(0x55657cff6830)) called at /usr/share/perl5/IO/Socket/SSL.pm line 675
	IO::Socket::SSL::configure_SSL(LWP::Protocol::https::Socket=GLOB(0x55657d6d4e40), HASH(0x55657cff6830)) called at /usr/share/perl5/IO/Socket/SSL.pm line 641
	IO::Socket::SSL::configure(LWP::Protocol::https::Socket=GLOB(0x55657d6d4e40), HASH(0x55657cff6830)) called at /usr/share/perl5/Net/HTTPS.pm line 67
	Net::HTTPS::http_connect(LWP::Protocol::https::Socket=GLOB(0x55657d6d4e40), HASH(0x55657cff6830)) called at /usr/share/perl5/Net/HTTP/Methods.pm line 89
	Net::HTTP::Methods::http_configure(LWP::Protocol::https::Socket=GLOB(0x55657d6d4e40), HASH(0x55657cff6830)) called at /usr/share/perl5/Net/HTTPS.pm line 48
	Net::HTTPS::configure(LWP::Protocol::https::Socket=GLOB(0x55657d6d4e40), HASH(0x55657cff6830)) called at /usr/lib/x86_64-linux-gnu/perl-base/IO/Socket.pm line 49
	IO::Socket::new("LWP::Protocol::https::Socket", "SSL_verifycn_scheme", "www", "SSL_ca_file", "/etc/hostname", "Timeout", 180, "SSL_verify_mode", ...) called at /usr/lib/x86_64-linux-gnu/perl-base/IO/Socket/IP.pm line 121
	IO::Socket::IP::new("LWP::Protocol::https::Socket", "PeerAddr", "localhost", "PeerPort", 8888, "LocalAddr", undef, "Proto", ...) called at /usr/share/perl5/LWP/Protocol/http.pm line 33
	LWP::Protocol::http::_new_socket(LWP::Protocol::https=HASH(0x55657d61b350), "localhost", 8888, 180) called at /usr/share/perl5/LWP/Protocol/http.pm line 216
	LWP::Protocol::http::request(LWP::Protocol::https=HASH(0x55657d61b350), HTTP::Request=HASH(0x55657d424e18), undef, undef, undef, 180) called at /usr/share/perl5/LWP/UserAgent.pm line 214
	LWP::UserAgent::try {...} () called at /usr/share/perl5/Try/Tiny.pm line 102
	eval {...} called at /usr/share/perl5/Try/Tiny.pm line 93
	Try::Tiny::try(CODE(0x55657d5a9f00), Try::Tiny::Catch=REF(0x55657d61b458)) called at /usr/share/perl5/LWP/UserAgent.pm line 229
	LWP::UserAgent::send_request(LWP::UserAgent=HASH(0x55657ca700f0), HTTP::Request=HASH(0x55657d424e18), undef, undef) called at /usr/share/perl5/LWP/UserAgent.pm line 301
	LWP::UserAgent::simple_request(LWP::UserAgent=HASH(0x55657ca700f0), HTTP::Request=HASH(0x55657d424e18), undef, undef) called at /usr/share/perl5/LWP/UserAgent.pm line 308
	LWP::UserAgent::request(LWP::UserAgent=HASH(0x55657ca700f0), HTTP::Request=HASH(0x55657d424e18)) called at /tmp/test.pl line 23


error from LWP::UserAgent: 500 Can't connect to localhost:8888
error from IO::Socket::SSL: Invalid certificate authority locations error:05800088:x509 certificate routines::no certificate or crl found

This is on a Debian system. Versions of relevant packages are:

$ dpkg -l libwww-perl liblwp-protocol-https-perl libio-socket-ssl-perl libnet-http-perl perl 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                       Version      Architecture Description
+++-==========================-============-============-=================================================================
ii  libio-socket-ssl-perl      2.088-1      all          Perl module implementing object oriented interface to SSL sockets
ii  liblwp-protocol-https-perl 6.14-1       all          HTTPS driver for LWP::UserAgent
ii  libnet-http-perl           6.23-1       all          module providing low-level HTTP connection client
ii  libwww-perl                6.77-1       all          simple and consistent interface to the world-wide web
ii  perl                       5.38.2-5     amd64        Larry Wall's Practical Extraction and Report Language

Thanks,
Corey

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions