mirror of
https://github.com/caddyserver/caddy.git
synced 2025-03-06 13:09:03 -05:00
Compare commits
7 Commits
b2f8ddb652
...
167d36e6d8
Author | SHA1 | Date | |
---|---|---|---|
|
167d36e6d8 | ||
|
eacd7720e9 | ||
|
02e348f911 | ||
|
f85be6a190 | ||
|
12d3591944 | ||
|
b773cc4e3e | ||
|
11fd2dcb2b |
8
go.mod
8
go.mod
@ -22,8 +22,8 @@ require (
|
||||
github.com/smallstep/certificates v0.26.1
|
||||
github.com/smallstep/nosql v0.6.1
|
||||
github.com/smallstep/truststore v0.13.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
@ -53,7 +53,7 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 // indirect
|
||||
github.com/google/go-tpm v0.9.0 // indirect
|
||||
@ -89,7 +89,7 @@ require (
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/dgraph-io/badger v1.6.2 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
|
||||
github.com/dgraph-io/ristretto v0.2.0 // indirect
|
||||
|
16
go.sum
16
go.sum
@ -121,8 +121,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@ -160,8 +160,8 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
|
||||
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
|
||||
@ -469,12 +469,12 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
|
@ -384,131 +384,127 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
||||
|
||||
repl.Map(httpVars)
|
||||
}
|
||||
// handleMTLSEnabledWithExport populates placeholders or a map with server and client certificate details.
|
||||
// - req: The incoming HTTP request.
|
||||
// - connState: The TLS connection state containing certificate information.
|
||||
// - exportCertData: If true, the data will be set in Caddy's Replacer placeholders; otherwise, it will populate the certDetails map.
|
||||
func handleMTLSEnabledWithExport(
|
||||
req *http.Request,
|
||||
connState *tls.ConnectionState,
|
||||
exportCertData bool,
|
||||
) map[string]string {
|
||||
certDetails := make(map[string]string)
|
||||
|
||||
func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||
if req == nil || req.TLS == nil {
|
||||
return nil, false
|
||||
}
|
||||
// Attempt to retrieve the Replacer from the request context
|
||||
repl, _ := req.Context().Value(ReplacerCtxKey).(*caddy.Replacer)
|
||||
|
||||
if len(key) < len(reqTLSReplPrefix) {
|
||||
return nil, false
|
||||
}
|
||||
// Helper function to set data either in Replacer placeholders or in the certDetails map
|
||||
setData := func(key, value string) {
|
||||
if exportCertData && repl != nil {
|
||||
repl.Set(key, value)
|
||||
} else {
|
||||
certDetails[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
field := strings.ToLower(key[len(reqTLSReplPrefix):])
|
||||
// Populate server certificate details
|
||||
if connState != nil && len(connState.PeerCertificates) > 0 {
|
||||
serverCert := connState.PeerCertificates[0]
|
||||
setData("http.request.tls.server.certificate_pem", string(pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: serverCert.Raw,
|
||||
})))
|
||||
setData("http.request.tls.server.subject", serverCert.Subject.String())
|
||||
setData("http.request.tls.server.issuer", serverCert.Issuer.String())
|
||||
} else {
|
||||
// Fallback values if no server certificate is present
|
||||
setData("http.request.tls.server.certificate_pem", "")
|
||||
setData("http.request.tls.server.subject", "No Server Certificate Subject")
|
||||
setData("http.request.tls.server.issuer", "No Server Certificate Issuer")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(field, "client.") {
|
||||
cert := getTLSPeerCert(req.TLS)
|
||||
if cert == nil {
|
||||
return nil, false
|
||||
}
|
||||
// Populate client certificate details (if mTLS is enabled and a client certificate is provided)
|
||||
if connState != nil && len(connState.VerifiedChains) > 0 {
|
||||
clientCert := connState.VerifiedChains[0][0]
|
||||
setData("http.request.tls.client.certificate_pem", string(pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: clientCert.Raw,
|
||||
})))
|
||||
setData("http.request.tls.client.subject", clientCert.Subject.String())
|
||||
setData("http.request.tls.client.issuer", clientCert.Issuer.String())
|
||||
} else {
|
||||
// Fallback values if no client certificate is provided
|
||||
setData("http.request.tls.client.certificate_pem", "")
|
||||
setData("http.request.tls.client.subject", "No Client Certificate Subject")
|
||||
setData("http.request.tls.client.issuer", "No Client Certificate Issuer")
|
||||
}
|
||||
|
||||
// subject alternate names (SANs)
|
||||
if strings.HasPrefix(field, "client.san.") {
|
||||
field = field[len("client.san."):]
|
||||
var fieldName string
|
||||
var fieldValue any
|
||||
switch {
|
||||
case strings.HasPrefix(field, "dns_names"):
|
||||
fieldName = "dns_names"
|
||||
fieldValue = cert.DNSNames
|
||||
case strings.HasPrefix(field, "emails"):
|
||||
fieldName = "emails"
|
||||
fieldValue = cert.EmailAddresses
|
||||
case strings.HasPrefix(field, "ips"):
|
||||
fieldName = "ips"
|
||||
fieldValue = cert.IPAddresses
|
||||
case strings.HasPrefix(field, "uris"):
|
||||
fieldName = "uris"
|
||||
fieldValue = cert.URIs
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
field = field[len(fieldName):]
|
||||
|
||||
// if no index was specified, return the whole list
|
||||
if field == "" {
|
||||
return fieldValue, true
|
||||
}
|
||||
if len(field) < 2 || field[0] != '.' {
|
||||
return nil, false
|
||||
}
|
||||
field = field[1:] // trim '.' between field name and index
|
||||
|
||||
// get the numeric index
|
||||
idx, err := strconv.Atoi(field)
|
||||
if err != nil || idx < 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// access the indexed element and return it
|
||||
switch v := fieldValue.(type) {
|
||||
case []string:
|
||||
if idx >= len(v) {
|
||||
return nil, true
|
||||
}
|
||||
return v[idx], true
|
||||
case []net.IP:
|
||||
if idx >= len(v) {
|
||||
return nil, true
|
||||
}
|
||||
return v[idx], true
|
||||
case []*url.URL:
|
||||
if idx >= len(v) {
|
||||
return nil, true
|
||||
}
|
||||
return v[idx], true
|
||||
}
|
||||
}
|
||||
|
||||
switch field {
|
||||
case "client.fingerprint":
|
||||
return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
|
||||
case "client.public_key", "client.public_key_sha256":
|
||||
if cert.PublicKey == nil {
|
||||
return nil, true
|
||||
}
|
||||
pubKeyBytes, err := marshalPublicKey(cert.PublicKey)
|
||||
if err != nil {
|
||||
return nil, true
|
||||
}
|
||||
if strings.HasSuffix(field, "_sha256") {
|
||||
return fmt.Sprintf("%x", sha256.Sum256(pubKeyBytes)), true
|
||||
}
|
||||
return fmt.Sprintf("%x", pubKeyBytes), true
|
||||
case "client.issuer":
|
||||
return cert.Issuer, true
|
||||
case "client.serial":
|
||||
return cert.SerialNumber, true
|
||||
case "client.subject":
|
||||
return cert.Subject, true
|
||||
case "client.certificate_pem":
|
||||
block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
||||
return pem.EncodeToMemory(&block), true
|
||||
case "client.certificate_der_base64":
|
||||
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
switch field {
|
||||
case "version":
|
||||
return caddytls.ProtocolName(req.TLS.Version), true
|
||||
case "cipher_suite":
|
||||
return tls.CipherSuiteName(req.TLS.CipherSuite), true
|
||||
case "resumed":
|
||||
return req.TLS.DidResume, true
|
||||
case "proto":
|
||||
return req.TLS.NegotiatedProtocol, true
|
||||
case "proto_mutual":
|
||||
// req.TLS.NegotiatedProtocolIsMutual is deprecated - it's always true.
|
||||
return true, true
|
||||
case "server_name":
|
||||
return req.TLS.ServerName, true
|
||||
}
|
||||
return nil, false
|
||||
return certDetails
|
||||
}
|
||||
|
||||
// getReqTLSReplacement retrieves specific TLS-related placeholder values for a given request and key.
|
||||
// - req: The incoming HTTP request.
|
||||
// - key: The placeholder key to retrieve.
|
||||
// Returns the placeholder value and whether it was found.
|
||||
func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||
if req == nil || req.TLS == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if len(key) < len(reqTLSReplPrefix) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
field := strings.ToLower(key[len(reqTLSReplPrefix):])
|
||||
|
||||
// Check if the key refers to client or server placeholders
|
||||
if strings.HasPrefix(field, "client.") || strings.HasPrefix(field, "server.") {
|
||||
// Populate placeholders using handleMTLSEnabledWithExport
|
||||
handleMTLSEnabledWithExport(req, req.TLS, true)
|
||||
|
||||
// Handle client-specific placeholders
|
||||
if strings.HasPrefix(field, "client.") {
|
||||
cert := getTLSPeerCert(req.TLS)
|
||||
if cert == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
switch field {
|
||||
case "client.fingerprint":
|
||||
return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)), true
|
||||
case "client.subject":
|
||||
return cert.Subject, true
|
||||
case "client.issuer":
|
||||
return cert.Issuer, true
|
||||
case "client.certificate_pem":
|
||||
block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
||||
return pem.EncodeToMemory(&block), true
|
||||
case "client.certificate_der_base64":
|
||||
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle general TLS-related placeholders
|
||||
switch field {
|
||||
case "version":
|
||||
return caddytls.ProtocolName(req.TLS.Version), true
|
||||
case "cipher_suite":
|
||||
return tls.CipherSuiteName(req.TLS.CipherSuite), true
|
||||
case "resumed":
|
||||
return req.TLS.DidResume, true
|
||||
case "proto":
|
||||
return req.TLS.NegotiatedProtocol, true
|
||||
case "proto_mutual":
|
||||
// req.TLS.NegotiatedProtocolIsMutual is deprecated - it's always true.
|
||||
return true, true
|
||||
case "server_name":
|
||||
return req.TLS.ServerName, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
||||
// marshalPublicKey returns the byte encoding of pubKey.
|
||||
func marshalPublicKey(pubKey any) ([]byte, error) {
|
||||
switch key := pubKey.(type) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user