nats-io / nats.py

Python3 client for NATS
https://nats-io.github.io/nats.py/
Apache License 2.0
838 stars 173 forks source link

CERTIFICATE_VERIFY_FAILED #526

Open anoronh4 opened 5 months ago

anoronh4 commented 5 months ago

Observed behavior

when trying to connect to a secure nats server with TLS protocol i get the error:

Error: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)

I can work around this error by setting:

ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE

but this seems unsafe.

Expected behavior

expecting to connect to the server while also verifying the certificate.

Server and client version

i don't seem to have nats or nats-server in my PATH, only the nats-py was installed. my nats-py version is 2.6.0 i also have an up to date version of certifi and pip-system-certs

Host environment

MacOS

Steps to reproduce

    options = {"error_cb": error_cb, "closed_cb": closed_cb, "reconnected_cb": reconnected_cb}

    options["user_credentials"] = args.creds
    options["servers"] = args.servers

    if args.cert and args.key:
        ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
        ssl_ctx.load_verify_locations('/etc/ssl/cert.pem')
        ssl_ctx.load_cert_chain(
            certfile=args.cert,
            keyfile=args.key
        )
        options["tls"] = ssl_ctx

    try:
        await nc.connect(**options)
    except Exception as e:
        print(e)

the cert.pm file was not provided to me by the nats server maintainers. I have tried a number of ways to generate my own cert.pm or cacert.pm files to use in the context, but the problem persists. commenting out that line does not appear to make a difference. I also tried running security find-certificate -a -p > ~/all_mac_certs.pem and exporting the key from my Mac's keychain to get new inputs for load_verify_locations() but i'm kind of lost here.

my certifi installation is up to date.

wallyqs commented 5 months ago

Hi @anoronh4 if yoy are using a self-signed certificate you need to define the CA as well for example:

ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
ssl_ctx.load_verify_locations('ca.pem')
ssl_ctx.load_cert_chain(certfile='client-cert.pem',
                        keyfile='client-key.pem')
await nats.connect(servers=["tls://127.0.0.1:4443"], tls=ssl_ctx)
anoronh4 commented 5 months ago

thanks for getting back to me. the person who sent the certfile and keyfile to me sent me their rootCA.pem file as well and unfortunately, it's still not working, i get CERTIFICATE_VERIFY_FAILED. none of us are experts certificates or ssl so it could be that the files are being generated or installed the wrong way but it's a bit difficult to tell what's the underlying issue. in any case, i am getting the impression that this is an ssl issue, not a nats issue!