@@ -10,19 +10,57 @@ import (
1010 "path/filepath"
1111 "runtime"
1212 "strings"
13+ "sync"
1314 "syscall"
1415
1516 "github.com/lib/pq/internal/pqutil"
1617)
1718
19+ // Registry for custom tls.Configs
20+ var (
21+ tlsConfs = make (map [string ]* tls.Config )
22+ tlsConfsMu sync.RWMutex
23+ )
24+
25+ // RegisterTLSConfig registers a custom [tls.Config]. They are used by using
26+ // sslmode=pqgo-«key» in the connection string.
27+ //
28+ // Set the config to nil to remove a configuration.
29+ func RegisterTLSConfig (key string , config * tls.Config ) error {
30+ key = strings .TrimPrefix (key , "pqgo-" )
31+ if config == nil {
32+ tlsConfsMu .Lock ()
33+ delete (tlsConfs , key )
34+ tlsConfsMu .Unlock ()
35+ return nil
36+ }
37+
38+ tlsConfsMu .Lock ()
39+ tlsConfs [key ] = config
40+ tlsConfsMu .Unlock ()
41+ return nil
42+ }
43+
44+ func getTLSConfigClone (key string ) * tls.Config {
45+ tlsConfsMu .RLock ()
46+ if v , ok := tlsConfs [key ]; ok {
47+ return v .Clone ()
48+ }
49+ tlsConfsMu .RUnlock ()
50+ return nil
51+ }
52+
1853// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
1954// related settings. The function is nil when no upgrade should take place.
2055func ssl (o values ) (func (net.Conn ) (net.Conn , error ), error ) {
21- verifyCaOnly := false
22- tlsConf := tls.Config {}
23- switch mode := o ["sslmode" ]; mode {
56+ var (
57+ verifyCaOnly = false
58+ tlsConf = & tls.Config {}
59+ mode = o ["sslmode" ]
60+ )
61+ switch {
2462 // "require" is the default.
25- case "" , "require" :
63+ case mode == "" || mode == "require" :
2664 // We must skip TLS's own verification since it requires full
2765 // verification since Go 1.3.
2866 tlsConf .InsecureSkipVerify = true
@@ -42,15 +80,20 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
4280 delete (o , "sslrootcert" )
4381 }
4482 }
45- case "verify-ca" :
83+ case mode == "verify-ca" :
4684 // We must skip TLS's own verification since it requires full
4785 // verification since Go 1.3.
4886 tlsConf .InsecureSkipVerify = true
4987 verifyCaOnly = true
50- case "verify-full" :
88+ case mode == "verify-full" :
5189 tlsConf .ServerName = o ["host" ]
52- case "disable" :
90+ case mode == "disable" :
5391 return nil , nil
92+ case strings .HasPrefix (mode , "pqgo-" ):
93+ tlsConf = getTLSConfigClone (mode [5 :])
94+ if tlsConf == nil {
95+ return nil , fmt .Errorf (`pq: unknown custom sslmode %q` , mode )
96+ }
5497 default :
5598 return nil , fmt .Errorf (
5699 `pq: unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported` ,
@@ -67,11 +110,11 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
67110 tlsConf .ServerName = o ["host" ]
68111 }
69112
70- err := sslClientCertificates (& tlsConf , o )
113+ err := sslClientCertificates (tlsConf , o )
71114 if err != nil {
72115 return nil , err
73116 }
74- err = sslCertificateAuthority (& tlsConf , o )
117+ err = sslCertificateAuthority (tlsConf , o )
75118 if err != nil {
76119 return nil , err
77120 }
@@ -84,7 +127,7 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
84127 tlsConf .Renegotiation = tls .RenegotiateFreelyAsClient
85128
86129 return func (conn net.Conn ) (net.Conn , error ) {
87- client := tls .Client (conn , & tlsConf )
130+ client := tls .Client (conn , tlsConf )
88131 if verifyCaOnly {
89132 err := client .Handshake ()
90133 if err != nil {
0 commit comments