knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/network/tls/config_test.go (about) 1 /* 2 Copyright 2026 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tls 18 19 import ( 20 cryptotls "crypto/tls" 21 "testing" 22 ) 23 24 func Test_parseVersion(t *testing.T) { 25 tests := []struct { 26 name string 27 input string 28 want uint16 29 wantErr bool 30 }{ 31 {name: "TLS 1.2", input: "1.2", want: cryptotls.VersionTLS12}, 32 {name: "TLS 1.3", input: "1.3", want: cryptotls.VersionTLS13}, 33 {name: "unsupported version", input: "1.0", wantErr: true}, 34 {name: "unsupported version 1.1", input: "1.1", wantErr: true}, 35 {name: "trailing space", input: "1.2 ", wantErr: true}, 36 {name: "empty string", input: "", wantErr: true}, 37 {name: "garbage", input: "abc", wantErr: true}, 38 } 39 40 for _, tc := range tests { 41 t.Run(tc.name, func(t *testing.T) { 42 got, err := parseVersion(tc.input) 43 if tc.wantErr { 44 if err == nil { 45 t.Fatalf("parseVersion(%q) = %d, want error", tc.input, got) 46 } 47 return 48 } 49 if err != nil { 50 t.Fatalf("parseVersion(%q) unexpected error: %v", tc.input, err) 51 } 52 if got != tc.want { 53 t.Errorf("parseVersion(%q) = %d, want %d", tc.input, got, tc.want) 54 } 55 }) 56 } 57 } 58 59 func Test_parseCipherSuites(t *testing.T) { 60 tests := []struct { 61 name string 62 input string 63 want []uint16 64 wantErr bool 65 }{ 66 { 67 name: "single suite", 68 input: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 69 want: []uint16{cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 70 }, 71 { 72 name: "multiple suites", 73 input: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 74 want: []uint16{ 75 cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 76 cryptotls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 77 }, 78 }, 79 { 80 name: "whitespace trimmed", 81 input: " TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 , TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ", 82 want: []uint16{ 83 cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 84 cryptotls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 85 }, 86 }, 87 { 88 name: "empty parts skipped", 89 input: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,,", 90 want: []uint16{cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, 91 }, 92 { 93 name: "unknown suite", 94 input: "DOES_NOT_EXIST", 95 wantErr: true, 96 }, 97 { 98 name: "empty string", 99 want: []uint16{}, 100 }, 101 } 102 103 for _, tc := range tests { 104 t.Run(tc.name, func(t *testing.T) { 105 got, err := parseCipherSuites(tc.input) 106 if tc.wantErr { 107 if err == nil { 108 t.Fatalf("parseCipherSuites(%q) = %v, want error", tc.input, got) 109 } 110 return 111 } 112 if err != nil { 113 t.Fatalf("parseCipherSuites(%q) unexpected error: %v", tc.input, err) 114 } 115 if len(got) != len(tc.want) { 116 t.Fatalf("parseCipherSuites(%q) returned %d suites, want %d", tc.input, len(got), len(tc.want)) 117 } 118 for i := range tc.want { 119 if got[i] != tc.want[i] { 120 t.Errorf("parseCipherSuites(%q)[%d] = %d, want %d", tc.input, i, got[i], tc.want[i]) 121 } 122 } 123 }) 124 } 125 } 126 127 func Test_parseCurvePreferences(t *testing.T) { 128 tests := []struct { 129 name string 130 input string 131 want []cryptotls.CurveID 132 wantErr bool 133 }{ 134 { 135 name: "Go constant name X25519", 136 input: "X25519", 137 want: []cryptotls.CurveID{cryptotls.X25519}, 138 }, 139 { 140 name: "Go constant name CurveP256", 141 input: "CurveP256", 142 want: []cryptotls.CurveID{cryptotls.CurveP256}, 143 }, 144 { 145 name: "standard name P-256", 146 input: "P-256", 147 want: []cryptotls.CurveID{cryptotls.CurveP256}, 148 }, 149 { 150 name: "multiple curves with mixed naming", 151 input: "X25519,P-256,CurveP384", 152 want: []cryptotls.CurveID{ 153 cryptotls.X25519, 154 cryptotls.CurveP256, 155 cryptotls.CurveP384, 156 }, 157 }, 158 { 159 name: "whitespace trimmed", 160 input: " X25519 , CurveP256 ", 161 want: []cryptotls.CurveID{ 162 cryptotls.X25519, 163 cryptotls.CurveP256, 164 }, 165 }, 166 { 167 name: "all curves by standard name", 168 input: "P-256,P-384,P-521,X25519", 169 want: []cryptotls.CurveID{ 170 cryptotls.CurveP256, 171 cryptotls.CurveP384, 172 cryptotls.CurveP521, 173 cryptotls.X25519, 174 }, 175 }, 176 { 177 name: "post-quantum hybrid X25519MLKEM768", 178 input: "X25519MLKEM768", 179 want: []cryptotls.CurveID{cryptotls.X25519MLKEM768}, 180 }, 181 { 182 name: "unknown curve", 183 input: "CurveP128", 184 wantErr: true, 185 }, 186 { 187 name: "empty string", 188 want: []cryptotls.CurveID{}, 189 }, 190 } 191 192 for _, tc := range tests { 193 t.Run(tc.name, func(t *testing.T) { 194 got, err := parseCurvePreferences(tc.input) 195 if tc.wantErr { 196 if err == nil { 197 t.Fatalf("parseCurvePreferences(%q) = %v, want error", tc.input, got) 198 } 199 return 200 } 201 if err != nil { 202 t.Fatalf("parseCurvePreferences(%q) unexpected error: %v", tc.input, err) 203 } 204 if len(got) != len(tc.want) { 205 t.Fatalf("parseCurvePreferences(%q) returned %d curves, want %d", tc.input, len(got), len(tc.want)) 206 } 207 for i := range tc.want { 208 if got[i] != tc.want[i] { 209 t.Errorf("parseCurvePreferences(%q)[%d] = %d, want %d", tc.input, i, got[i], tc.want[i]) 210 } 211 } 212 }) 213 } 214 } 215 216 func TestDefaultConfigFromEnv(t *testing.T) { 217 t.Run("no env vars returns TLS 1.3 default", func(t *testing.T) { 218 cfg, err := DefaultConfigFromEnv("") 219 if err != nil { 220 t.Fatal("unexpected error:", err) 221 } 222 if cfg.MinVersion != cryptotls.VersionTLS13 { 223 t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, cryptotls.VersionTLS13) 224 } 225 if cfg.MaxVersion != 0 { 226 t.Errorf("MaxVersion = %d, want 0", cfg.MaxVersion) 227 } 228 if cfg.CipherSuites != nil { 229 t.Errorf("CipherSuites = %v, want nil", cfg.CipherSuites) 230 } 231 if cfg.CurvePreferences != nil { 232 t.Errorf("CurvePreferences = %v, want nil", cfg.CurvePreferences) 233 } 234 }) 235 236 t.Run("min version from env overrides default", func(t *testing.T) { 237 t.Setenv(MinVersionEnvKey, "1.2") 238 cfg, err := DefaultConfigFromEnv("") 239 if err != nil { 240 t.Fatal("unexpected error:", err) 241 } 242 if cfg.MinVersion != cryptotls.VersionTLS12 { 243 t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, cryptotls.VersionTLS12) 244 } 245 }) 246 247 t.Run("max version from env", func(t *testing.T) { 248 t.Setenv(MaxVersionEnvKey, "1.3") 249 cfg, err := DefaultConfigFromEnv("") 250 if err != nil { 251 t.Fatal("unexpected error:", err) 252 } 253 if cfg.MaxVersion != cryptotls.VersionTLS13 { 254 t.Errorf("MaxVersion = %d, want %d", cfg.MaxVersion, cryptotls.VersionTLS13) 255 } 256 }) 257 258 t.Run("cipher suites from env", func(t *testing.T) { 259 t.Setenv(CipherSuitesEnvKey, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") 260 cfg, err := DefaultConfigFromEnv("") 261 if err != nil { 262 t.Fatal("unexpected error:", err) 263 } 264 if len(cfg.CipherSuites) != 1 || cfg.CipherSuites[0] != cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { 265 t.Errorf("CipherSuites = %v, want [%d]", cfg.CipherSuites, cryptotls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) 266 } 267 }) 268 269 t.Run("curve preferences from env", func(t *testing.T) { 270 t.Setenv(CurvePreferencesEnvKey, "X25519,CurveP256") 271 cfg, err := DefaultConfigFromEnv("") 272 if err != nil { 273 t.Fatal("unexpected error:", err) 274 } 275 if len(cfg.CurvePreferences) != 2 { 276 t.Fatalf("CurvePreferences has %d entries, want 2", len(cfg.CurvePreferences)) 277 } 278 if cfg.CurvePreferences[0] != cryptotls.X25519 { 279 t.Errorf("CurvePreferences[0] = %d, want %d", cfg.CurvePreferences[0], cryptotls.X25519) 280 } 281 if cfg.CurvePreferences[1] != cryptotls.CurveP256 { 282 t.Errorf("CurvePreferences[1] = %d, want %d", cfg.CurvePreferences[1], cryptotls.CurveP256) 283 } 284 }) 285 286 t.Run("prefix is prepended to env key", func(t *testing.T) { 287 t.Setenv("WEBHOOK_TLS_MIN_VERSION", "1.2") 288 cfg, err := DefaultConfigFromEnv("WEBHOOK_") 289 if err != nil { 290 t.Fatal("unexpected error:", err) 291 } 292 if cfg.MinVersion != cryptotls.VersionTLS12 { 293 t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, cryptotls.VersionTLS12) 294 } 295 }) 296 297 t.Run("all env vars set", func(t *testing.T) { 298 t.Setenv(MinVersionEnvKey, "1.2") 299 t.Setenv(MaxVersionEnvKey, "1.3") 300 t.Setenv(CipherSuitesEnvKey, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384") 301 t.Setenv(CurvePreferencesEnvKey, "X25519,P-256") 302 303 cfg, err := DefaultConfigFromEnv("") 304 if err != nil { 305 t.Fatal("unexpected error:", err) 306 } 307 if cfg.MinVersion != cryptotls.VersionTLS12 { 308 t.Errorf("MinVersion = %d, want %d", cfg.MinVersion, cryptotls.VersionTLS12) 309 } 310 if cfg.MaxVersion != cryptotls.VersionTLS13 { 311 t.Errorf("MaxVersion = %d, want %d", cfg.MaxVersion, cryptotls.VersionTLS13) 312 } 313 if len(cfg.CipherSuites) != 2 { 314 t.Fatalf("CipherSuites has %d entries, want 2", len(cfg.CipherSuites)) 315 } 316 if len(cfg.CurvePreferences) != 2 { 317 t.Fatalf("CurvePreferences has %d entries, want 2", len(cfg.CurvePreferences)) 318 } 319 }) 320 321 t.Run("invalid min version", func(t *testing.T) { 322 t.Setenv(MinVersionEnvKey, "1.0") 323 _, err := DefaultConfigFromEnv("") 324 if err == nil { 325 t.Fatal("expected error for invalid min version") 326 } 327 }) 328 329 t.Run("invalid max version", func(t *testing.T) { 330 t.Setenv(MaxVersionEnvKey, "bad") 331 _, err := DefaultConfigFromEnv("") 332 if err == nil { 333 t.Fatal("expected error for invalid max version") 334 } 335 }) 336 337 t.Run("invalid cipher suite", func(t *testing.T) { 338 t.Setenv(CipherSuitesEnvKey, "NOT_A_REAL_CIPHER") 339 _, err := DefaultConfigFromEnv("") 340 if err == nil { 341 t.Fatal("expected error for invalid cipher suite") 342 } 343 }) 344 345 t.Run("invalid curve", func(t *testing.T) { 346 t.Setenv(CurvePreferencesEnvKey, "NotACurve") 347 _, err := DefaultConfigFromEnv("") 348 if err == nil { 349 t.Fatal("expected error for invalid curve") 350 } 351 }) 352 }