You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ssl.go 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package pq
  2. import (
  3. "crypto/tls"
  4. "crypto/x509"
  5. "io/ioutil"
  6. "net"
  7. "os"
  8. "os/user"
  9. "path/filepath"
  10. )
  11. // ssl generates a function to upgrade a net.Conn based on the "sslmode" and
  12. // related settings. The function is nil when no upgrade should take place.
  13. func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
  14. verifyCaOnly := false
  15. tlsConf := tls.Config{}
  16. switch mode := o["sslmode"]; mode {
  17. // "require" is the default.
  18. case "", "require":
  19. // We must skip TLS's own verification since it requires full
  20. // verification since Go 1.3.
  21. tlsConf.InsecureSkipVerify = true
  22. // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
  23. //
  24. // Note: For backwards compatibility with earlier versions of
  25. // PostgreSQL, if a root CA file exists, the behavior of
  26. // sslmode=require will be the same as that of verify-ca, meaning the
  27. // server certificate is validated against the CA. Relying on this
  28. // behavior is discouraged, and applications that need certificate
  29. // validation should always use verify-ca or verify-full.
  30. if sslrootcert, ok := o["sslrootcert"]; ok {
  31. if _, err := os.Stat(sslrootcert); err == nil {
  32. verifyCaOnly = true
  33. } else {
  34. delete(o, "sslrootcert")
  35. }
  36. }
  37. case "verify-ca":
  38. // We must skip TLS's own verification since it requires full
  39. // verification since Go 1.3.
  40. tlsConf.InsecureSkipVerify = true
  41. verifyCaOnly = true
  42. case "verify-full":
  43. tlsConf.ServerName = o["host"]
  44. case "disable":
  45. return nil, nil
  46. default:
  47. return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
  48. }
  49. err := sslClientCertificates(&tlsConf, o)
  50. if err != nil {
  51. return nil, err
  52. }
  53. err = sslCertificateAuthority(&tlsConf, o)
  54. if err != nil {
  55. return nil, err
  56. }
  57. // Accept renegotiation requests initiated by the backend.
  58. //
  59. // Renegotiation was deprecated then removed from PostgreSQL 9.5, but
  60. // the default configuration of older versions has it enabled. Redshift
  61. // also initiates renegotiations and cannot be reconfigured.
  62. tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
  63. return func(conn net.Conn) (net.Conn, error) {
  64. client := tls.Client(conn, &tlsConf)
  65. if verifyCaOnly {
  66. err := sslVerifyCertificateAuthority(client, &tlsConf)
  67. if err != nil {
  68. return nil, err
  69. }
  70. }
  71. return client, nil
  72. }, nil
  73. }
  74. // sslClientCertificates adds the certificate specified in the "sslcert" and
  75. // "sslkey" settings, or if they aren't set, from the .postgresql directory
  76. // in the user's home directory. The configured files must exist and have
  77. // the correct permissions.
  78. func sslClientCertificates(tlsConf *tls.Config, o values) error {
  79. sslinline := o["sslinline"]
  80. if sslinline == "true" {
  81. cert, err := tls.X509KeyPair([]byte(o["sslcert"]), []byte(o["sslkey"]))
  82. if err != nil {
  83. return err
  84. }
  85. tlsConf.Certificates = []tls.Certificate{cert}
  86. return nil
  87. }
  88. // user.Current() might fail when cross-compiling. We have to ignore the
  89. // error and continue without home directory defaults, since we wouldn't
  90. // know from where to load them.
  91. user, _ := user.Current()
  92. // In libpq, the client certificate is only loaded if the setting is not blank.
  93. //
  94. // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037
  95. sslcert := o["sslcert"]
  96. if len(sslcert) == 0 && user != nil {
  97. sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
  98. }
  99. // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
  100. if len(sslcert) == 0 {
  101. return nil
  102. }
  103. // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
  104. if _, err := os.Stat(sslcert); os.IsNotExist(err) {
  105. return nil
  106. } else if err != nil {
  107. return err
  108. }
  109. // In libpq, the ssl key is only loaded if the setting is not blank.
  110. //
  111. // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222
  112. sslkey := o["sslkey"]
  113. if len(sslkey) == 0 && user != nil {
  114. sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
  115. }
  116. if len(sslkey) > 0 {
  117. if err := sslKeyPermissions(sslkey); err != nil {
  118. return err
  119. }
  120. }
  121. cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
  122. if err != nil {
  123. return err
  124. }
  125. tlsConf.Certificates = []tls.Certificate{cert}
  126. return nil
  127. }
  128. // sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
  129. func sslCertificateAuthority(tlsConf *tls.Config, o values) error {
  130. // In libpq, the root certificate is only loaded if the setting is not blank.
  131. //
  132. // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
  133. if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
  134. tlsConf.RootCAs = x509.NewCertPool()
  135. sslinline := o["sslinline"]
  136. var cert []byte
  137. if sslinline == "true" {
  138. cert = []byte(sslrootcert)
  139. } else {
  140. var err error
  141. cert, err = ioutil.ReadFile(sslrootcert)
  142. if err != nil {
  143. return err
  144. }
  145. }
  146. if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
  147. return fmterrorf("couldn't parse pem in sslrootcert")
  148. }
  149. }
  150. return nil
  151. }
  152. // sslVerifyCertificateAuthority carries out a TLS handshake to the server and
  153. // verifies the presented certificate against the CA, i.e. the one specified in
  154. // sslrootcert or the system CA if sslrootcert was not specified.
  155. func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error {
  156. err := client.Handshake()
  157. if err != nil {
  158. return err
  159. }
  160. certs := client.ConnectionState().PeerCertificates
  161. opts := x509.VerifyOptions{
  162. DNSName: client.ConnectionState().ServerName,
  163. Intermediates: x509.NewCertPool(),
  164. Roots: tlsConf.RootCAs,
  165. }
  166. for i, cert := range certs {
  167. if i == 0 {
  168. continue
  169. }
  170. opts.Intermediates.AddCert(cert)
  171. }
  172. _, err = certs[0].Verify(opts)
  173. return err
  174. }