3

I'm writing a PHP script that is requesting confidential data from a remote server. I'm using cURL to get the remote server's certificate information (for its output, please see below).

Which array keys do I need to check for certificate validity to make sure that no one could spoof them?

For example, key [certinfo][0][Subject][CN] can be spoofed by a self-signed certificate.

I could just validate the MD5 hash of the CA-bundle file that I'm using on the client side, but when the server's certificate is about to expire, I need to replace the CA-bundle file accordingly, and update the hash in PHP. That is unacceptable for me. The only one acquiescence is to replace the CA-bundle file without updating the PHP script. For that I need to validate the attributes of the server's certificate, that remain the same through future certificate regeneration and cannot be spoofed by malefactors.

print_r( curl_getinfo($ch) ) :

[url] => https://remoteserver.com
[content_type] => text/html
[http_code] => 200
[header_size] => 148
[request_size] => 79
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.374
[namelookup_time] => 0
[connect_time] => 0.062
[pretransfer_time] => 0.203
[size_upload] => 0
[size_download] => 20618
[speed_download] => 55128
[speed_upload] => 0
[download_content_length] => -1
[upload_content_length] => 0
[starttransfer_time] => 0.281
[redirect_time] => 0
[certinfo] => Array
    (
        [0] => Array
            (
                [Subject] => Array
                    (
                        [OU] => Globe Standard SSL
                        [CN] => www.remoteserver.com
                    )

                [Issuer] => Array
                    (
                        [C] => US
                        [O] => Globe Hosting, Inc.
                        [OU] => GlobeSSL DV Certification Authority
                        [CN] => GlobeSSL CA
                    )

                [Version] => 2
                [Signature Algorithm] => sha1WithRSAEncryption
                [Start date] => 2011-09-30 00:00:00 GMT
                [Expire date] => 2014-09-30 23:59:59 GMT
                [Public Key Algorithm] => rsaEncryption
                [RSA Public Key] => 2048
                [rsa(n)] => d7:c0:0b:3f:f3:3e:d6:ed:92:56:22:12:64:c1:c4:00:d7:c9:a1:1e:..cut..
                [rsa(e)] => 01:00:01:
                [X509v3 Authority Key Identifier] => keyid:C3:AB:A0:02:F0:9B:F5:66:7F:28:15:92:22:95:DB:B8:4E:D3:93:08
                [X509v3 Subject Key Identifier] => 13:1B:B2:52:14:3C:70:1C:B2:93:F1:C5:04:06:86:60:8A:D4:E5:5C
                [X509v3 Key Usage] => DigitalSignature,KeyEncipherment
                [X509v3 Basic Constraints] => CA:FALSE
                [X509v3 Extended Key Usage] => TLSWebServerAuthentication,TLSWebClientAuthentication
                [X509v3 Certificate Policies] => Policy:1.3.6.1.4.1.6449.1.2.2.27, CPS:http://www.globessl.com/docs/GlobeSSL_CPS.pdf
                [X509v3 CRL Distribution Points] => URI:http://crl.globessl.com/GlobeSSLDVCertificationAuthority.crl
                [Authority Information Access] => CAIssuers-URI:http://crt.globessl.com/GlobeSSLDVCertificationAuthority.crt, OCSP-URI:http://ocsp.globessl.com
                [X509v3 Subject Alternative Name] => DNS:www.remoteserver.com,DNS:remoteserver.com
                [Signature] => 61:38:06:d4:30:9c:14:a4:e5:1e:b2:c8:c4:..cut..
                [Cert] => -----BEGIN CERTIFICATE-----cut-----END CERTIFICATE-----

            )

        [1] => Array
            (
                [Subject] => Array
                    (
                        [C] => US
                        [O] => Globe Hosting, Inc.
                        [OU] => GlobeSSL DV Certification Authority
                        [CN] => GlobeSSL CA
                    )

                [Issuer] => Array
                    (
                        [C] => SE
                        [O] => AddTrust AB
                        [OU] => AddTrust External TTP Network
                        [CN] => AddTrust External CA Root
                    )

                [Version] => 2
                [Signature Algorithm] => sha1WithRSAEncryption
                [Start date] => 2010-06-22 00:00:00 GMT
                [Expire date] => 2020-05-30 10:48:38 GMT
                [Public Key Algorithm] => rsaEncryption
                [RSA Public Key] => 2048
                [rsa(n)] => a0:47:04:ce:a8:33:ab:..cut..
                [rsa(e)] => 01:00:01:
                [X509v3 Authority Key Identifier] => keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
                [X509v3 Subject Key Identifier] => C3:AB:A0:02:F0:9B:F5:66:7F:28:15:92:22:95:DB:B8:4E:D3:93:08
                [X509v3 Key Usage] => CertificateSign,CRLSign
                [X509v3 Basic Constraints] => CA:TRUE,pathlen:0
                [X509v3 Certificate Policies] => Policy:1.3.6.1.4.1.6449.1.2.2.27
                [X509v3 CRL Distribution Points] => URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl
                [Authority Information Access] => CAIssuers-URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c, CAIssuers-URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt, OCSP-URI:http://ocsp.usertrust.com
                [Signature] => 66:9c:13:6d:d2:7e:2c:..cut..
                [Cert] => -----BEGIN CERTIFICATE-----cut-----END CERTIFICATE-----

            )

    )
