mirror of
https://github.com/minio/minio.git
synced 2024-12-26 23:25:54 -05:00
e29009d347
Commit 5c13765168
removed postgre registration triggerd
by the automatic gofmt command but it was the only where pg is registered. This commit
fixes behavior and adds unit tests to check whether postgre & sql are registered or not.
176 lines
5.4 KiB
Go
176 lines
5.4 KiB
Go
package pq
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
)
|
|
|
|
// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
|
|
// related settings. The function is nil when no upgrade should take place.
|
|
func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
|
|
verifyCaOnly := false
|
|
tlsConf := tls.Config{}
|
|
switch mode := o["sslmode"]; mode {
|
|
// "require" is the default.
|
|
case "", "require":
|
|
// We must skip TLS's own verification since it requires full
|
|
// verification since Go 1.3.
|
|
tlsConf.InsecureSkipVerify = true
|
|
|
|
// From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
|
|
//
|
|
// Note: For backwards compatibility with earlier versions of
|
|
// PostgreSQL, if a root CA file exists, the behavior of
|
|
// sslmode=require will be the same as that of verify-ca, meaning the
|
|
// server certificate is validated against the CA. Relying on this
|
|
// behavior is discouraged, and applications that need certificate
|
|
// validation should always use verify-ca or verify-full.
|
|
if sslrootcert, ok := o["sslrootcert"]; ok {
|
|
if _, err := os.Stat(sslrootcert); err == nil {
|
|
verifyCaOnly = true
|
|
} else {
|
|
delete(o, "sslrootcert")
|
|
}
|
|
}
|
|
case "verify-ca":
|
|
// We must skip TLS's own verification since it requires full
|
|
// verification since Go 1.3.
|
|
tlsConf.InsecureSkipVerify = true
|
|
verifyCaOnly = true
|
|
case "verify-full":
|
|
tlsConf.ServerName = o["host"]
|
|
case "disable":
|
|
return nil, nil
|
|
default:
|
|
return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
|
|
}
|
|
|
|
err := sslClientCertificates(&tlsConf, o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = sslCertificateAuthority(&tlsConf, o)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Accept renegotiation requests initiated by the backend.
|
|
//
|
|
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
|
|
// the default configuration of older versions has it enabled. Redshift
|
|
// also initiates renegotiations and cannot be reconfigured.
|
|
tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
|
|
|
|
return func(conn net.Conn) (net.Conn, error) {
|
|
client := tls.Client(conn, &tlsConf)
|
|
if verifyCaOnly {
|
|
err := sslVerifyCertificateAuthority(client, &tlsConf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return client, nil
|
|
}, nil
|
|
}
|
|
|
|
// sslClientCertificates adds the certificate specified in the "sslcert" and
|
|
// "sslkey" settings, or if they aren't set, from the .postgresql directory
|
|
// in the user's home directory. The configured files must exist and have
|
|
// the correct permissions.
|
|
func sslClientCertificates(tlsConf *tls.Config, o values) error {
|
|
// user.Current() might fail when cross-compiling. We have to ignore the
|
|
// error and continue without home directory defaults, since we wouldn't
|
|
// know from where to load them.
|
|
user, _ := user.Current()
|
|
|
|
// In libpq, the client certificate is only loaded if the setting is not blank.
|
|
//
|
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037
|
|
sslcert := o["sslcert"]
|
|
if len(sslcert) == 0 && user != nil {
|
|
sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
|
|
}
|
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
|
|
if len(sslcert) == 0 {
|
|
return nil
|
|
}
|
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
|
|
if _, err := os.Stat(sslcert); os.IsNotExist(err) {
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
// In libpq, the ssl key is only loaded if the setting is not blank.
|
|
//
|
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222
|
|
sslkey := o["sslkey"]
|
|
if len(sslkey) == 0 && user != nil {
|
|
sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
|
|
}
|
|
|
|
if len(sslkey) > 0 {
|
|
if err := sslKeyPermissions(sslkey); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tlsConf.Certificates = []tls.Certificate{cert}
|
|
return nil
|
|
}
|
|
|
|
// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
|
|
func sslCertificateAuthority(tlsConf *tls.Config, o values) error {
|
|
// In libpq, the root certificate is only loaded if the setting is not blank.
|
|
//
|
|
// https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
|
|
if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
|
|
tlsConf.RootCAs = x509.NewCertPool()
|
|
|
|
cert, err := ioutil.ReadFile(sslrootcert)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
|
|
return fmterrorf("couldn't parse pem in sslrootcert")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
|
|
// verifies the presented certificate against the CA, i.e. the one specified in
|
|
// sslrootcert or the system CA if sslrootcert was not specified.
|
|
func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error {
|
|
err := client.Handshake()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
certs := client.ConnectionState().PeerCertificates
|
|
opts := x509.VerifyOptions{
|
|
DNSName: client.ConnectionState().ServerName,
|
|
Intermediates: x509.NewCertPool(),
|
|
Roots: tlsConf.RootCAs,
|
|
}
|
|
for i, cert := range certs {
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
opts.Intermediates.AddCert(cert)
|
|
}
|
|
_, err = certs[0].Verify(opts)
|
|
return err
|
|
}
|