ManyHats has asked for the wisdom of the Perl Monks concerning the following question:

The script below fails with this error: 500 Can't connect to login.salesforce.com:443 (certificate verify failed) Can't connect to login.salesforce.com:443 (certificate verify failed) LWP::Protocol::https::Socket: SSL connect attempt failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed at /Library/Perl/5.16/LWP/Protocol/http.pm line 47.

My best take on the error message is that the SSLeay (openssl) code is unable to verify the certificate. However, if I use the command 'openssl s_client -host login.salesforce.com -port 443', I get an OK at the end (see below), making me think that openssl is able to verify the certificate. So I have a "reality mismatch" with which I need help.

New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: 8FA80F5DE8D33D29B20AE38665A96F1EE29517E229038F6EDDE9D8 +CA294DFEF8 Session-ID-ctx: Master-Key: D1E833AEFD8C0D9345BAD5996ED1B1D0D6E8F58CABBCAE47071B15 +0B49AD510A1A2D4075719C5296D01FDDBA3DFD67C3 Key-Arg : None Start Time: 1425321673 Timeout : 300 (sec) Verify return code: 0 (ok)

If I uncomment the line that sets verify_hostname to zero, the error goes away. It is my understanding that all this option does is to disable the identify check that is done outside of openssl.

Note that "working" code will still break because this code snippet does not providing the proper login information. In other words, I expect a whiny message from Salesforce that will include "INVALID_LOGIN: Invalid username, password"

I do get more debug information if I run the program like this: 'perl -MIO::Socket::SSL=debug30 Testcase':

Newton:salesforce_work tpl$ perl -MIO::Socket::SSL=debug30 Testcase DEBUG: .../IO/Socket/SSL.pm:2602: new ctx 140688297857808 DEBUG: .../IO/Socket/SSL.pm:542: socket not yet connected DEBUG: .../IO/Socket/SSL.pm:544: socket connected DEBUG: .../IO/Socket/SSL.pm:566: ssl handshake not started DEBUG: .../IO/Socket/SSL.pm:608: not using SNI because openssl is too +old DEBUG: .../IO/Socket/SSL.pm:653: set socket to non-blocking to enforce + timeout=120 DEBUG: .../IO/Socket/SSL.pm:667: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:677: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:687: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:707: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:667: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:677: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:687: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:707: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:667: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:677: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:687: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:707: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:2458: ok=0 cert=140688300414128 DEBUG: .../IO/Socket/SSL.pm:667: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:1791: SSL connect attempt failed DEBUG: .../IO/Socket/SSL.pm:1796: SSL connect attempt failed error:140 +90086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify fai +led DEBUG: .../IO/Socket/SSL.pm:673: fatal SSL error: SSL connect attempt +failed error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certif +icate verify failed DEBUG: .../IO/Socket/SSL.pm:1780: IO::Socket::INET6 configuration fail +ed DEBUG: .../IO/Socket/SSL.pm:2635: free ctx 140688297857808 open=140688 +297857808 DEBUG: .../IO/Socket/SSL.pm:2640: free ctx 140688297857808 callback DEBUG: .../IO/Socket/SSL.pm:2647: OK free ctx 140688297857808 500 Can't connect to login.salesforce.com:443 (certificate verify fail +ed) Can't connect to login.salesforce.com:443 (certificate verify failed) LWP::Protocol::https::Socket: SSL connect attempt failed error:1409008 +6:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed +at /Library/Perl/5.16/LWP/Protocol/http.pm line 47.
The message from line 2458 says that OK is zero, which makes me think that openssl already said that the certificate is bad (does openssl 0.9.8 check identity? Why would it not like it now even though is seems to like it in the openssl s_client command?)

I'd appreciate any enlightenment

#!/usr/bin/perl -w use strict; use LWP::UserAgent; use Mozilla::CA; # To set debug we can run the program like this: perl -MIO::Socket::S +SL=debug30 Testcase # Print versions #print "LWP::UserAgent->VERSION is " . LWP::UserAgent->VERSION . "\n"; my ($Request, $Reply, $res); # A User agent for all WWW requests my $ua = LWP::UserAgent->new( timeout => 120 ); $ua->ssl_opts( # verify_hostname => 0, SSL_ca_file => Mozilla::CA::SSL_ca_file(), SSL_verifycn_scheme => 'http', SSL_verifycn_name => 'login.salesforce.com', ); my $LoginXML = <<EOF; <?xml version="1.0" encoding="utf-8" ?> <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"> <env:Body> <n1:login xmlns:n1="urn:partner.soap.sforce.com"> <n1:username>USERNAME</n1:username> <n1:password>AUTHCODE</n1:password> </n1:login> </env:Body> </env:Envelope> EOF $Request = HTTP::Request->new(POST => "https://login.salesforce.com/se +rvices/Soap/u/22.0"); $Request->header( 'Content-Type' => 'text/xml; charset=UTF-8', 'SOAPAction' => 'login' ); $Request->content($LoginXML); # Make the request and check the results $res = $ua->request($Request); $Reply= $res->content; if (!($res->is_success)) { warn $res->status_line, "\n"; warn $Reply, "\n"; } else { warn "The request succeeded\n"; }

