denisenkom / go-mssqldb

Microsoft SQL server driver written in go language
BSD 3-Clause "New" or "Revised" License
1.82k stars 499 forks source link

Allow non-standard Common Name (CN) for SSL verification of connections with provided certificates. #704

Closed jsimonweb closed 2 years ago

jsimonweb commented 2 years ago

Issue: Google Cloud SQL for SQL Server generated SSL server certificates include a Common Name (CN) formatted as: project-id:instance-id

Example snippet from a generated SSL server certificate: CN = my-project:test-sqlserver

The : character in the CN currently causes a connection formatted as the following snippet to fail: dbURI += fmt.Sprintf("encrypt=true;hostnameincertificate=my-project:test-sqlserver;certificate=%s;", dbRootCert)

Feature request: Provide an option to allow verification of SSL certificates that include a custom non-standard Common Name (CN).

For more information on this issue see: https://github.com/golang/go/issues/40748

kardianos commented 2 years ago

@jsimonweb I appreciate the PR. I think you would need to replace the : with %3A, because it is URL encoded. Can you tell me exactly where it errors, and what it says? Does it fail with a connection error cert match error?

I don't think I would want to do exactly as you have it, but let's discuss what would work.

jsimonweb commented 2 years ago

The error happens upon calling sql.Open() as in the following code snippet:

dbURI := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=%s;", dbTCPHost, dbUser, dbPwd, dbPort, dbName) 
dbURI += fmt.Sprintf("encrypt=true;hostnameincertificate=my-project:test-sqlserver;certificate=%s;", dbRootCert)
sql.Open("mssql", dbURI)

The error message is: TLS Handshake failed: x509: certificate is valid for [IP Address], not my-project:test-sqlserver

Using go-mssqldb updated with the code in PR #705, the following code snippet works as expected:

dbURI := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=%s;", dbTCPHost, dbUser, dbPwd, dbPort, dbName) 
dbURI += fmt.Sprintf("encrypt=true;hostnameincertificate=my-project:test-sqlserver;nonstandardcertcommonname=true;certificate=%s;", dbRootCert) 
sql.Open("mssql", dbURI)

I don't think I would want to do exactly as you have it, but let's discuss what would work.

My PR is the approach I found to resolve this issue while still ensuring a verified certificate based encrypted connection. Feel free to treat it as a proof of concept and re-implement it in a way that's best for the go-mssqldb driver.

Let me know if you need any more details or have any follow-up questions. Thank you!

kardianos commented 2 years ago

Proposal approved. I left comments on PR.