Ali Ahmad
  • 4,814
  • 8
  • 35
  • 61

1 Answers1

5

Theory is: cURL should validate the server's certificate (and it claims to do it). Validation is a complex process (see section 6 of RFC 5280 if you do not value much your sanity) but the gist of it is that, given some a priori trusted keys (that's cURL's "CA cert bundle"), it can verify that the certificate sent by the server has been more or less directly issued by one of these trusted CA (called "trust anchors" or "root CA" in X.509 parlance).

Then, cURL should also verify that the name in the server's certificate really matches the intended server name. This is described in RFC 2818. cURL's documentation is not clear on that subject, but the cURL command-line tools I have here (7.21.4, as distributed with MacOS X 10.7, and 7.23.1) appear to perform that verification as well: I have a SSL server on a machine which has several DNS names; if I use a wrong name, not matching what the server certificate contains, then curl complains loudly:

curl: (35) error:14077458:SSL routines:SSL23_GET_SERVER_HELLO:reason(1112)

Therefore what you should do is use a "CA cert bundle" file on the client which is limited to as few CA as possible (possibly only one). By definition, the client will trust all these CA, so this is reason enough to limit their number. When the server's certificate expire, you do not need to change the CA bundle: you only need to change it when one of the CA themselves expire (but root CA are usually very long lived, precisely because changing one of them entails updating the "CA bundles" or equivalent concept on every client, which is tiresome and expensive).

You do not have to make additional checks from your PHP script, since that would be redundant with what cURL already does.

Note that it has recently been reported that a lot of applications which do some SSL totally botch the server certificate validation part, due to misreading the documentation of the used libraries, or an utter lack of such documentation. At least, cURL has a bit of documentation which is reasonably clear. I encourage you to check the "server name check" part as I described above.

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
  • Thanks for answer. The info about ca-bundle was very useful. Now I'll investigate this. Thanks again. – Alexander M. Oct 28 '12 at 08:26
  • One question. As I understood, each certificate has 3 "public" components: a) AddTrustExternalCARoot.crt (exp. 2020); b) GlobeSSLCA.crt (exp. 2020); c) www.domain.com.crt (exp. 2013) So, I have to use on client side GlobeSSLCA.crt as ca-bundle to verify remote server's certificate and it (ca-bundle) will be valid for further regenerated certificates till 2020? And if I use www.domain.com.crt that expires on 2013 as ca-bundle, I'll have to update it accordingly with server's certificate? Correct? – Alexander M. Oct 28 '12 at 16:27
  • Each certificate contains a _name_ and a _public key_; and it is signed. Certificates chain: you begin with a root (a certificate from the "CA bundle") and each subsequent certificate in the chain is signed by the previous one. This ends on the SSL server's certificate (called "end entity"). The "CA bundle" contains only the roots. You can put any certificate you wish in that set of roots, but your interest is to put only long-lived certificates there. The point of chains is that you do _not_ have to put the server certificate itself in the Ca bundle. – Thomas Pornin Oct 28 '12 at 16:36