Replies are listed 'Best First'.
Re: SSL Certificate Verification problem, using LWP::UserAgent
by hippo (Archbishop) on Mar 02, 2015 at 19:11 UTC

    Your code as it stands works fine for me. Perhaps your version of Mozilla::CA is outdated (or broken)? My test used version 20110914

      Thanks for checking that. You get the "INVALID_LOGIN" message?

      I should have included versions:

    • LWP::UserAgent is 6.13
    • Mozilla::CA is 20141217
    • IO::Socket::SSL is 2.012
    • Net::SSLeay is 1.68
    • Perl is 5.16
    • The OS is Mac OS X Mavericks, but I've updated a lot of the Perl modules using cpan.
    • Suggestions for the next step? Could you post output from your run, with the IO::Socket::SSL debugging turned on? I'm open to other ideas too, as I'm dangling off the edge of my expertise.

        Yes, I do receive the "INVALID_LOGIN" response. Here is the full output with the debugging:

        DEBUG: .../IO/Socket/SSL.pm:1545: new ctx 20310048 DEBUG: .../IO/Socket/SSL.pm:334: socket not yet connected DEBUG: .../IO/Socket/SSL.pm:336: socket connected DEBUG: .../IO/Socket/SSL.pm:349: ssl handshake not started DEBUG: .../IO/Socket/SSL.pm:379: set socket to non-blocking to enforce + timeout=120 DEBUG: .../IO/Socket/SSL.pm:392: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:402: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:412: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:432: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:392: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:402: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:412: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:432: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:1533: ok=1 cert=21706288 DEBUG: .../IO/Socket/SSL.pm:1533: ok=1 cert=22023680 DEBUG: .../IO/Socket/SSL.pm:1533: ok=1 cert=22015040 DEBUG: .../IO/Socket/SSL.pm:1533: ok=1 cert=22007520 DEBUG: .../IO/Socket/SSL.pm:1148: scheme=www cert=22007520 DEBUG: .../IO/Socket/SSL.pm:1155: identity=login.salesforce.com cn=log +in.salesforce.com alt=2 login.salesforce.com DEBUG: .../IO/Socket/SSL.pm:392: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:402: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:412: waiting for fd to become ready: SSL w +ants a read first DEBUG: .../IO/Socket/SSL.pm:432: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:392: Net::SSLeay::connect -> 1 DEBUG: .../IO/Socket/SSL.pm:447: ssl handshake done DEBUG: .../IO/Socket/SSL.pm:1582: free ctx 20310048 open=20310048 DEBUG: .../IO/Socket/SSL.pm:1587: free ctx 20310048 callback DEBUG: .../IO/Socket/SSL.pm:1590: OK free ctx 20310048 500 Server Error <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv= +"http://schemas.xmlsoap.org/soap/envelope/" xmlns:sf="urn:fault.partn +er.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-insta +nce"><soapenv:Body><soapenv:Fault><faultcode>INVALID_LOGIN</faultcode +><faultstring>INVALID_LOGIN: Invalid username, password, security tok +en; or user locked out.</faultstring><detail><sf:LoginFault xsi:type= +"sf:LoginFault"><sf:exceptionCode>INVALID_LOGIN</sf:exceptionCode><sf +:exceptionMessage>Invalid username, password, security token; or user + locked out.</sf:exceptionMessage></sf:LoginFault></detail></soapenv: +Fault></soapenv:Body></soapenv:Envelope>

        This was run with perl v5.14.3 on 64-bit Linux. Since the cert verification will either pass or fail regardless of the payload, you could try an even simpler script such as this:

        use strict; use warnings; use LWP::UserAgent; use Mozilla::CA; my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 1, SSL_ca_file => Mozilla::CA::SSL_ca_file() }) or die; my $url = $ARGV[0] || 'https://login.salesforce.com/'; my $res = $ua->get($url); print $res->code . "\n"; exit;

        You can then run this with any number of known, good URLs (eg: https://www.google.com/ or https://metacpan.org/ ) to see if any of them pass verification.

        Good luck.

        > Mozilla::CA is 20141217

        And that's where your problem is. Mozilla removed lots of 1024-bit root-CA and the CA you need is among these. If you use an older version of the CA store (like from 2013) it works again.
Re: SSL Certificate Verification problem, using LWP::UserAgent
by ManyHats (Initiate) on Mar 04, 2015 at 06:45 UTC

    As a result of the help from both of you, I believe I understand this sufficiently. One problem was that the version of Mozilla::CA I was using was too new. But Apple has thrown some additional mystery into the mix.

    It turns out that OS X uses a patched version of OpenSSL. One feature of this patch is that in some cases where the certificate is going to fail, they use their own TEA code to verify. See Here for more information on their patch. This patch caused my test case to work on a similar machine. While I believed the machines to be configured similarly, I knew that there had been many Perl updates on my primary machine. Further investigation showed that the version of IO::Socket::SSL is different on the two machines (1.77 vs 2.012). The newer version has special code for OS X that overrides Apple's patch to OpenSSL. This special code caused it to fail on my main machine until I tried the older version of Mozilla::CA that has the 1024 bit key.

    Thanks for the enlightenment.