Jay
273278d322
1. add cron module 2. add pool module 3. add tcgplayer background job 4. add card price model
170 lines
5.1 KiB
Go
170 lines
5.1 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
|
|
}
|
|
sslRenegotiation(&tlsConf)
|
|
|
|
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
|
|
}
|