carlos / platform Public

edge: tls-alpn-01 hellos bypass the wildcard to reach autocert's challenge cert

wrapGetCertificate answered a tls-alpn-01 validation ClientHello
(SupportedProtos == ["acme-tls/1"]) for a covered host with the wildcard
instead of autocert's per-host challenge cert, failing that validation. The
CA is probing the per-host order the inner path holds, so those hellos must
always reach inner, never the wildcard.
Paul Campbell 7147f2bb6f5b3776e1fa8cc659c560e4a1c20afd parent 0d8ab51
2 files changed, +14 −0
  • internal/edge/wildcard.go +6 −0
  • internal/edge/wildcard_test.go +8 −0
diff --git a/internal/edge/wildcard.go b/internal/edge/wildcard.go
index d3d7a2988..251c8e0fc 100644
--- a/internal/edge/wildcard.go
+++ b/internal/edge/wildcard.go
@@ -540,6 +540,12 @@ func newWildcardFromEnv(e *Edge, cache autocert.Cache) *wildcardManager {
// fall-through contract is testable without a TLS listener.
func wrapGetCertificate(w *wildcardManager, inner func(*tls.ClientHelloInfo) (*tls.Certificate, error)) func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
return func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ // A tls-alpn-01 validation handshake must reach autocert's challenge
+ // cert, never the wildcard — the CA is probing the per-host order the
+ // inner path holds.
+ if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
+ return inner(hello)
+ }
if c := w.certFor(hello.ServerName); c != nil {
return c, nil
}
diff --git a/internal/edge/wildcard_test.go b/internal/edge/wildcard_test.go
index e16e6bf2c..4925d6918 100644
--- a/internal/edge/wildcard_test.go
+++ b/internal/edge/wildcard_test.go
@@ -345,6 +345,14 @@ func TestWrappedGetCertificateFallsThrough(t *testing.T) {
if _, err := wrapped(&tls.ClientHelloInfo{ServerName: "custom.example.com"}); err == nil || fallbackHit != "custom.example.com" {
t.Fatalf("uncovered name must fall through to inner; fallbackHit=%q err=%v", fallbackHit, err)
}
+
+ // A tls-alpn-01 validation ClientHello for a COVERED name must still
+ // reach autocert's challenge cert, not the wildcard — otherwise that
+ // validation fails every time.
+ fallbackHit = ""
+ if _, err := wrapped(&tls.ClientHelloInfo{ServerName: "new.abs.oncarlos.com", SupportedProtos: []string{"acme-tls/1"}}); err == nil || fallbackHit != "new.abs.oncarlos.com" {
+ t.Fatalf("tls-alpn-01 hello for covered name must reach inner; fallbackHit=%q err=%v", fallbackHit, err)
+ }
}
func TestNewWildcardFromEnv(t *testing.T) {