ID:               49419
 Comment by:       ryan+phpbugs at sleevi dot com
 Reported By:      Jacek at jacekk dot info
 Status:           Open
 Bug Type:         OpenSSL related
 Operating System: Ubuntu
 PHP Version:      5.3.0
 New Comment:

I was unable to reproduce the "good" OpenSSL output that you described,
using OpenSSL FIPS 1.2. For documentation sake (and because everything
I'm about to explain is relative to that, which is equivalent to 0.9.8f
code more or less), what version have you linked against with your PHP?

Running

openssl s_client -connect www.verisign.com:443 -CAfile chain.pem

I get

CONNECTED(00000003)
depth=3 /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification
Authority
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
 0
s:/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/2.5.4.15=V1.0,
Clause
5.(b)/serialNumber=2497886/C=US/postalCode=94043/ST=California/L=Mountain
View/streetAddress=487 East Middlefield Road/O=VeriSign,
Inc./OU=Production Security Services/CN=www.verisign.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use
at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended
Validation SSL SGC CA
 1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use
at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended
Validation SSL SGC CA
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006
VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public
Primary Certification Authority - G5
 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006
VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public
Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification
Authority
 3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification
Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification
Authority
---

Using the chain file at http://pastebin.com/f16f72c6e and I am able to
use the code without the issues you describe (There is an HTTP 500 error
with the PayPal site, but that demonstrates the connection is
successful). The certificate in this file corresponds to the last
certificate in the chain as supplied by both Verisign and Paypal.

The explanation of "why" this works follows, and is based on the
0.9.8/OpenSSL FIPS Module 1.2 code. While I cannot be certain that this
explanation fully explains your problem, based on those missing pieces
of information, it may shed light on the issues and limitations of the
'cafile' and 'capath' arguments.

I do not believe that what you want to work will work the way you've
described, which is due to OpenSSL limitations.

In the chain file you provided, the two certificates you provided are:
subject= /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006
VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public
Primary Certification Authority - G5
issuer= /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006
VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public
Primary Certification Authority - G5

and

subject= /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of
use at https://www.verisign.com/rpa (c)06/CN=VeriSign Class 3 Extended
Validation SSL CA
issuer= /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006
VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public
Primary Certification Authority - G5


The first certificate in the supplied chain file corresponds to being
the issuer of the certificate at index 1 in the above output from
OpenSSL. Thus, one would expect the chain to go from index 0
(www.verisign.com) -> index 1 (EV SSL SGC CA) -> chain file 0 (Public
Primary CA - G5). As chain file 0 is both a self-signed certificate and
in the trusted list, one would presume the connection is now
trusted/verified.

However, OpenSSL's verify code is set to respect the ordering supplied
by the remote server over the preference of a chain file when used for
certificate path building. The untrusted list of certs receives
precedence when building the chain, with the capath, cafile, and any
other lookups only being consulted to complete any missing parts of the
chain.

This can be found in the OpenSSL sources in crypto/x509/x509_vfy.c
X509_verify_cert. The comment in the code states "if we were passed a
cert chain, use it first", in reference to the 'untrusted' chain.

The Verisign server, above, is supplying a chain that actually
terminates at "Class 3 Public Primary Certification Authority" (Index 3)
This is the certificate that would need to be contained in chain.pem for
verification to happen properly, as this is the certificate that OpenSSL
(ergo, by proxy, PHP) expects to find in the trusted store (created by
the cafile/capath options).

If the Verisign server were instead supplying the (intermediate)
certificate "CN=VeriSign Class 3 Public Primary Certification Authority
- G5" (Index: 2) as the last certificate, then the chain.pem you
supplied would still not work, because the Verisign server is supplying
a version who says its issuer is the "Class 3 Public Primary
Certification Authority". As such, that is the certificate that would be
looked up, rather than the self-signed version that you have in your
chain.pem.

If the Verisign server was supplying the last certificate as
"CN=VeriSign Class 3 Extended Validation SSL SGC CA" (Index 1), then the
code you supplied *WOULD* work for Verisign, because OpenSSL would have
an incomplete chain, and then examine chain.pem to inject the trusted
(self-signed) version of the G5 key.

For the PayPal example, the chain I receive from

openssl s_client -connect www.paypal.com:443

is

Certificate chain
 0 s:/C=US/ST=California/L=San Jose/O=PayPal, Inc./OU=Information
Systems/CN=api-3t.paypal.com
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use
at https://www.verisign.com/rpa (c)05/CN=VeriSign Class 3 Secure Server
CA
 1 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use
at https://www.verisign.com/rpa (c)05/CN=VeriSign Class 3 Secure Server
CA
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification
Authority

Here, as best I can tell, none of the certificates in your chain.pem
match certificates in this list. However, using the chain.pem I supplied
above, which contains the "Class 3 Public Primary Certification
Authority", the code executes as intended.


Previous Comments:
------------------------------------------------------------------------

[2009-08-30 18:46:59] Jacek at jacekk dot info

Description:
------------
PHP cannot validate some (VeriSign's?) certificate chains correctly.
openssl s_client works fine with the same input.

Verification of thawte chain works well.

chain.pem is available at http://pastebin.com/f4ab25a9a

OpenSSL:
$ openssl s_client -connect www.verisign.com:443 -CAfile chain.pem
(...)
    Verify return code: 0 (ok)
(...)

Reproduce code:
---------------
<?php
$ssl = array(
        'verify_peer' => TRUE,
        'verify_depth' => 5,
        'allow_self_signed' => FALSE,
        'cafile' => 'chain.pem',
        'capture_peer_cert' => TRUE,
        'capture_peer_chain' => TRUE,
);
$context = stream_context_create(array(
        'ssl' => $ssl,
));

file_get_contents('https://api-3t.paypal.com/', NULL, $context);
file_get_contents('https://www.verisign.com/', NULL, $context);
?>

Expected result:
----------------
Nothing

Actual result:
--------------
Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL
Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate
verify failed in /home/me/test/test.php on line 14

Warning: file_get_contents(): Failed to enable crypto in
/home/me/test/test.php on line 14

Warning: file_get_contents(https://api-3t.paypal.com/): failed to open
stream: operation failed in /home/me/test/test.php on line 14

Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL
Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate
verify failed in /home/me/test/test.php on line 15

Warning: file_get_contents(): Failed to enable crypto in
/home/me/test/test.php on line 15

Warning: file_get_contents(https://www.verisign.com/): failed to open
stream: operation failed in /home/me/test/test.php on line 15



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=49419&edit=1

Reply via email to