Skip to content

Commit afa3e49

Browse files
Copilotshueybubbles
andcommitted
Remove InsecureSkipVerify from setupTLSCertificateOnly, use VerifyPeerCertificate in setupTLSCommonName
Co-authored-by: shueybubbles <[email protected]>
1 parent c6eb984 commit afa3e49

File tree

3 files changed

+35
-35
lines changed

3 files changed

+35
-35
lines changed

msdsn/conn_str_go115.go

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,50 @@ func setupTLSCommonName(config *tls.Config, pem []byte) error {
1313
// fix for https://github.com/denisenkom/go-mssqldb/issues/704
1414
// A SSL/TLS certificate Common Name (CN) containing the ":" character
1515
// (which is a non-standard character) will cause normal verification to fail.
16-
// Since the VerifyConnection callback runs after normal certificate
17-
// verification, confirm that SetupTLS() has been called
18-
// with "insecureSkipVerify=false", then InsecureSkipVerify must be set to true
19-
// for this VerifyConnection callback to accomplish certificate verification.
16+
// We use VerifyPeerCertificate to perform custom verification.
17+
// This is required because standard TLS verification in Go doesn't handle ":" in CN.
18+
19+
// Create a certificate pool with the provided certificate as the root CA
20+
roots := x509.NewCertPool()
21+
roots.AppendCertsFromPEM(pem)
22+
23+
// We must use InsecureSkipVerify=true for this specific edge case because
24+
// normal verification will fail for certificates with ":" in the CN.
25+
// The VerifyPeerCertificate callback performs proper certificate chain verification.
2026
config.InsecureSkipVerify = true
21-
config.VerifyConnection = func(cs tls.ConnectionState) error {
22-
if len(cs.PeerCertificates) == 0 {
27+
config.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
28+
if len(rawCerts) == 0 {
2329
return fmt.Errorf("no peer certificates provided")
2430
}
25-
commonName := cs.PeerCertificates[0].Subject.CommonName
26-
if commonName != cs.ServerName {
27-
return fmt.Errorf("invalid certificate name %q, expected %q", commonName, cs.ServerName)
31+
32+
// Parse the peer certificate
33+
cert, err := x509.ParseCertificate(rawCerts[0])
34+
if err != nil {
35+
return fmt.Errorf("failed to parse certificate: %w", err)
2836
}
29-
// Create a certificate pool with the provided certificate as the root CA
30-
roots := x509.NewCertPool()
31-
roots.AppendCertsFromPEM(pem)
32-
37+
38+
// Check the common name matches the expected server name
39+
commonName := cert.Subject.CommonName
40+
if commonName != config.ServerName {
41+
return fmt.Errorf("invalid certificate name %q, expected %q", commonName, config.ServerName)
42+
}
43+
44+
// Verify the certificate chain against the provided root CA
3345
opts := x509.VerifyOptions{
3446
Roots: roots,
3547
Intermediates: x509.NewCertPool(),
3648
}
37-
_, err := cs.PeerCertificates[0].Verify(opts)
49+
_, err = cert.Verify(opts)
3850
return err
3951
}
4052
return nil
4153
}
4254

4355
// setupTLSCertificateOnly validates the certificate chain without checking the hostname
4456
func setupTLSCertificateOnly(config *tls.Config, pem []byte) error {
45-
// Skip hostname validation but still verify the certificate chain
46-
config.InsecureSkipVerify = true
47-
config.VerifyConnection = func(cs tls.ConnectionState) error {
48-
if len(cs.PeerCertificates) == 0 {
49-
return fmt.Errorf("no peer certificates provided")
50-
}
51-
// Create a certificate pool with the provided certificate as the root CA
52-
roots := x509.NewCertPool()
53-
roots.AppendCertsFromPEM(pem)
54-
55-
opts := x509.VerifyOptions{
56-
Roots: roots,
57-
Intermediates: x509.NewCertPool(),
58-
}
59-
_, err := cs.PeerCertificates[0].Verify(opts)
60-
return err
61-
}
57+
// Skip hostname validation by setting ServerName to empty string
58+
// The certificate chain will still be verified against RootCAs (set later in SetupTLS)
59+
// This is the secure way to skip hostname validation without using InsecureSkipVerify
60+
config.ServerName = ""
6261
return nil
6362
}

msdsn/conn_str_go115pre.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ func setupTLSCommonName(config *tls.Config, pem []byte) error {
1313

1414
// setupTLSCertificateOnly validates the certificate chain without checking the hostname
1515
func setupTLSCertificateOnly(config *tls.Config, pem []byte) error {
16-
// Prior to Go 1.15, we can't use VerifyConnection callback
17-
// So we rely on InsecureSkipVerify being set in SetupTLS
16+
// Skip hostname validation by setting ServerName to empty string
17+
// The certificate chain will still be verified against RootCAs (set later in SetupTLS)
18+
config.ServerName = ""
1819
return nil
1920
}

msdsn/conn_str_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ f0kGHKQEAFYGJLqJdK4KsGQDKLfZr9fqvXCCAA==
390390
assert.Nil(t, err, "Expected no error parsing connection string")
391391
assert.Equal(t, Encryption(EncryptionStrict), config.Encryption, "Expected EncryptionStrict")
392392
assert.NotNil(t, config.TLSConfig, "Expected TLSConfig to be set")
393-
assert.True(t, config.TLSConfig.InsecureSkipVerify, "Expected InsecureSkipVerify to be true when certificate is provided with strict encryption")
394-
assert.NotNil(t, config.TLSConfig.VerifyConnection, "Expected VerifyConnection callback to be set")
393+
assert.Equal(t, "", config.TLSConfig.ServerName, "Expected ServerName to be empty when certificate is provided with strict encryption")
394+
assert.False(t, config.TLSConfig.InsecureSkipVerify, "Expected InsecureSkipVerify to be false")
395395

396396
// Test 2: encrypt=strict without certificate should NOT skip hostname validation
397397
connStr2 := "server=somehost;encrypt=strict"

0 commit comments

Comments
 (0)