@marcel91200 / caddy Mirror · read-only / commits / 71c5812c
Fork 0

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 +}