github.com/jackc/pgx/v5@v5.5.5/testsetup/generate_certs.go (about) 1 // Generates a CA, server certificate, and encrypted client certificate for testing pgx. 2 3 package main 4 5 import ( 6 "crypto/rand" 7 "crypto/rsa" 8 "crypto/x509" 9 "crypto/x509/pkix" 10 "encoding/pem" 11 "fmt" 12 "math/big" 13 "net" 14 "os" 15 "time" 16 ) 17 18 func main() { 19 // Create the CA 20 ca := &x509.Certificate{ 21 SerialNumber: big.NewInt(1), 22 Subject: pkix.Name{ 23 CommonName: "pgx-root-ca", 24 }, 25 NotBefore: time.Now(), 26 NotAfter: time.Now().AddDate(20, 0, 0), 27 IsCA: true, 28 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 29 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 30 BasicConstraintsValid: true, 31 } 32 33 caKey, err := rsa.GenerateKey(rand.Reader, 4096) 34 if err != nil { 35 panic(err) 36 } 37 38 caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caKey.PublicKey, caKey) 39 if err != nil { 40 panic(err) 41 } 42 43 err = writePrivateKey("ca.key", caKey) 44 if err != nil { 45 panic(err) 46 } 47 48 err = writeCertificate("ca.pem", caBytes) 49 if err != nil { 50 panic(err) 51 } 52 53 // Create a server certificate signed by the CA for localhost. 54 serverCert := &x509.Certificate{ 55 SerialNumber: big.NewInt(2), 56 Subject: pkix.Name{ 57 CommonName: "localhost", 58 }, 59 DNSNames: []string{"localhost"}, 60 IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, 61 NotBefore: time.Now(), 62 NotAfter: time.Now().AddDate(20, 0, 0), 63 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 64 KeyUsage: x509.KeyUsageDigitalSignature, 65 } 66 67 serverCertPrivKey, err := rsa.GenerateKey(rand.Reader, 2048) 68 if err != nil { 69 panic(err) 70 } 71 72 serverBytes, err := x509.CreateCertificate(rand.Reader, serverCert, ca, &serverCertPrivKey.PublicKey, caKey) 73 if err != nil { 74 panic(err) 75 } 76 77 err = writePrivateKey("localhost.key", serverCertPrivKey) 78 if err != nil { 79 panic(err) 80 } 81 82 err = writeCertificate("localhost.crt", serverBytes) 83 if err != nil { 84 panic(err) 85 } 86 87 // Create a client certificate signed by the CA and encrypted. 88 clientCert := &x509.Certificate{ 89 SerialNumber: big.NewInt(3), 90 Subject: pkix.Name{ 91 CommonName: "pgx_sslcert", 92 }, 93 NotBefore: time.Now(), 94 NotAfter: time.Now().AddDate(20, 0, 0), 95 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 96 KeyUsage: x509.KeyUsageDigitalSignature, 97 } 98 99 clientCertPrivKey, err := rsa.GenerateKey(rand.Reader, 2048) 100 if err != nil { 101 panic(err) 102 } 103 104 clientBytes, err := x509.CreateCertificate(rand.Reader, clientCert, ca, &clientCertPrivKey.PublicKey, caKey) 105 if err != nil { 106 panic(err) 107 } 108 109 writeEncryptedPrivateKey("pgx_sslcert.key", clientCertPrivKey, "certpw") 110 if err != nil { 111 panic(err) 112 } 113 114 writeCertificate("pgx_sslcert.crt", clientBytes) 115 if err != nil { 116 panic(err) 117 } 118 } 119 120 func writePrivateKey(path string, privateKey *rsa.PrivateKey) error { 121 file, err := os.Create(path) 122 if err != nil { 123 return fmt.Errorf("writePrivateKey: %w", err) 124 } 125 126 err = pem.Encode(file, &pem.Block{ 127 Type: "RSA PRIVATE KEY", 128 Bytes: x509.MarshalPKCS1PrivateKey(privateKey), 129 }) 130 if err != nil { 131 return fmt.Errorf("writePrivateKey: %w", err) 132 } 133 134 err = file.Close() 135 if err != nil { 136 return fmt.Errorf("writePrivateKey: %w", err) 137 } 138 139 return nil 140 } 141 142 func writeEncryptedPrivateKey(path string, privateKey *rsa.PrivateKey, password string) error { 143 file, err := os.Create(path) 144 if err != nil { 145 return fmt.Errorf("writeEncryptedPrivateKey: %w", err) 146 } 147 148 block, err := x509.EncryptPEMBlock(rand.Reader, "CERTIFICATE", x509.MarshalPKCS1PrivateKey(privateKey), []byte(password), x509.PEMCipher3DES) 149 if err != nil { 150 return fmt.Errorf("writeEncryptedPrivateKey: %w", err) 151 } 152 153 err = pem.Encode(file, block) 154 if err != nil { 155 return fmt.Errorf("writeEncryptedPrivateKey: %w", err) 156 } 157 158 err = file.Close() 159 if err != nil { 160 return fmt.Errorf("writeEncryptedPrivateKey: %w", err) 161 } 162 163 return nil 164 165 } 166 167 func writeCertificate(path string, certBytes []byte) error { 168 file, err := os.Create(path) 169 if err != nil { 170 return fmt.Errorf("writeCertificate: %w", err) 171 } 172 173 err = pem.Encode(file, &pem.Block{ 174 Type: "CERTIFICATE", 175 Bytes: certBytes, 176 }) 177 if err != nil { 178 return fmt.Errorf("writeCertificate: %w", err) 179 } 180 181 err = file.Close() 182 if err != nil { 183 return fmt.Errorf("writeCertificate: %w", err) 184 } 185 186 return nil 187 }