Skip to content

Commit f52c4b9

Browse files
authored
test: removed static testing TLS material (replaced by test helper) (#413)
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
1 parent 7b92467 commit f52c4b9

19 files changed

+314
-484
lines changed

client/gencerts_test.go

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
// SPDX-FileCopyrightText: Copyright 2015-2026 go-swagger maintainers
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package client
5+
6+
import (
7+
"crypto/ecdsa"
8+
"crypto/elliptic"
9+
"crypto/rand"
10+
"crypto/rsa"
11+
"crypto/x509"
12+
"crypto/x509/pkix"
13+
"encoding/pem"
14+
"fmt"
15+
"math/big"
16+
"net"
17+
"os"
18+
"path/filepath"
19+
"strings"
20+
"testing"
21+
"time"
22+
23+
"github.com/go-openapi/testify/v2/require"
24+
)
25+
26+
const (
27+
// X509 material: keys and certificates to test TLS
28+
myClientKey = "myclient.key"
29+
myClientCert = "myclient.crt"
30+
myCAKey = "myCA.key"
31+
myCACert = "myCA.crt"
32+
myServerKey = "mycert1.key"
33+
myServerCert = "mycert1.crt"
34+
myClientECCKey = "myclient-ecc.key"
35+
myClientECCCert = "myclient-ecc.crt"
36+
)
37+
38+
// newTLSFixtures loads TLS material for testing.
39+
func newTLSFixtures(t testing.TB) *tlsFixtures {
40+
const subject = "somewhere"
41+
42+
certFixturesDir := t.TempDir()
43+
require.NoError(t, runGenCerts(t, certFixturesDir))
44+
45+
keyFile := filepath.Join(certFixturesDir, myClientKey)
46+
keyPem, err := os.ReadFile(keyFile)
47+
require.NoError(t, err)
48+
keyDer, _ := pem.Decode(keyPem)
49+
require.NotNil(t, keyDer)
50+
key, err := x509.ParsePKCS1PrivateKey(keyDer.Bytes)
51+
require.NoError(t, err)
52+
53+
certFile := filepath.Join(certFixturesDir, myClientCert)
54+
certPem, err := os.ReadFile(certFile)
55+
require.NoError(t, err)
56+
certDer, _ := pem.Decode(certPem)
57+
require.NotNil(t, certDer)
58+
cert, err := x509.ParseCertificate(certDer.Bytes)
59+
require.NoError(t, err)
60+
61+
eccKeyFile := filepath.Join(certFixturesDir, myClientECCKey)
62+
eckeyPem, err := os.ReadFile(eccKeyFile)
63+
require.NoError(t, err)
64+
eccBlock, remainder := pem.Decode(eckeyPem)
65+
ecKeyDer, _ := pem.Decode(remainder)
66+
require.Nil(t, ecKeyDer)
67+
ecKey, err := x509.ParseECPrivateKey(eccBlock.Bytes)
68+
require.NoError(t, err)
69+
70+
eccCertFile := filepath.Join(certFixturesDir, myClientECCCert)
71+
ecCertPem, err := os.ReadFile(eccCertFile)
72+
require.NoError(t, err)
73+
ecCertDer, _ := pem.Decode(ecCertPem)
74+
require.NotNil(t, ecCertDer)
75+
ecCert, err := x509.ParseCertificate(ecCertDer.Bytes)
76+
require.NoError(t, err)
77+
caFile := filepath.Join(certFixturesDir, myCACert)
78+
caPem, err := os.ReadFile(caFile)
79+
require.NoError(t, err)
80+
caBlock, _ := pem.Decode(caPem)
81+
require.NotNil(t, caBlock)
82+
caCert, err := x509.ParseCertificate(caBlock.Bytes)
83+
require.NoError(t, err)
84+
85+
serverKeyFile := filepath.Join(certFixturesDir, myServerKey)
86+
serverKeyPem, err := os.ReadFile(serverKeyFile)
87+
require.NoError(t, err)
88+
serverKeyDer, _ := pem.Decode(serverKeyPem)
89+
require.NotNil(t, serverKeyDer)
90+
serverKey, err := x509.ParseECPrivateKey(serverKeyDer.Bytes)
91+
require.NoError(t, err)
92+
93+
serverCertFile := filepath.Join(certFixturesDir, myServerCert)
94+
serverCertPem, err := os.ReadFile(serverCertFile)
95+
require.NoError(t, err)
96+
serverCertDer, _ := pem.Decode(serverCertPem)
97+
require.NotNil(t, serverCertDer)
98+
serverCert, err := x509.ParseCertificate(serverCertDer.Bytes)
99+
require.NoError(t, err)
100+
101+
return &tlsFixtures{
102+
Subject: subject,
103+
RSA: tlsFixture{
104+
CAFile: caFile,
105+
KeyFile: keyFile,
106+
CertFile: certFile,
107+
LoadedCA: caCert,
108+
LoadedKey: key,
109+
LoadedCert: cert,
110+
},
111+
ECDSA: tlsFixture{
112+
KeyFile: eccKeyFile,
113+
CertFile: eccCertFile,
114+
LoadedKey: ecKey,
115+
LoadedCert: ecCert,
116+
},
117+
Server: tlsFixture{
118+
KeyFile: serverKeyFile,
119+
CertFile: serverCertFile,
120+
LoadedCA: caCert,
121+
LoadedKey: serverKey,
122+
LoadedCert: serverCert,
123+
},
124+
}
125+
}
126+
127+
// runGenCerts generates self-signed TLS certificates for the todo-list-errors example.
128+
//
129+
// It produces:
130+
// - myCA.key / myCA.crt — self-signed certificate authority
131+
// - mycert1.key / mycert1.crt — server certificate (CN=goswagger.local)
132+
// - myclient.key / myclient.crt — RSA client certificate (CN=localhost)
133+
// - myclient-ecc.key / myclient-ecc.crt — ECDSA client certificate (CN=localhost)
134+
//
135+
// All ECDSA certificates use ECDSA P-256. All certificates are valid for 10 years.
136+
func runGenCerts(t testing.TB, outDir string) error {
137+
t.Logf("Generating TLS certificates in %s", outDir)
138+
139+
// Generate CA
140+
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
141+
if err != nil {
142+
return fmt.Errorf("generating CA key: %w", err)
143+
}
144+
145+
caTemplate := &x509.Certificate{
146+
SerialNumber: big.NewInt(1),
147+
Subject: pkix.Name{CommonName: "Go Swagger"},
148+
NotBefore: time.Now(),
149+
NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour),
150+
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
151+
BasicConstraintsValid: true,
152+
IsCA: true,
153+
}
154+
155+
caCertDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey)
156+
if err != nil {
157+
return fmt.Errorf("creating CA certificate: %w", err)
158+
}
159+
160+
caCert, err := x509.ParseCertificate(caCertDER)
161+
if err != nil {
162+
return fmt.Errorf("parsing CA certificate: %w", err)
163+
}
164+
165+
if err := writeKeyPair(outDir, stem(myCACert), caKey, caCertDER); err != nil {
166+
return err
167+
}
168+
169+
// Generate server certificate
170+
serverKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
171+
if err != nil {
172+
return fmt.Errorf("generating server key: %w", err)
173+
}
174+
175+
serverTemplate := &x509.Certificate{
176+
SerialNumber: big.NewInt(2),
177+
Subject: pkix.Name{CommonName: "goswagger.local"},
178+
NotBefore: time.Now(),
179+
NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour),
180+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
181+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
182+
DNSNames: []string{"goswagger.local", "localhost", "www.example.com"},
183+
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)},
184+
}
185+
186+
serverCertDER, err := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverKey.PublicKey, caKey)
187+
if err != nil {
188+
return fmt.Errorf("creating server certificate: %w", err)
189+
}
190+
191+
if err := writeKeyPair(outDir, stem(myServerKey), serverKey, serverCertDER); err != nil {
192+
return err
193+
}
194+
195+
// Generate client certificate
196+
197+
// RSA client cert
198+
clientRSAKey, err := rsa.GenerateKey(rand.Reader, 2048)
199+
if err != nil {
200+
return fmt.Errorf("generating client RSA key: %w", err)
201+
}
202+
203+
clientTemplate := makeCertReqTemplate(3)
204+
clientRSACertDER, err := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientRSAKey.PublicKey, caKey)
205+
if err != nil {
206+
return fmt.Errorf("creating client RSA certificate: %w", err)
207+
}
208+
209+
if err := writePKCS1KeyPair(outDir, stem(myClientCert), clientRSAKey, clientRSACertDER); err != nil {
210+
return err
211+
}
212+
213+
// ECC client cert
214+
clientKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
215+
if err != nil {
216+
return fmt.Errorf("generating client key: %w", err)
217+
}
218+
219+
clientTemplate = makeCertReqTemplate(4)
220+
clientCertDER, err := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientKey.PublicKey, caKey)
221+
if err != nil {
222+
return fmt.Errorf("creating client ECDSA certificate: %w", err)
223+
}
224+
225+
if err := writeKeyPair(outDir, stem(myClientECCCert), clientKey, clientCertDER); err != nil {
226+
return err
227+
}
228+
229+
t.Logf(" %s / %s — certificate authority", myCAKey, myCACert)
230+
t.Logf(" %s / %s — server (CN=goswagger.local)", myServerKey, myServerCert)
231+
t.Logf(" %s / %s — client (RSA, CN=localhost)", myClientKey, myClientCert)
232+
t.Logf(" %s / %s — client (ECDSA, CN=localhost)", myClientECCKey, myClientECCCert)
233+
234+
return nil
235+
}
236+
237+
func makeCertReqTemplate(n int64) *x509.Certificate {
238+
return &x509.Certificate{
239+
SerialNumber: big.NewInt(n),
240+
Subject: pkix.Name{
241+
CommonName: "localhost",
242+
Country: []string{"US"},
243+
Province: []string{"California"},
244+
Locality: []string{"San Francisco"},
245+
Organization: []string{"go-swagger"},
246+
},
247+
NotBefore: time.Now(),
248+
NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour),
249+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
250+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
251+
}
252+
}
253+
254+
func writeKeyPair(dir, name string, key *ecdsa.PrivateKey, certDER []byte) error {
255+
keyPath := filepath.Join(dir, name+".key")
256+
certPath := filepath.Join(dir, name+".crt")
257+
258+
// Write private key
259+
keyDER, err := x509.MarshalECPrivateKey(key)
260+
if err != nil {
261+
return fmt.Errorf("marshaling %s key: %w", name, err)
262+
}
263+
264+
if err := writePEM(keyPath, "EC PRIVATE KEY", keyDER); err != nil {
265+
return err
266+
}
267+
268+
// Write certificate
269+
if err := writePEM(certPath, "CERTIFICATE", certDER); err != nil {
270+
return err
271+
}
272+
273+
return nil
274+
}
275+
276+
func writePKCS1KeyPair(dir, name string, key *rsa.PrivateKey, certDER []byte) error {
277+
keyPath := filepath.Join(dir, name+".key")
278+
certPath := filepath.Join(dir, name+".crt")
279+
280+
// Write private key
281+
keyDER := x509.MarshalPKCS1PrivateKey(key)
282+
if err := writePEM(keyPath, "EC PRIVATE KEY", keyDER); err != nil {
283+
return err
284+
}
285+
286+
// Write certificate
287+
if err := writePEM(certPath, "CERTIFICATE", certDER); err != nil {
288+
return err
289+
}
290+
291+
return nil
292+
}
293+
294+
func writePEM(path, blockType string, data []byte) error {
295+
f, err := os.Create(path)
296+
if err != nil {
297+
return fmt.Errorf("creating %s: %w", path, err)
298+
}
299+
defer f.Close()
300+
301+
return pem.Encode(f, &pem.Block{Type: blockType, Bytes: data})
302+
}
303+
304+
func stem(file string) string {
305+
s := strings.Split(file, ".")
306+
307+
return s[0]
308+
}

0 commit comments

Comments
 (0)