Open Lilja opened 2 years ago
Same issue for me. Using export CURL_CA_BUNDLE="/etc/ssl/cert.pem"
can solve this. Is it any methods easier?
I have no issue with curl
. but I got the issue with ruby, python. did u fix it?
env:
> curl --version
curl 7.79.1 (x86_64-apple-darwin21.0) libcurl/7.79.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.45.1
Release-Date: 2021-09-22
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets
curl
> curl -X POST https://api.localhost/v1/url
* Trying 127.0.0.1:443...
* Connected to api.localhost (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: O=
* start date: Jan 19 07:00:18 2023 GMT
* expire date: Apr 19 07:00:18 2025 GMT
* subjectAltName: host "api.localhost" matched cert's "api.localhost"
* issuer: O=
* SSL certificate verify ok.
> POST /v1/url HTTP/1.1
> Host: api.localhost
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< connection: close
< content-type: application/json; charset=utf-8
< content-length: 40
< Date: Thu, 19 Jan 2023 14:00:54 GMT
ruby
> RestClient.post("https://api.localhost/v1/url", nil, nil)
Traceback (most recent call last):
/Users/fuxin.haocrypto.com/.rbenv/versions/2.7.6/lib/ruby/2.7.0/net/protocol.rb:44:in `connect_nonblock': SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate) (OpenSSL::SSL::SSLError)
/Users/fuxin.haocrypto.com/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rest-client-2.0.2/lib/restclient/request.rb:758:in `rescue in transmit': SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate) (RestClient::SSLCertificateNotVerified)
python
> requests.post("https://api.localhost:443/v1/url")
File /usr/local/lib/python3.9/site-packages/requests/api.py:119, in post(url, data, json, **kwargs)
107 def post(url, data=None, json=None, **kwargs):
108 r"""Sends a POST request.
109
110 :param url: URL for the new :class:`Request` object.
(...)
116 :rtype: requests.Response
117 """
--> 119 return request('post', url, data=data, json=json, **kwargs)
File /usr/local/lib/python3.9/site-packages/requests/api.py:61, in request(method, url, **kwargs)
57 # By using the 'with' statement we are sure the session is closed, thus we
58 # avoid leaving sockets open which can trigger a ResourceWarning in some
59 # cases, and look like a memory leak in others.
60 with sessions.Session() as session:
---> 61 return session.request(method=method, url=url, **kwargs)
File /usr/local/lib/python3.9/site-packages/requests/sessions.py:542, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
537 send_kwargs = {
538 'timeout': timeout,
539 'allow_redirects': allow_redirects,
540 }
541 send_kwargs.update(settings)
--> 542 resp = self.send(prep, **send_kwargs)
544 return resp
File /usr/local/lib/python3.9/site-packages/requests/sessions.py:655, in Session.send(self, request, **kwargs)
652 start = preferred_clock()
654 # Send the request
--> 655 r = adapter.send(request, **kwargs)
657 # Total elapsed time of the request (approximately)
658 elapsed = preferred_clock() - start
File /usr/local/lib/python3.9/site-packages/requests/adapters.py:514, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
510 raise ProxyError(e, request=request)
512 if isinstance(e.reason, _SSLError):
513 # This branch is for urllib3 v1.22 and later.
--> 514 raise SSLError(e, request=request)
516 raise ConnectionError(e, request=request)
518 except ClosedPoolError as e:
SSLError: HTTPSConnectionPool(host='api.localhost', port=443): Max retries exceeded with url: /v1/url (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)')))
I fixed my problems. for Python, The reason is that Python Requests uses certificates from the python-certifi package., not those of the underlying operating system. so the fix is
In [19]: import certifi
...: print(certifi.where())
/usr/local/lib/python3.9/site-packages/certifi/cacert.pem
cat "$(mkcert -CAROOT)/rootCA.pem" >> /usr/local/lib/python3.9/site-packages/certifi/cacert.pem
For ruby, thanks to emboss's answer it's more complicated because Ruby does use any system trust certificates by default. My workaround:
module SetDefaultOpenSSLTrustStore
def initialize(*args, **kwargs)
super
cert_store = OpenSSL::X509::Store.new
cert_store.set_default_paths
@cert_store = cert_store
end
end
Net::HTTP.prepend SetDefaultOpenSSLTrustStore
Ruby can also be solved by added the root certificate to the open_ssl certs folder.
First, get OPENSSL_CERT_PATH that ruby by running irb
:
require "openssl"
puts OpenSSL::X509::DEFAULT_CERT_DIR
Depending how you installed Ruby, you might get something like ~/.rbenv/versions/3.1.4/openssl/ssl/certs
In your shell, copy the mkcert's RootCA to this directory:
cp "$(mkcert -CAROOT)/rootCA.pem" <OPENSSL_CERT_PATH>
Then reload the certs for this openssl with
<OPENSSL_CERT_PATH>/../../../bin/c_rehash
(e.g. ~/.rbenv/versions/3.1.4/openssl/bin/c_rehash)
for python u can run command: /Applications/Python/Install Certificates.command
Ruby can also be solved by added the root certificate to the open_ssl certs folder. First, get OPENSSL_CERT_PATH that ruby by running
irb
:require "openssl" puts OpenSSL::X509::DEFAULT_CERT_DIR
Depending how you installed Ruby, you might get something like ~/.rbenv/versions/3.1.4/openssl/ssl/certs
In your shell, copy the mkcert's RootCA to this directory:
cp "$(mkcert -CAROOT)/rootCA.pem" <OPENSSL_CERT_PATH>
Then reload the certs for this openssl with
<OPENSSL_CERT_PATH>/../../bin/c_rehash
(e.g. ~/.rbenv/versions/3.1.4/openssl/bin/c_rehash)
Thanks @shnikola your steps worked for me except the last one – the file was not at the correct location. Instead I did:
brew info openssl
which revealed the following caveat:
To add additional certificates, place .pem files in
/opt/homebrew/etc/openssl@3/certs
and run/opt/homebrew/opt/openssl@3/bin/c_rehash
following the caveat did the trick:
/opt/homebrew/opt/openssl@3/bin/c_rehash
Mac keychain:
macOS:
12.2.1
OpenSSL:LibreSSL 2.8.3
curl:curl 7.79.1
mkcert:v1.4.3