2

Not 100% sure this is a Perl issue, but it seems to be. I have an IPN script that connects with PayPal to verify transactions. It was working fine until yesterday, when I installed LWP::Protocol::https. Since then, it's been failing with the error:

Can't connect to www.paypal.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 /usr/local/share/perl5/LWP/Protocol/http.pm line 47.

Running GET https://www.paypal.com from bash (which uses LWP) yields the same error message. OTOH, running GET https://www.gmail.com is successful. Running openssl s_client -host paypal.com -port 443 returns (among other things) Verify return code: 0 (ok). curl "https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate" successfully receives a response from PayPal. So it does seem to be Perl-specific.

Module versions:

LWP 6.13
LWP::Protocol::https 6.06
IO::Socket::SSL 2.015
Mozilla::CA 20141217 (note: I've tried the script both using Mozilla::CA and without it... results have been the same)

Please let me know if there are other relevant modules. Perl version is 5.10.1. Server OS is RHEL 6.

Bintz
  • 784
  • 2
  • 9
  • 22

1 Answers1

7

Mozilla::CA 20141217 (note: I've tried the script both using Mozilla::CA and without it... results have been the same)

In short: I don't know what "without it" means for RHEL6 but please try again with Mozilla::CA 20130114 or with the "older ca-bundle" linked from http://curl.haxx.se/docs/caextract.html.

Details: The certificate chain you get from www.paypal.com

[0] www.paypal.com
[1] Symantec Class 3 EV SSL CA - G2
[2] VeriSign Class 3 Public Primary Certification Authority - G5

The last certificate in the chain is signed by the 1024 certificate

/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

Since 1024 bit certificates where removed by Mozilla end of last year you will not find them in the current Mozilla::CA any longer. But browsers don't need the old certificate because the create the trust chain based on certificates [0] and [1] already because they use a built-in certificate instead of the certificate [2] send by the server.

While this newer built-in certificate is also included in Mozilla::CA it will not be used because of a long-standing bug in how OpenSSL validates certificates: it will always try to validate the longest chain and not check if a shorter chain is possible.

For more details about this problem see

The problem can be resolved by using the flag X509_V_FLAG_TRUSTED_FIRST which was introduced with OpenSSL 1.02 (released 4 month ago and probably not in RHEL yet) or by using an even newer and not yet released version of OpenSSL where they finally fixed the problem (see https://rt.openssl.org/Ticket/Display.html?id=3637&user=guest&pass=guest).

The problem can be worked around by having the older 1024 bit CA certificates still available, i.e either using an older Mozilla::CA or CA bundle or using the system CA store which usually includes these older CA. See also:

  • A current bug report against IO::Socket::SSL to use the X509_V_FLAG_TRUSTED_FIRST by default (if available). This flag gets set with 2.016 (not yet released) but needs a version of Net::SSLeay which exports this flag (not yet released) and OpenSSL 1.02 (not included in RHEL).
  • A pull request against LWP to use the default CA on the system instead of Mozilla::CA. This would probably save the problem for you too. Note that Debian/Ubuntu have a similar patch included. I don't know about the version of LWP shipped with RHEL.
Community
  • 1
  • 1
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Ok, so the following actions on my part solved the problem: as CPAN doesn't include a way to roll back modules (in this case Mozilla::CA), I downloaded the older CA bundle manually and copied it into the Mozilla::CA directory (`/usr/local/share/perl5/Mozilla/CA`), replacing the `cacert.pem` file. I _thought_ that LWP used Mozilla::CA for its certificates only if `use Mozilla::CA` was specified, and default behavior was to use the server's CA bundle, but I guess this is not the case? – Bintz May 31 '15 at 07:41
  • 1
    The CPAN distribution of LWP::Protocol::https uses currently Mozilla::CA as the set of trusted CA's. Debian/Ubuntu patched it to use the system CA's instead. What the servers sends will of course be used too, but only for leaf and intermediate certificates and of course not for the trusted root which must be local. – Steffen Ullrich May 31 '15 at 11:06
  • Thank you for the explanation. All is now clear to me! – Bintz May 31 '15 at 20:38