|
1 | 1 | package main |
2 | | - |
3 | | -import ( |
4 | | - "crypto/ecdsa" |
5 | | - "crypto/elliptic" |
6 | | - "crypto/rand" |
7 | | - "crypto/tls" |
8 | | - "crypto/x509" |
9 | | - "crypto/x509/pkix" |
10 | | - "encoding/pem" |
11 | | - "math/big" |
12 | | - "os" |
13 | | - "path/filepath" |
14 | | - "testing" |
15 | | - "time" |
16 | | -) |
17 | | - |
18 | | -func generateTestCert(t *testing.T, dir string) (caPath, certPath, keyPath string) { |
19 | | - t.Helper() |
20 | | - |
21 | | - caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
22 | | - if err != nil { |
23 | | - t.Fatalf("generate CA key: %v", err) |
24 | | - } |
25 | | - caTemplate := &x509.Certificate{ |
26 | | - SerialNumber: big.NewInt(1), |
27 | | - Subject: pkix.Name{CommonName: "Test CA"}, |
28 | | - NotBefore: time.Now().Add(-time.Hour), |
29 | | - NotAfter: time.Now().Add(time.Hour), |
30 | | - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, |
31 | | - BasicConstraintsValid: true, |
32 | | - IsCA: true, |
33 | | - } |
34 | | - caCertDER, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caKey.PublicKey, caKey) |
35 | | - if err != nil { |
36 | | - t.Fatalf("create CA cert: %v", err) |
37 | | - } |
38 | | - |
39 | | - caPath = filepath.Join(dir, "ca.pem") |
40 | | - caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCertDER}) |
41 | | - if err := os.WriteFile(caPath, caPEM, 0600); err != nil { |
42 | | - t.Fatalf("write CA cert: %v", err) |
43 | | - } |
44 | | - |
45 | | - caCert, err := x509.ParseCertificate(caCertDER) |
46 | | - if err != nil { |
47 | | - t.Fatalf("parse CA cert: %v", err) |
48 | | - } |
49 | | - |
50 | | - clientKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
51 | | - if err != nil { |
52 | | - t.Fatalf("generate client key: %v", err) |
53 | | - } |
54 | | - clientTemplate := &x509.Certificate{ |
55 | | - SerialNumber: big.NewInt(2), |
56 | | - Subject: pkix.Name{CommonName: "Test Client"}, |
57 | | - NotBefore: time.Now().Add(-time.Hour), |
58 | | - NotAfter: time.Now().Add(time.Hour), |
59 | | - KeyUsage: x509.KeyUsageDigitalSignature, |
60 | | - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, |
61 | | - } |
62 | | - clientCertDER, err := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientKey.PublicKey, caKey) |
63 | | - if err != nil { |
64 | | - t.Fatalf("create client cert: %v", err) |
65 | | - } |
66 | | - |
67 | | - certPath = filepath.Join(dir, "client.pem") |
68 | | - certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: clientCertDER}) |
69 | | - if err := os.WriteFile(certPath, certPEM, 0600); err != nil { |
70 | | - t.Fatalf("write client cert: %v", err) |
71 | | - } |
72 | | - |
73 | | - keyPath = filepath.Join(dir, "client-key.pem") |
74 | | - keyDER, err := x509.MarshalECPrivateKey(clientKey) |
75 | | - if err != nil { |
76 | | - t.Fatalf("marshal client key: %v", err) |
77 | | - } |
78 | | - keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER}) |
79 | | - if err := os.WriteFile(keyPath, keyPEM, 0600); err != nil { |
80 | | - t.Fatalf("write client key: %v", err) |
81 | | - } |
82 | | - |
83 | | - return caPath, certPath, keyPath |
84 | | -} |
85 | | - |
86 | | -func TestBuildTLSConfig_noFlags(t *testing.T) { |
87 | | - cfg, err := buildTLSConfig("", "", "", false) |
88 | | - if err != nil { |
89 | | - t.Fatalf("unexpected error: %v", err) |
90 | | - } |
91 | | - if cfg != nil { |
92 | | - t.Error("expected nil config when no TLS flags are set") |
93 | | - } |
94 | | -} |
95 | | - |
96 | | -func TestBuildTLSConfig_mismatchedCertKey(t *testing.T) { |
97 | | - tests := []struct { |
98 | | - name string |
99 | | - cert string |
100 | | - key string |
101 | | - }{ |
102 | | - {"cert without key", "/some/cert.pem", ""}, |
103 | | - {"key without cert", "", "/some/key.pem"}, |
104 | | - } |
105 | | - for _, tt := range tests { |
106 | | - t.Run(tt.name, func(t *testing.T) { |
107 | | - _, err := buildTLSConfig("", tt.cert, tt.key, false) |
108 | | - if err == nil { |
109 | | - t.Fatal("expected error for mismatched cert/key") |
110 | | - } |
111 | | - }) |
112 | | - } |
113 | | -} |
114 | | - |
115 | | -func TestBuildTLSConfig_caCertOnly(t *testing.T) { |
116 | | - dir := t.TempDir() |
117 | | - caPath, _, _ := generateTestCert(t, dir) |
118 | | - |
119 | | - cfg, err := buildTLSConfig(caPath, "", "", false) |
120 | | - if err != nil { |
121 | | - t.Fatalf("unexpected error: %v", err) |
122 | | - } |
123 | | - if cfg == nil { |
124 | | - t.Fatal("expected non-nil TLS config") |
125 | | - } |
126 | | - if cfg.RootCAs == nil { |
127 | | - t.Error("expected RootCAs to be populated") |
128 | | - } |
129 | | - if cfg.MinVersion != tls.VersionTLS12 { |
130 | | - t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, tls.VersionTLS12) |
131 | | - } |
132 | | - if len(cfg.Certificates) != 0 { |
133 | | - t.Errorf("expected no client certificates, got %d", len(cfg.Certificates)) |
134 | | - } |
135 | | -} |
136 | | - |
137 | | -func TestBuildTLSConfig_mTLS(t *testing.T) { |
138 | | - dir := t.TempDir() |
139 | | - _, certPath, keyPath := generateTestCert(t, dir) |
140 | | - |
141 | | - cfg, err := buildTLSConfig("", certPath, keyPath, false) |
142 | | - if err != nil { |
143 | | - t.Fatalf("unexpected error: %v", err) |
144 | | - } |
145 | | - if cfg == nil { |
146 | | - t.Fatal("expected non-nil TLS config") |
147 | | - } |
148 | | - if len(cfg.Certificates) != 1 { |
149 | | - t.Errorf("expected 1 client certificate, got %d", len(cfg.Certificates)) |
150 | | - } |
151 | | -} |
152 | | - |
153 | | -func TestBuildTLSConfig_caPlusMTLS(t *testing.T) { |
154 | | - dir := t.TempDir() |
155 | | - caPath, certPath, keyPath := generateTestCert(t, dir) |
156 | | - |
157 | | - cfg, err := buildTLSConfig(caPath, certPath, keyPath, false) |
158 | | - if err != nil { |
159 | | - t.Fatalf("unexpected error: %v", err) |
160 | | - } |
161 | | - if cfg == nil { |
162 | | - t.Fatal("expected non-nil TLS config") |
163 | | - } |
164 | | - if cfg.RootCAs == nil { |
165 | | - t.Error("expected RootCAs to be populated") |
166 | | - } |
167 | | - if len(cfg.Certificates) != 1 { |
168 | | - t.Errorf("expected 1 client certificate, got %d", len(cfg.Certificates)) |
169 | | - } |
170 | | -} |
171 | | - |
172 | | -func TestBuildTLSConfig_insecureSkipVerify(t *testing.T) { |
173 | | - cfg, err := buildTLSConfig("", "", "", true) |
174 | | - if err != nil { |
175 | | - t.Fatalf("unexpected error: %v", err) |
176 | | - } |
177 | | - if cfg == nil { |
178 | | - t.Fatal("expected non-nil TLS config") |
179 | | - } |
180 | | - if !cfg.InsecureSkipVerify { |
181 | | - t.Error("expected InsecureSkipVerify to be true") |
182 | | - } |
183 | | - if cfg.MinVersion != tls.VersionTLS12 { |
184 | | - t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, tls.VersionTLS12) |
185 | | - } |
186 | | -} |
187 | | - |
188 | | -func TestBuildTLSConfig_caCertFileNotFound(t *testing.T) { |
189 | | - _, err := buildTLSConfig("/nonexistent/ca.pem", "", "", false) |
190 | | - if err == nil { |
191 | | - t.Fatal("expected error for missing CA cert file") |
192 | | - } |
193 | | -} |
194 | | - |
195 | | -func TestBuildTLSConfig_malformedCACert(t *testing.T) { |
196 | | - dir := t.TempDir() |
197 | | - badCA := filepath.Join(dir, "bad-ca.pem") |
198 | | - if err := os.WriteFile(badCA, []byte("not a valid PEM"), 0600); err != nil { |
199 | | - t.Fatalf("write bad CA: %v", err) |
200 | | - } |
201 | | - |
202 | | - _, err := buildTLSConfig(badCA, "", "", false) |
203 | | - if err == nil { |
204 | | - t.Fatal("expected error for malformed CA cert") |
205 | | - } |
206 | | -} |
207 | | - |
208 | | -func TestBuildTLSConfig_invalidCertKeyPair(t *testing.T) { |
209 | | - dir := t.TempDir() |
210 | | - |
211 | | - certPath := filepath.Join(dir, "cert.pem") |
212 | | - keyPath := filepath.Join(dir, "key.pem") |
213 | | - if err := os.WriteFile(certPath, []byte("not a cert"), 0600); err != nil { |
214 | | - t.Fatalf("write bad cert: %v", err) |
215 | | - } |
216 | | - if err := os.WriteFile(keyPath, []byte("not a key"), 0600); err != nil { |
217 | | - t.Fatalf("write bad key: %v", err) |
218 | | - } |
219 | | - |
220 | | - _, err := buildTLSConfig("", certPath, keyPath, false) |
221 | | - if err == nil { |
222 | | - t.Fatal("expected error for invalid cert/key pair") |
223 | | - } |
224 | | -} |
0 commit comments