Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 03:30 UTC
caddytls: validate curve and protocol names, compare protocol IDs (#8266)
* caddytls: validate curve and protocol names, compare protocol IDs * caddytls: Add final newline to tests and drop duplicate protocol comment
Akinyemi Toluwalase committed
Oct 26, 2026 at 21:14 UTC
71c5812cfeb7ce9ab471d323ccd98e6fb7cf8d26
4 files changed
+79
-7
modules/caddyhttp/reverseproxy/httptransport.go
+4
-1
@@ -896,7 +896,10 @@ func (t *TLSConfig) MakeTLSClientConfig(ctx caddy.Context) (*tls.Config, error)
896
897
curvesAdded := make(map[tls.CurveID]struct{})
898
for _, curveName := range t.Curves {
899
- curveID := caddytls.SupportedCurves[curveName]
899
+ curveID, ok := caddytls.SupportedCurves[curveName]
900
+ if !ok {
901
+ return nil, fmt.Errorf("unsupported curve: %s", curveName)
902
+ }
903
if _, ok := curvesAdded[curveID]; !ok {
904
curvesAdded[curveID] = struct{}{}
905
cfg.CurvePreferences = append(cfg.CurvePreferences, curveID)
modules/caddyhttp/reverseproxy/httptransport_test.go
+10
@@ -406,3 +406,13 @@ func TestHTTPTransportH3UsesConfiguredTrustPool(t *testing.T) {
406
t.Fatal("HTTP/3 transport: TLS client config must be a clone, not the same pointer as the HTTP/1.1+2 transport's")
407
}
408
}
409
+
410
+func TestTLSConfigRejectsUnknownCurve(t *testing.T) {
411
+ ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
412
+ defer cancel()
413
+
414
+ tc := &TLSConfig{Curves: []string{"X25519"}}
415
+ if _, err := tc.MakeTLSClientConfig(ctx); err == nil {
416
+ t.Fatal("expected an error for an unknown curve, got nil")
417
+ }
418
+}
modules/caddytls/connpolicy.go
+18
-6
@@ -363,7 +363,10 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
363
// add all the curve preferences in order, without duplicates
364
curvesAdded := make(map[tls.CurveID]struct{})
365
for _, curveName := range p.Curves {
366
- curveID := SupportedCurves[curveName]
366
+ curveID, ok := SupportedCurves[curveName]
367
+ if !ok {
368
+ return fmt.Errorf("unsupported curve: %s", curveName)
369
+ }
370
if _, ok := curvesAdded[curveID]; !ok {
371
curvesAdded[curveID] = struct{}{}
372
cfg.CurvePreferences = append(cfg.CurvePreferences, curveID)
@@ -377,14 +380,23 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
380
}
381
382
// min and max protocol versions
380
- if (p.ProtocolMin != "" && p.ProtocolMax != "") && p.ProtocolMin > p.ProtocolMax {
381
- return fmt.Errorf("protocol min (%x) cannot be greater than protocol max (%x)", p.ProtocolMin, p.ProtocolMax)
382
- }
383
if p.ProtocolMin != "" {
384
- cfg.MinVersion = SupportedProtocols[p.ProtocolMin]
384
+ minVersion, ok := SupportedProtocols[p.ProtocolMin]
385
+ if !ok {
386
+ return fmt.Errorf("unsupported protocol_min: %s", p.ProtocolMin)
387
+ }
388
+ cfg.MinVersion = minVersion
389
}
390
if p.ProtocolMax != "" {
387
- cfg.MaxVersion = SupportedProtocols[p.ProtocolMax]
391
+ maxVersion, ok := SupportedProtocols[p.ProtocolMax]
392
+ if !ok {
393
+ return fmt.Errorf("unsupported protocol_max: %s", p.ProtocolMax)
394
+ }
395
+ cfg.MaxVersion = maxVersion
396
+ }
397
+ if cfg.MinVersion > cfg.MaxVersion {
398
+ return fmt.Errorf("protocol min (%s) cannot be greater than protocol max (%s)",
399
+ ProtocolName(cfg.MinVersion), ProtocolName(cfg.MaxVersion))
400
}
401
402
// client authentication
modules/caddytls/connpolicy_test.go
+47
@@ -418,3 +418,50 @@ func TestParseCaddyfileNestedMatcherSet(t *testing.T) {
418
}
419
}
420
}
421
+
422
+func TestConnectionPolicyRejectsUnknownNames(t *testing.T) {
423
+ for _, tc := range []struct {
424
+ name string
425
+ policy ConnectionPolicy
426
+ }{
427
+ {"unknown curve", ConnectionPolicy{Curves: []string{"X25519"}}},
428
+ {"unknown protocol_min", ConnectionPolicy{ProtocolMin: "TLS1.3"}},
429
+ {"unknown protocol_max", ConnectionPolicy{ProtocolMax: "tls13"}},
430
+ {"protocol_min greater than protocol_max", ConnectionPolicy{ProtocolMin: "tls1.3", ProtocolMax: "tls1.2"}},
431
+ } {
432
+ t.Run(tc.name, func(t *testing.T) {
433
+ ctx, err := caddy.ProvisionContext(&caddy.Config{})
434
+ if err != nil {
435
+ t.Fatal(err)
436
+ }
437
+ if err := (ConnectionPolicies{&tc.policy}).Provision(ctx); err == nil {
438
+ t.Fatal("expected an error, got nil")
439
+ }
440
+ })
441
+ }
442
+}
443
+
444
+func TestConnectionPolicyProtocolDefaults(t *testing.T) {
445
+ for _, tc := range []struct {
446
+ name string
447
+ policy ConnectionPolicy
448
+ min, max uint16
449
+ }{
450
+ {"both empty", ConnectionPolicy{}, tls.VersionTLS12, tls.VersionTLS13},
451
+ {"min only", ConnectionPolicy{ProtocolMin: "tls1.3"}, tls.VersionTLS13, tls.VersionTLS13},
452
+ {"max only", ConnectionPolicy{ProtocolMax: "tls1.2"}, tls.VersionTLS12, tls.VersionTLS12},
453
+ } {
454
+ t.Run(tc.name, func(t *testing.T) {
455
+ ctx, err := caddy.ProvisionContext(&caddy.Config{})
456
+ if err != nil {
457
+ t.Fatal(err)
458
+ }
459
+ if err := (ConnectionPolicies{&tc.policy}).Provision(ctx); err != nil {
460
+ t.Fatalf("unexpected error: %v", err)
461
+ }
462
+ if got := tc.policy.TLSConfig; got.MinVersion != tc.min || got.MaxVersion != tc.max {
463
+ t.Fatalf("got min=%x max=%x, want min=%x max=%x", got.MinVersion, got.MaxVersion, tc.min, tc.max)
464
+ }
465
+ })
466
+ }
467
+}