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, 11:00 UTC
caddytls: Fix client auth (fix #7724) (#7727)
The peer certificates should be loaded even if existingVerifyPeerCert is nil. Patched with the assistance of Copilot, as an experiment.
Matt Holt committed
May 14, 2026 at 10:05 UTC
6c675e29f87cbe7326983ddb6d739175119d394c
2 files changed
+65
-5
modules/caddytls/connpolicy.go
+6
-5
@@ -896,18 +896,19 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro
896
// Unlike VerifyPeerCertificate, VerifyConnection is called on every
897
// connection including resumed sessions, preventing session-resumption bypass.
898
func (clientauth *ClientAuthentication) verifyConnection(cs tls.ConnectionState) error {
899
+ rawCerts := make([][]byte, len(cs.PeerCertificates))
900
+ for i, cert := range cs.PeerCertificates {
901
+ rawCerts[i] = cert.Raw
902
+ }
903
+
904
// first use any pre-existing custom verification function
905
if clientauth.existingVerifyPeerCert != nil {
901
- rawCerts := make([][]byte, len(cs.PeerCertificates))
902
- for i, cert := range cs.PeerCertificates {
903
- rawCerts[i] = cert.Raw
904
- }
906
if err := clientauth.existingVerifyPeerCert(rawCerts, cs.VerifiedChains); err != nil {
907
return err
908
}
909
}
910
for _, verifier := range clientauth.verifiers {
910
- if err := verifier.VerifyClientCertificate(nil, cs.VerifiedChains); err != nil {
911
+ if err := verifier.VerifyClientCertificate(rawCerts, cs.VerifiedChains); err != nil {
912
return err
913
}
914
}
modules/caddytls/connpolicy_verifyconnection_test.go
new
+59
@@ -0,0 +1,59 @@
1
+package caddytls
2
+
3
+import (
4
+ "crypto/tls"
5
+ "crypto/x509"
6
+ "errors"
7
+ "reflect"
8
+ "testing"
9
+)
10
+
11
+type testClientCertificateVerifier struct {
12
+ rawCerts [][]byte
13
+ verifiedChains [][]*x509.Certificate
14
+ err error
15
+}
16
+
17
+func (v *testClientCertificateVerifier) VerifyClientCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
18
+ v.rawCerts = rawCerts
19
+ v.verifiedChains = verifiedChains
20
+ return v.err
21
+}
22
+
23
+func TestClientAuthenticationVerifyConnectionPassesRawCertsToVerifiers(t *testing.T) {
24
+ verifier := &testClientCertificateVerifier{}
25
+ clientauth := &ClientAuthentication{
26
+ verifiers: []ClientCertificateVerifier{verifier},
27
+ }
28
+
29
+ peerCert := &x509.Certificate{Raw: []byte("peer-cert-raw")}
30
+ verifiedChains := [][]*x509.Certificate{{peerCert}}
31
+ connState := tls.ConnectionState{
32
+ PeerCertificates: []*x509.Certificate{peerCert},
33
+ VerifiedChains: verifiedChains,
34
+ }
35
+
36
+ if err := clientauth.verifyConnection(connState); err != nil {
37
+ t.Fatalf("verifyConnection failed: %v", err)
38
+ }
39
+
40
+ if !reflect.DeepEqual(verifier.rawCerts, [][]byte{[]byte("peer-cert-raw")}) {
41
+ t.Fatalf("unexpected raw certs: got %#v", verifier.rawCerts)
42
+ }
43
+ if !reflect.DeepEqual(verifier.verifiedChains, verifiedChains) {
44
+ t.Fatalf("unexpected verified chains: got %#v", verifier.verifiedChains)
45
+ }
46
+}
47
+
48
+func TestClientAuthenticationVerifyConnectionReturnsVerifierError(t *testing.T) {
49
+ wantErr := errors.New("verify failed")
50
+ verifier := &testClientCertificateVerifier{err: wantErr}
51
+ clientauth := &ClientAuthentication{
52
+ verifiers: []ClientCertificateVerifier{verifier},
53
+ }
54
+
55
+ err := clientauth.verifyConnection(tls.ConnectionState{})
56
+ if !errors.Is(err, wantErr) {
57
+ t.Fatalf("expected error %v, got %v", wantErr, err)
58
+ }
59
+}