Home > Mobile >  urllib3 self-signed certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable
urllib3 self-signed certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable

Time:01-13

I am attempting to connect to a third party system and this will be using self-signed certificates from both sides as this will not be public internet facing.

I am using Python 3 with urllib3 Pool Manager. I have a copy of the certificate, the private key and the verification certificate from the third party. Utilising these in curl confirms the connection works:

curl https://third_party_url.com/hello -iv --cert ./cert.cert --cacert ./verify.cert   --key ./key.key

However, when I try to utilise this in code:

client = urllib3.PoolManager(
    cert_file = "./cert.cert",
    key_file="./key.key",
    ca_certs="./verify.cert",
    cert_reqs="CERT_REQUIRED"
)
resp = client.request("GET", "https://third_party_url.com/hello")

An exception occurs:

    Exception has occurred: SSLError
   [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

A lot of the answers to similar questions is about disabling the verification, which is definitely not an option. Any input would be greatly appreciated.

EDIT

Answers to the questions raised by @Steffen

1) When running without the -cacert argument, curl provides this output:

*   Trying 10.10.10.10:443...
* Connected to third_party_url.com (10.10.10.10) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

So it's the same issue. It's like urllib3 is not accepting the argument to load a provided one.

2) On running openssl x509 -in verify.cert -text The output does not have basic constraints set to CA:true.

The output is:

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            <SerialNumber>
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, O = me.com, OU = third-party
        Validity
            Not Before: Valid Date
            Not After : Expiry Date
        Subject: C = GB, O = Third Party Company Name, OU = third-party, CN = *third-party.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
            <Modulus>
                Exponent: <Redacted Value>
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
    <Signature Value>
-----BEGIN CERTIFICATE-----
<Certificate Details>
-----END CERTIFICATE-----

CodePudding user response:

    Version: 1 (0x0)
    ...
    Issuer: C = GB, O = me.com, OU = third-party
    ...
    Subject: C = GB, O = Third Party Company Name, OU = third-party, CN = *third-party.com

The issuer and subject of this certificate differ. So this is not a self-signed root CA which is expected as a trust anchor.

By default OpenSSL (which is used by Python as SSL library) will not treat an intermediate certificate like this as the trust anchor. This is only done if X509_V_FLAG_PARTIAL_CHAIN is explicitly set, which is not done by Python but since a while by curl.

So this explains why it succeeds with curl but not with Python.

See also Python WWS Library requires entire certificate chain to verify server on how to deal with this issue by setting the appropriate option on the SSL context.

Apart from that - this certificate is a very old X509v2 certificate which does not support extensions. Modern certificates are X509v3 and also have the domain names there are valid for in a Subject Alternative Names extensions. Relevant modern software like Chrome browser will complain about certificates like this.

  • Related