Python 2.7.11 httplib2 throws CERTIFICATE_VERIFY_FAILED for the wrong certificate for SSL SNI website

543 views Asked by At

I have a website that's accessible through multiple URL's, 2 of which have SSL certificates, which are served using SSL SNI (the entire thing is served using nginx).

This setup worked fine for browsers as well as Python 2.7.11 code that monitors the website, as long as both certificates were valid.

Recently, one of the certificates expired - the one that's not used for anything (not for inbound traffic, and not for monitoring). This had no impact on browsers accessing the website, but it started causing failures in the monitoring Python script that look like this:

2016-12-24 02:09:49,351 - foo.__main__(140582120666944) - app_monitoring.py:90 - ERROR - Call to <lambda> Failed 1 times
Traceback (most recent call last):
  File "devops/monitoring/app_monitoring.py", line 88, in call_with_retry
    func(*args, **kwargs)
  File "devops/monitoring/app_monitoring.py", line 116, in <lambda>
    test_func=lambda: yapi_calls.test_api_on_all_datasets(Flags.yapi_url)),
  File "/usr/src/app/system_tests/yapi_calls.py", line 158, in test_api_on_all_datasets
    datasets = send(yapi_url, 'list_datasets', {})
  File "/usr/src/app/system_tests/yapi_calls.py", line 48, in send
    return gcloud.get_yapi(yapi_url).execute(api_call, req)
  File "/usr/src/app/cloudapi/yapi.py", line 23, in execute
    return self._execute(api_call, req, True)
  File "/usr/src/app/cloudapi/yapi.py", line 36, in _execute
    headers=headers)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 631, in new_request
    redirections, connection_type)
  File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1609, in request
    (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
  File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1351, in _request
    (response, content) = self._conn_request(conn, request_uri, method, body, headers)
  File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1272, in _conn_request
    conn.connect()
  File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1059, in connect
    raise SSLHandshakeError(e)
SSLHandshakeError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

Note: I have one valid certificate, and one expired certificate, and the problem is that the exception is thrown because of the expired certificate even though I go through the URL with valid certificate.

I checked with requests, and had no problem accessing the "good" URL, while getting the expected SSL error if I access the expired URL - so I suspect this is an issue specific to httplib2 handling of SNI certificates.

Unfortunately, I can't switch to requests in this flow, since this is an external library (as visible in the stack trace - oauth2client).

Other than installing a new valid SNI certificate (or switching to non-SNI certificate) - is there anything else I can do about this?

UPDATE: I found a workaround that works for this case.

when serving SSL SNI with nginx, one still needs to set a default certificate. turns out that in this case, the default certificate was the one that expired. by changing the default certificate to the valid one, the error went away.

this workaround makes me think that there's a bug in httplib2 SSL SNI implementation - it seems to require verification of the default certificate, even if it's not the certificate for the requested domain.

0

There are 0 answers