package pq

import (
	
	
	
	
	
	
	
)
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 ( values) (func(net.Conn) (net.Conn, error), error) {
	 := false
	 := tls.Config{}
"require" is the default.
We must skip TLS's own verification since it requires full verification since Go 1.3.
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"];  {
			if ,  := os.Stat();  == nil {
				 = true
			} else {
				delete(, "sslrootcert")
			}
		}
We must skip TLS's own verification since it requires full verification since Go 1.3.
		.InsecureSkipVerify = true
		 = true
	case "verify-full":
		.ServerName = ["host"]
	case "disable":
		return nil, nil
	default:
		return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, )
	}

	 := sslClientCertificates(&, )
	if  != nil {
		return nil, 
	}
	 = sslCertificateAuthority(&, )
	if  != nil {
		return nil, 
	}
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.
	.Renegotiation = tls.RenegotiateFreelyAsClient

	return func( net.Conn) (net.Conn, error) {
		 := tls.Client(, &)
		if  {
			 := sslVerifyCertificateAuthority(, &)
			if  != nil {
				return nil, 
			}
		}
		return , 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.
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.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"]
	if len() == 0 &&  != nil {
		 = filepath.Join(.HomeDir, ".postgresql", "postgresql.crt")
https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
	if len() == 0 {
		return nil
https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
	if ,  := os.Stat(); os.IsNotExist() {
		return nil
	} else if  != nil {
		return 
	}
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"]
	if len() == 0 &&  != nil {
		 = filepath.Join(.HomeDir, ".postgresql", "postgresql.key")
	}

	if len() > 0 {
		if  := sslKeyPermissions();  != nil {
			return 
		}
	}

	,  := tls.LoadX509KeyPair(, )
	if  != nil {
		return 
	}

	.Certificates = []tls.Certificate{}
	return nil
}
sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
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"]; len() > 0 {
		.RootCAs = x509.NewCertPool()

		,  := ioutil.ReadFile()
		if  != nil {
			return 
		}

		if !.RootCAs.AppendCertsFromPEM() {
			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 ( *tls.Conn,  *tls.Config) error {
	 := .Handshake()
	if  != nil {
		return 
	}
	 := .ConnectionState().PeerCertificates
	 := x509.VerifyOptions{
		DNSName:       .ConnectionState().ServerName,
		Intermediates: x509.NewCertPool(),
		Roots:         .RootCAs,
	}
	for ,  := range  {
		if  == 0 {
			continue
		}
		.Intermediates.AddCert()
	}
	_,  = [0].Verify()
	return