0

I have the following code in Python3.7:

    import urllib.request
    import urllib.error
    import ssl
    import certifi

    # Create the SSL context
    # Was using cafile=certifi.where() before, but copied it inline. Read below
    context = ssl.create_default_context(cafile='cacert.pem')

    # Prepare the request
    request = urllib.request.Request(some_url)

    try:

        connection = urllib.request.urlopen(request, context=context)

    except urllib.error.URLError as e:
        print(e)

I've tried several different some_url and I'm getting a problem for a specific one, https://hypelabs.io. Other URLs are working; I tested, for example, https://facebook.com, https://stackoverflow.com, and so on, all working properly. For hypelabs.io I get this instead:

<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1051)>

First thoughts were that the CA was not recognized by the system, and that I needed to install the CA certificate first. I checked the chain in the browser and this is what I found:

enter image description here

However, the COMODO RSA Certification Authority is in all bundle files that I tried (as expected) and in the Keychain as well (I'm using MacOS High Sierra). Notice that the serial numbers match.

The second certificate in the chain is not in the system. I know that the root is enough, but just in case I tried downloading it and adding it to the bundle file, after converting the CRT file to PEM:

enter image description here

Same result. Why is this particular certificate failing? What should I be looking at?

André Fratelli
  • 5,920
  • 7
  • 46
  • 87

1 Answers1

1

The site is misconfigured and fails to provide a necessary intermediate certificate. The SSLLabs report therefore says:

This server's certificate chain is incomplete. Grade capped to B.

The second certificate in the chain is not in the system. I know that the root is enough, but just in case I tried downloading it and adding it to the bundle file, after converting the CRT file to PEM.

My guess is that you did something wrong here. Given that your description is correct I assume that it does not fully match what you actually did.

I've took the missing certificate with the same fingerprint as can be found here and added it to the list of root CA (taken on Ubuntu from /etc/ssl/certs/ca-certificates.crt. After that access to the site worked without any problems.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • I see... I need to fix the site first then. Regarding the certificate, I downloaded the link that is shown in the browser while inspecting the certificate, which maps to `crt` file. I then converted it to `pem` as seen [here](https://stackoverflow.com/questions/4691699/how-to-convert-crt-to-pem). I created a copy of `certify.where()` and prepended the converted `pem` contents to the file. This is the same file you see `cafile` pointing at in the question. I tried the same for the `pem` file you linked, but it still didn't work! Any idea why? – André Fratelli Dec 23 '18 at 22:39
  • @AndréFratelli: I have no idea what you are doing differently then I. But please try the cacert.pem from [here](https://pastebin.com/raw/kdmbpd3t) which only consists of the root CA and the missing intermediate CA. Works perfectly for me. – Steffen Ullrich Dec 23 '18 at 22:45
  • Still not working with that one! I started wondering whether it could be the file that wasn't being found, but the other tests (facebook, stackoverflow, etc) still work.. I'll go ahead with fixing this on the server side, but would like to understand why this is not working having the client recognize the chain.. – André Fratelli Dec 23 '18 at 22:50
  • Managed to make it work! It happens that, with all the iterations I was testing, I ended up removing `context=context` so the file was not being used at all for these last tests. Thank you for all your input! – André Fratelli Dec 23 '18 at 23:25