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

Implement "verify-ca" SSL mode #32

Merged
merged 1 commit into from Mar 21, 2020
Merged

Implement "verify-ca" SSL mode #32

merged 1 commit into from Mar 21, 2020

Conversation

gcurtis
Copy link
Contributor

@gcurtis gcurtis commented Mar 18, 2020

I came across a situation with Google Cloud SQL where I needed the behavior of "verify-ca" because "verify-full" was too strict. Specifically, Postgres instances on GCP typically don't have a hostname and use their own private CA when signing certs. This causes the TLS handshake to fail if you attempt to connect via IP:

failed to connect to host=xx.xx.xx.xxx user=postgres database=postgres: failed to write startup message (x509: cannot validate certificate for xx.xx.xx.xxx because it doesn't contain any IP SANs)

Since the CA is private, checking the server name is unnecessary, and Google's docs recommend using "verify-ca".

I found a solution by setting InsecureSkipVerify to true and setting a VerifyPeerCertificate function in the tls.Config returned by ParseConfig. Basically, VerifyPeerCertificate manually verifies the cert chain, but skips checking the hostname. You can see golang/go#21971 (comment) and the crypto/tls package example for more details on how this is implemented.

Since this wasn't super straightforward to figure out, I thought I'd see if you wanted it upstream. I also poked around and couldn't find a way to write a test the new SSL behavior, but I did test everything manually for my use-case.

ParseConfig currently treats the libpq "verify-ca" SSL mode as
"verify-full". This is okay from a security standpoint because
"verify-full" performs certificate verification and hostname
verification, whereas "verify-ca" only performs certificate
verification.

The downside to this approach is that checking the hostname is
unnecessary when the server's certificate has been signed by a private
CA. It can also cause the SSL handshake to fail when connecting to an
instance by IP. For example, a Google Cloud SQL instance typically
doesn't have a hostname and uses its own private CA to sign its
server and client certs.

This change uses the tls.Config.VerifyPeerCertificate function to
perform certificate verification without checking the hostname when the
"verify-ca" SSL mode is set. This brings pgconn's behavior closer to
that of libpq.

See golang/go#21971 (comment)
and https://pkg.go.dev/crypto/tls?tab=doc#example-Config-VerifyPeerCertificate
for more details on how this is implemented.
@jackc jackc merged commit 87c8ddd into jackc:master Mar 21, 2020
@jackc
Copy link
Owner

jackc commented Mar 21, 2020

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants