Question: By pointing my browser to <https://graph.facebook.com/me>, I get an encrypted HTTPS connection, which the certificate chain is:

* DigiCert High Assurance EV Root CA (root)
* DigiCert High Assurance CA-3
* \*.facebook.com

So I have downloaded the root certificate from <https://www.digicert.com/digicert-root-certificates.htm> (I have also exported it from my browser, diff shows they are the same thing), and tried to use Python built-in SSL module to verify the authenticity of the connection to graph.facebook.com.

I have just executed the example <http://docs.python.org/library/ssl.html#client-side-operation>, replacing the ca\_cert with "DigiCertHighAssuranceEVRootCA.crt" and the address with graph.facebook.com. The connection attempt fails with the exception:

```
ssl.SSLError: [Errno 1] _ssl.c:499: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

```

If I try the same code and certificate against ev-root.digicert.com (which is the address provided by DigiCert for testing if the client can verify their certificate), everything works nicely. Via browser, I could verify that the chain used in this connection is:

* DigiCert High Assurance EV Root CA (root)
* DigiCert High Assurance EV CA-1
* ev-root.digicert.com

By running
 ssl.get\_server\_certificate(('graph.facebook.com', 443))
I get the same certificate identifyed as "\*.facebook.com" by my browser, what means both Python code and my browser gets the same certificate to validate.

Why Chrome can validate graph.facebook.com with the given root certficate, Python can validate another site with this same root certificate, but Python can not validate graph.facebook.com ?

Answer: 
I got the answer from the OpenSSL mailing list. It seems that "DigiCert High Assurance EV Root CA" was signed by another certificate authority before being self-signed. Now there are two versions of the certificate. One is bundled with SSL implementations and provided for download by DigiCert, which is self-signed and can be used as Root CA for verifying other certificates it signs. The other version is the one returned by Facebook's server in the SSL handshake process, which is signed by some Entrust certificate. Both have the same public key and keyid.

NSS, the SSL implementation of Firefox and Chrome, apparently correctly follows the X.509 specification and ignores the last certificate in the chain sent by the server, and uses its own trusted version of "DigiCert High Assurance EV Root CA" to verify the chain. Python's implementation is over OpenSSL, which verifies "DigiCert High Assurance CA-3" using the certificate provided by the host, and in turn tries to verify this last one. Since it was signed by other CA, and I did not provided that certificate, it fails. I do not think this behavior is correct, because since I already trust a certificate in the middle of the chain, theoretically I have no need to check the rest.

My solutions was to provide to the ssl module the Entrust certificate that verifies "DigiCert High Assurance EV Root CA".
If you are working behind a proxy, you might also want to open <https://graph.facebook.com> in your browser, and check the certification path from there. It is possible that your proxy acts as the issuer of the website certificate. In this case, identifity your proxy certificate, extract it into a pem file and append the content to the Python certifi cacert.pem certificate.