Skip to content

Commit

Permalink
Remove openssl from TLS test setup
Browse files Browse the repository at this point in the history
TLS setup and tests were rather finicky. It seems that openssl 3
encrypts certificates differently than older openssl and it does it in
a way Go and/or pgx ssl handling code can't handle. It appears that
this related to the use of a deprecated client certificate encryption
system.

This caused CI to be stuck on Ubuntu 20.04 and recently caused the
contributing guide to fail to work on MacOS.

Remove openssl from the test setup and replace it with a Go program
that generates the certificates.
  • Loading branch information
jackc committed Jan 27, 2024
1 parent bf1c1d7 commit 0819a17
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 61 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ on:
jobs:
test:
name: Test
# Note: The TLS tests are rather finicky. It seems that openssl 3 encrypts certificates differently than older
# openssl and it does it in a way Go and/or pgx ssl handling code can't handle. So stick with Ubuntu 20.04 until
# that is figured out.
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04

strategy:
matrix:
Expand Down
18 changes: 2 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,18 @@ echo "listen_addresses = '127.0.0.1'" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql
echo "port = $PGPORT" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
cat testsetup/postgresql_ssl.conf >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
cp testsetup/pg_hba.conf .testdb/$POSTGRESQL_DATA_DIR/pg_hba.conf
cp testsetup/ca.cnf .testdb
cp testsetup/localhost.cnf .testdb
cp testsetup/pgx_sslcert.cnf .testdb
cd .testdb
# Generate a CA public / private key pair.
openssl genrsa -out ca.key 4096
openssl req -x509 -config ca.cnf -new -nodes -key ca.key -sha256 -days 365 -subj '/O=pgx-test-root' -out ca.pem
# Generate the certificate for localhost (the server).
openssl genrsa -out localhost.key 2048
openssl req -new -config localhost.cnf -key localhost.key -out localhost.csr
openssl x509 -req -in localhost.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out localhost.crt -days 364 -sha256 -extfile localhost.cnf -extensions v3_req
# Generate CA, server, and encrypted client certificates.
go run ../testsetup/generate_certs.go
# Copy certificates to server directory and set permissions.
cp ca.pem $POSTGRESQL_DATA_DIR/root.crt
cp localhost.key $POSTGRESQL_DATA_DIR/server.key
chmod 600 $POSTGRESQL_DATA_DIR/server.key
cp localhost.crt $POSTGRESQL_DATA_DIR/server.crt
# Generate the certificate for client authentication.
openssl genrsa -des3 -out pgx_sslcert.key -passout pass:certpw 2048
openssl req -new -config pgx_sslcert.cnf -key pgx_sslcert.key -passin pass:certpw -out pgx_sslcert.csr
openssl x509 -req -in pgx_sslcert.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out pgx_sslcert.crt -days 363 -sha256 -extfile pgx_sslcert.cnf -extensions v3_req
cd ..
```

Expand Down
15 changes: 2 additions & 13 deletions ci/setup_test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@ then

cd testsetup

# Generate a CA public / private key pair.
openssl genrsa -out ca.key 4096
openssl req -x509 -config ca.cnf -new -nodes -key ca.key -sha256 -days 365 -subj '/O=pgx-test-root' -out ca.pem

# Generate the certificate for localhost (the server).
openssl genrsa -out localhost.key 2048
openssl req -new -config localhost.cnf -key localhost.key -out localhost.csr
openssl x509 -req -in localhost.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out localhost.crt -days 364 -sha256 -extfile localhost.cnf -extensions v3_req
# Generate CA, server, and encrypted client certificates.
go run generate_certs.go

# Copy certificates to server directory and set permissions.
sudo cp ca.pem /var/lib/postgresql/$PGVERSION/main/root.crt
Expand All @@ -34,11 +28,6 @@ then
sudo cp localhost.crt /var/lib/postgresql/$PGVERSION/main/server.crt
sudo chown postgres:postgres /var/lib/postgresql/$PGVERSION/main/server.crt

# Generate the certificate for client authentication.
openssl genrsa -des3 -out pgx_sslcert.key -passout pass:certpw 2048
openssl req -new -config pgx_sslcert.cnf -key pgx_sslcert.key -passin pass:certpw -out pgx_sslcert.csr
openssl x509 -req -in pgx_sslcert.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out pgx_sslcert.crt -days 363 -sha256 -extfile pgx_sslcert.cnf -extensions v3_req

cp ca.pem /tmp
cp pgx_sslcert.key /tmp
cp pgx_sslcert.crt /tmp
Expand Down
6 changes: 0 additions & 6 deletions testsetup/ca.cnf

This file was deleted.

187 changes: 187 additions & 0 deletions testsetup/generate_certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Generates a CA, server certificate, and encrypted client certificate for testing pgx.

package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
"os"
"time"
)

func main() {
// Create the CA
ca := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "pgx-root-ca",
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}

caKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
panic(err)
}

caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caKey.PublicKey, caKey)
if err != nil {
panic(err)
}

err = writePrivateKey("ca.key", caKey)
if err != nil {
panic(err)
}

err = writeCertificate("ca.pem", caBytes)
if err != nil {
panic(err)
}

// Create a server certificate signed by the CA for localhost.
serverCert := &x509.Certificate{
SerialNumber: big.NewInt(2),
Subject: pkix.Name{
CommonName: "localhost",
},
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}

serverCertPrivKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}

serverBytes, err := x509.CreateCertificate(rand.Reader, serverCert, ca, &serverCertPrivKey.PublicKey, caKey)
if err != nil {
panic(err)
}

err = writePrivateKey("localhost.key", serverCertPrivKey)
if err != nil {
panic(err)
}

err = writeCertificate("localhost.crt", serverBytes)
if err != nil {
panic(err)
}

// Create a client certificate signed by the CA and encrypted.
clientCert := &x509.Certificate{
SerialNumber: big.NewInt(3),
Subject: pkix.Name{
CommonName: "pgx_sslcert",
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}

clientCertPrivKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}

clientBytes, err := x509.CreateCertificate(rand.Reader, clientCert, ca, &clientCertPrivKey.PublicKey, caKey)
if err != nil {
panic(err)
}

writeEncryptedPrivateKey("pgx_sslcert.key", clientCertPrivKey, "certpw")
if err != nil {
panic(err)
}

writeCertificate("pgx_sslcert.crt", clientBytes)
if err != nil {
panic(err)
}
}

func writePrivateKey(path string, privateKey *rsa.PrivateKey) error {
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("writePrivateKey: %w", err)
}

err = pem.Encode(file, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
})
if err != nil {
return fmt.Errorf("writePrivateKey: %w", err)
}

err = file.Close()
if err != nil {
return fmt.Errorf("writePrivateKey: %w", err)
}

return nil
}

func writeEncryptedPrivateKey(path string, privateKey *rsa.PrivateKey, password string) error {
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("writeEncryptedPrivateKey: %w", err)
}

block, err := x509.EncryptPEMBlock(rand.Reader, "CERTIFICATE", x509.MarshalPKCS1PrivateKey(privateKey), []byte(password), x509.PEMCipher3DES)
if err != nil {
return fmt.Errorf("writeEncryptedPrivateKey: %w", err)
}

err = pem.Encode(file, block)
if err != nil {
return fmt.Errorf("writeEncryptedPrivateKey: %w", err)
}

err = file.Close()
if err != nil {
return fmt.Errorf("writeEncryptedPrivateKey: %w", err)
}

return nil

}

func writeCertificate(path string, certBytes []byte) error {
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("writeCertificate: %w", err)
}

err = pem.Encode(file, &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
})
if err != nil {
return fmt.Errorf("writeCertificate: %w", err)
}

err = file.Close()
if err != nil {
return fmt.Errorf("writeCertificate: %w", err)
}

return nil
}
13 changes: 0 additions & 13 deletions testsetup/localhost.cnf

This file was deleted.

9 changes: 0 additions & 9 deletions testsetup/pgx_sslcert.cnf

This file was deleted.

0 comments on commit 0819a17

Please sign in to comment.