Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS system certs don't seem to be used; getting: certificate verify failed: unable to get local issuer certificate #1622

Open
2 tasks done
mike-pt opened this issue Mar 18, 2025 · 4 comments
Labels
bug Something isn't working new Needs triage. Comments are welcome!

Comments

@mike-pt
Copy link

mike-pt commented Mar 18, 2025

Checklist

  • I've searched for similar issues.
  • I'm using the latest version of HTTPie.

Minimal reproduction code and steps

  1. Install httpie trough "pip install httpie"
  2. use http/https cmd line to make a request
  3. get the expected http return code (200 i.e.)

Current result

I get "certificate verify failed: unable to get local issuer certificate"

https HEAD https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb

https: error: SSLError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)'))) while doing a HEAD request to URL: https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb

Expected result

Expect the same as bellow but without need to use "--verify=/etc/ssl/cert.pem "

https --verify=/etc/ssl/cert.pem HEAD https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: max-age=300
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 2388
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox
Content-Type: text/plain; charset=utf-8
Cross-Origin-Resource-Policy: cross-origin
Date: Tue, 18 Mar 2025 11:22:41 GMT
ETag: W/"41f0fa741ee4bacb4bb12de4d4c088af7e319efa97d58539675ac6ae979b17ef"
Expires: Tue, 18 Mar 2025 11:27:41 GMT
Source-Age: 0
Strict-Transport-Security: max-age=31536000
Vary: Authorization,Accept-Encoding,Origin
Via: 1.1 varnish
X-Cache: MISS
X-Cache-Hits: 0
X-Content-Type-Options: nosniff
X-Fastly-Request-ID: 6e9b205b4693da2c1c8a78f9c35e025492e5b1bf
X-Frame-Options: deny
X-GitHub-Request-Id: D178:3D47E7:D3151:E8800:67D9577F
X-Served-By: cache-lis1490059-LIS
X-Timer: S1742296961.030921,VS0,VE217
X-XSS-Protection: 1; mode=block

Debug output

Please re-run the command with --debug, then copy the entire command & output and paste both below:

❯ https --debug HEAD https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb
HTTPie 3.2.4
Requests 2.32.3
Pygments 2.19.1
Python 3.13.0 (v3.13.0:60403a5409f, Oct  7 2024, 00:37:40) [Clang 15.0.0 (clang-1500.3.9.4)]
/Library/Frameworks/Python.framework/Versions/3.13/bin/python3
Darwin 24.3.0

<Environment {'apply_warnings_filter': <function Environment.apply_warnings_filter at 0x1012d0a40>,
 'args': Namespace(),
 'as_silent': <function Environment.as_silent at 0x1012d0900>,
 'colors': 256,
 'config': {'default_options': []},
 'config_dir': PosixPath('/Users/miguelc/.config/httpie'),
 'devnull': <property object at 0x10117eb60>,
 'is_windows': False,
 'log_error': <function Environment.log_error at 0x1012d09a0>,
 'program_name': 'https',
 'quiet': 0,
 'rich_console': <functools.cached_property object at 0x100a2d910>,
 'rich_error_console': <functools.cached_property object at 0x101178af0>,
 'show_displays': True,
 'stderr': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>,
 'stderr_isatty': True,
 'stdin': <_io.TextIOWrapper name='<stdin>' mode='r' encoding='utf-8'>,
 'stdin_encoding': 'utf-8',
 'stdin_isatty': True,
 'stdout': <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>,
 'stdout_encoding': 'utf-8',
 'stdout_isatty': True}>

<PluginManager {'adapters': [],
 'auth': [<class 'httpie.plugins.builtin.BasicAuthPlugin'>,
          <class 'httpie.plugins.builtin.DigestAuthPlugin'>,
          <class 'httpie.plugins.builtin.BearerAuthPlugin'>],
 'converters': [],
 'formatters': [<class 'httpie.output.formatters.headers.HeadersFormatter'>,
                <class 'httpie.output.formatters.json.JSONFormatter'>,
                <class 'httpie.output.formatters.xml.XMLFormatter'>,
                <class 'httpie.output.formatters.colors.ColorFormatter'>]}>

>>> requests.request(**{'auth': None,
 'data': RequestJSONDataDict(),
 'headers': <HTTPHeadersDict('User-Agent': b'HTTPie/3.2.4')>,
 'method': 'head',
 'params': <generator object MultiValueOrderedDict.items at 0x10218df30>,
 'url': 'https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb'})


