Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support inline SSL certificates #818

Merged
merged 3 commits into from
Feb 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
return nil, err
}

// This pseudo-parameter is not recognized by the PostgreSQL server, so let's delete it after use.
delete(o, "sslinline")

// Accept renegotiation requests initiated by the backend.
//
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
Expand All @@ -83,6 +86,19 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
// in the user's home directory. The configured files must exist and have
// the correct permissions.
func sslClientCertificates(tlsConf *tls.Config, o values) error {
sslinline := o["sslinline"]
if sslinline == "true" {
cert, err := tls.X509KeyPair([]byte(o["sslcert"]), []byte(o["sslkey"]))
// Clear out these params, in case they were to be sent to the PostgreSQL server by mistake
o["sslcert"] = ""
o["sslkey"] = ""
if err != nil {
return err
}
tlsConf.Certificates = []tls.Certificate{cert}
return nil
}

// 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.
Expand Down Expand Up @@ -137,9 +153,19 @@ func sslCertificateAuthority(tlsConf *tls.Config, o values) error {
if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
tlsConf.RootCAs = x509.NewCertPool()

cert, err := ioutil.ReadFile(sslrootcert)
if err != nil {
return err
sslinline := o["sslinline"]

var cert []byte
if sslinline == "true" {
// // Clear out this param, in case it were to be sent to the PostgreSQL server by mistake
o["sslrootcert"] = ""
cert = []byte(sslrootcert)
} else {
var err error
cert, err = ioutil.ReadFile(sslrootcert)
if err != nil {
return err
}
}

if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
Expand Down
4 changes: 2 additions & 2 deletions url.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ func ParseURL(url string) (string, error) {
}

var kvs []string
escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
escaper := strings.NewReplacer(`'`, `\'`, `\`, `\\`)
accrue := func(k, v string) {
if v != "" {
kvs = append(kvs, k+"="+escaper.Replace(v))
kvs = append(kvs, k+"='"+escaper.Replace(v)+"'")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was made because PEM certificates include newlines, equal signs and various stuff that is tricky to escape - but by adding single quotes, we can work around the problem.

}
}

Expand Down
6 changes: 3 additions & 3 deletions url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

func TestSimpleParseURL(t *testing.T) {
expected := "host=hostname.remote"
expected := "host='hostname.remote'"
str, err := ParseURL("postgres://hostname.remote")
if err != nil {
t.Fatal(err)
Expand All @@ -17,7 +17,7 @@ func TestSimpleParseURL(t *testing.T) {
}

func TestIPv6LoopbackParseURL(t *testing.T) {
expected := "host=::1 port=1234"
expected := "host='::1' port='1234'"
str, err := ParseURL("postgres://[::1]:1234")
if err != nil {
t.Fatal(err)
Expand All @@ -29,7 +29,7 @@ func TestIPv6LoopbackParseURL(t *testing.T) {
}

func TestFullParseURL(t *testing.T) {
expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username`
expected := `dbname='database' host='hostname.remote' password='top secret' port='1234' user='username'`
str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database")
if err != nil {
t.Fatal(err)
Expand Down