From 2ef8fdfaafdcc7c1340d8568e4fb849af97eea96 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Wed, 8 May 2024 20:10:52 -0600 Subject: [PATCH] Stricter TLS-ALPN challenge matching According to RFC 8737. --- handshake.go | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/handshake.go b/handshake.go index bd23ac61..a90afd86 100644 --- a/handshake.go +++ b/handshake.go @@ -65,24 +65,27 @@ func (cfg *Config) GetCertificateWithContext(ctx context.Context, clientHello *t ctx = context.WithValue(ctx, ClientHelloInfoCtxKey, clientHello) // special case: serve up the certificate for a TLS-ALPN ACME challenge - // (https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05) - for _, proto := range clientHello.SupportedProtos { - if proto == acmez.ACMETLS1Protocol { - challengeCert, distributed, err := cfg.getTLSALPNChallengeCert(clientHello) - if err != nil { - cfg.Logger.Error("tls-alpn challenge", - zap.String("remote_addr", clientHello.Conn.RemoteAddr().String()), - zap.String("server_name", clientHello.ServerName), - zap.Error(err)) - return nil, err - } - cfg.Logger.Info("served key authentication certificate", + // (https://www.rfc-editor.org/rfc/rfc8737.html) + // "The ACME server MUST provide an ALPN extension with the single protocol + // name "acme-tls/1" and an SNI extension containing only the domain name + // being validated during the TLS handshake." + if clientHello.ServerName != "" && + len(clientHello.SupportedProtos) == 1 && + clientHello.SupportedProtos[0] == acmez.ACMETLS1Protocol { + challengeCert, distributed, err := cfg.getTLSALPNChallengeCert(clientHello) + if err != nil { + cfg.Logger.Error("tls-alpn challenge", + zap.String("remote_addr", clientHello.Conn.RemoteAddr().String()), zap.String("server_name", clientHello.ServerName), - zap.String("challenge", "tls-alpn-01"), - zap.String("remote", clientHello.Conn.RemoteAddr().String()), - zap.Bool("distributed", distributed)) - return challengeCert, nil + zap.Error(err)) + return nil, err } + cfg.Logger.Info("served key authentication certificate", + zap.String("server_name", clientHello.ServerName), + zap.String("challenge", "tls-alpn-01"), + zap.String("remote", clientHello.Conn.RemoteAddr().String()), + zap.Bool("distributed", distributed)) + return challengeCert, nil } // get the certificate and serve it up