https: error: SSLError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)'))) while doing a HEAD request to URL: https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb


Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connectionpool.py", line 464, in _make_request
    self._validate_conn(conn)
    ~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connectionpool.py", line 1093, in _validate_conn
    conn.connect()
    ~~~~~~~~~~~~^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connection.py", line 741, in connect
    sock_and_verified = _ssl_wrap_socket_and_match_hostname(
        sock=sock,
    ...<14 lines>...
        assert_fingerprint=self.assert_fingerprint,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connection.py", line 920, in _ssl_wrap_socket_and_match_hostname
    ssl_sock = ssl_wrap_socket(
        sock=sock,
    ...<8 lines>...
        tls_in_tls=tls_in_tls,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/util/ssl_.py", line 460, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/util/ssl_.py", line 504, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sock=sock,
        ^^^^^^^^^^
    ...<5 lines>...
        session=session
        ^^^^^^^^^^^^^^^
    )
    ^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/ssl.py", line 1076, in _create
    self.do_handshake()
    ~~~~~~~~~~~~~~~~~^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/ssl.py", line 1372, in do_handshake
    self._sslobj.do_handshake()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    response = self._make_request(
        conn,
    ...<10 lines>...
        **response_kw,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connectionpool.py", line 488, in _make_request
    raise new_e
urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/requests/adapters.py", line 667, in send
    resp = conn.urlopen(
        method=request.method,
    ...<9 lines>...
        chunked=chunked,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/connectionpool.py", line 841, in urlopen
    retries = retries.increment(
        method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/urllib3/util/retry.py", line 519, in increment
    raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)')))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.13/bin/https", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/__main__.py", line 9, in main
    exit_status = main()
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/core.py", line 162, in main
    return raw_main(
        parser=parser,
    ...<2 lines>...
        env=env
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/core.py", line 136, in raw_main
    handle_generic_error(propagated_exc, annotation=annotation)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/core.py", line 100, in raw_main
    exit_status = main_program(
        args=parsed_args,
        env=env,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/core.py", line 213, in program
    for message in messages:
                   ^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/httpie/client.py", line 114, in collect_messages
    response = requests_session.send(
        request=prepared_request,
        **send_kwargs_merged,
        **send_kwargs,
    )
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/requests/adapters.py", line 698, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1020)')))

Additional information, screenshots, or code examples

I haven't used http in terminal in a while so I'm not sure when this started, httpie desktop has covered most my needs :) but sometimes I do need to run requests in the terminal and I prefer htttpie to curl, but seems like its using something else other that OS ca bundle for certs.

Curl and wget just work, this only happens with httpie, there a previous ticket that suggests this comes from requests or certifi, but I'l just using the version httpie installs, I started with a clean pip env and this is all installed as deps of httpie (also that other issue was apparently fixed long ago):

pip freeze
certifi==2025.1.31
charset-normalizer==3.4.1
defusedxml==0.7.1
httpie==3.2.4
idna==3.10
markdown-it-py==3.0.0
mdurl==0.1.2
multidict==6.2.0
Pygments==2.19.1
PySocks==1.7.1
requests==2.32.3
requests-toolbelt==1.0.0
rich==13.9.4
setuptools==76.1.0

On that note, I was thinking it might be getting the bundle from certifi so I tried:

HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: max-age=300
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 2388
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox
Content-Type: text/plain; charset=utf-8
Cross-Origin-Resource-Policy: cross-origin
Date: Tue, 18 Mar 2025 11:36:11 GMT
ETag: W/"41f0fa741ee4bacb4bb12de4d4c088af7e319efa97d58539675ac6ae979b17ef"
Expires: Tue, 18 Mar 2025 11:41:11 GMT
Source-Age: 0
Strict-Transport-Security: max-age=31536000
Vary: Authorization,Accept-Encoding,Origin
Via: 1.1 varnish
X-Cache: HIT
X-Cache-Hits: 0
X-Content-Type-Options: nosniff
X-Fastly-Request-ID: 9e4ef8eaa7a0223b662995628abbdefefe41b2f1
X-Frame-Options: deny
X-GitHub-Request-Id: D178:3D47E7:D3151:E8800:67D9577F
X-Served-By: cache-lis1490051-LIS
X-Timer: S1742297771.249778,VS0,VE121
X-XSS-Protection: 1; mode=block

Also seems to work, so not quite sure what httpie actually uses as cert bundle, it doesn't seem to be either the on included in macOS installation or certifi.

@mike-pt mike-pt added bug Something isn't working new Needs triage. Comments are welcome! labels Mar 18, 2025
@mike-pt
Copy link
Author

mike-pt commented Mar 18, 2025

Just adding here that request also seems to work fine:

>>> import requests
>>> r = requests.head('https://raw.githubusercontent.com/Homebrew/homebrew-core/HEAD/Formula/h/httpie.rb')
>>> print(r.status_code)
200

@mike-pt
Copy link
Author

mike-pt commented Mar 18, 2025

So I found this:

ls -lah /Library/Frameworks/Python.framework/Versions/3.13/etc/openssl
total 0
drwxrwxr-x@ 2 root  admin    64B  7 Oct 06:42 .
drwxrwxr-x@ 3 root  admin    96B  7 Oct 06:42 ..

I'm wondering if httpie is actually not using certifi (while requests is)

>>> import ssl
>>> print(ssl.get_default_verify_paths())
DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/Library/Frameworks/Python.framework/Versions/3.13/etc/openssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/Library/Frameworks/Python.framework/Versions/3.13/etc/openssl/certs')

So my theory is:

httpie might be relying on Python’s built-in ssl module, which expects CA certificates inside OpenSSL’s default location (/Library/Frameworks/Python.framework/Versions/3.13/etc/openssl/cert.pem).

Since this location is empty, httpie fails.

But httpie does install certifi has a dependency so why is it not using it?

>>> print(certifi.where())
/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/certifi/cacert.pem
>>>
❯ ll /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/certifi/cacert.pem
-rw-r--r--@ 1 miguelc  admin   290K 18 Mar 11:19 /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/certifi/cacert.pem

@mike-pt
Copy link
Author

mike-pt commented Mar 18, 2025

As a workaround I will set env > REQUESTS_CA_BUNDLE=/etc/ssl/cert.pem (I prefer to use the system one its usually up to date), ofc I could set to certifi dir but I do believe there is a bug here.

@mike-pt
Copy link
Author

mike-pt commented Mar 18, 2025

Found the issue, it was when we started to work around a previous issue with requests lib:

https://github.com/httpie/cli/blob/master/httpie/compat.py#L104

But it seems now this fails on macOS because it doesnt seem to include any certs in the default python dir:
/Library/Frameworks/Python.framework/Versions/3.13/etc/openssl/

This should probably be symlinked to the system one but its just empty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working new Needs triage. Comments are welcome!
Projects
None yet
Development

No branches or pull requests

1 participant