mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-13 03:26:37 +01:00
Implement mod_ssl-like behavior: Placeholder support for server and client certificates
This commit is contained in:
parent
b773cc4e3e
commit
12d3591944
1 changed files with 48 additions and 41 deletions
|
@ -384,6 +384,10 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
||||||
|
|
||||||
repl.Map(httpVars)
|
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(
|
func handleMTLSEnabledWithExport(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
connState *tls.ConnectionState,
|
connState *tls.ConnectionState,
|
||||||
|
@ -391,10 +395,10 @@ func handleMTLSEnabledWithExport(
|
||||||
) map[string]string {
|
) map[string]string {
|
||||||
certDetails := make(map[string]string)
|
certDetails := make(map[string]string)
|
||||||
|
|
||||||
// Get the Caddy replacer from the request context
|
// Attempt to retrieve the Replacer from the request context
|
||||||
repl, _ := req.Context().Value(ReplacerCtxKey).(*caddy.Replacer)
|
repl, _ := req.Context().Value(ReplacerCtxKey).(*caddy.Replacer)
|
||||||
|
|
||||||
// Helper function to set placeholders or map values
|
// Helper function to set data either in Replacer placeholders or in the certDetails map
|
||||||
setData := func(key, value string) {
|
setData := func(key, value string) {
|
||||||
if exportCertData && repl != nil {
|
if exportCertData && repl != nil {
|
||||||
repl.Set(key, value)
|
repl.Set(key, value)
|
||||||
|
@ -403,46 +407,45 @@ func handleMTLSEnabledWithExport(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server certificate details
|
// Populate server certificate details
|
||||||
if connState != nil && len(connState.PeerCertificates) > 0 {
|
if connState != nil && len(connState.PeerCertificates) > 0 {
|
||||||
serverCert := connState.PeerCertificates[0]
|
serverCert := connState.PeerCertificates[0]
|
||||||
setData("SSL_SERVER_CERT", string(pem.EncodeToMemory(&pem.Block{
|
setData("http.request.tls.server.certificate_pem", string(pem.EncodeToMemory(&pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: serverCert.Raw,
|
Bytes: serverCert.Raw,
|
||||||
})))
|
})))
|
||||||
setData("SSL_SERVER_SUBJECT", serverCert.Subject.String())
|
setData("http.request.tls.server.subject", serverCert.Subject.String())
|
||||||
setData("SSL_SERVER_ISSUER", serverCert.Issuer.String())
|
setData("http.request.tls.server.issuer", serverCert.Issuer.String())
|
||||||
} else {
|
} else {
|
||||||
setData("SSL_SERVER_CERT", "No Server Certificate Found")
|
// Fallback values if no server certificate is present
|
||||||
setData("SSL_SERVER_SUBJECT", "No Server Certificate Subject")
|
setData("http.request.tls.server.certificate_pem", "")
|
||||||
setData("SSL_SERVER_ISSUER", "No Server Certificate Issuer")
|
setData("http.request.tls.server.subject", "No Server Certificate Subject")
|
||||||
|
setData("http.request.tls.server.issuer", "No Server Certificate Issuer")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client certificate details
|
// Populate client certificate details (if mTLS is enabled and a client certificate is provided)
|
||||||
if connState != nil && len(connState.VerifiedChains) > 0 {
|
if connState != nil && len(connState.VerifiedChains) > 0 {
|
||||||
clientCert := connState.VerifiedChains[0][0]
|
clientCert := connState.VerifiedChains[0][0]
|
||||||
setData("SSL_CLIENT_CERT", string(pem.EncodeToMemory(&pem.Block{
|
setData("http.request.tls.client.certificate_pem", string(pem.EncodeToMemory(&pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: clientCert.Raw,
|
Bytes: clientCert.Raw,
|
||||||
})))
|
})))
|
||||||
setData("SSL_CLIENT_SUBJECT", clientCert.Subject.String())
|
setData("http.request.tls.client.subject", clientCert.Subject.String())
|
||||||
setData("SSL_CLIENT_ISSUER", clientCert.Issuer.String())
|
setData("http.request.tls.client.issuer", clientCert.Issuer.String())
|
||||||
} else {
|
} else {
|
||||||
// Fallback: Set SSL_CLIENT_CERT to "null" or empty when no client certificate is provided
|
// Fallback values if no client certificate is provided
|
||||||
if exportCertData && repl != nil {
|
setData("http.request.tls.client.certificate_pem", "")
|
||||||
repl.Set("SSL_CLIENT_CERT", "") // Empty string represents "null"
|
setData("http.request.tls.client.subject", "No Client Certificate Subject")
|
||||||
repl.Set("SSL_CLIENT_SUBJECT", "No Client Certificate Subject")
|
setData("http.request.tls.client.issuer", "No Client Certificate Issuer")
|
||||||
repl.Set("SSL_CLIENT_ISSUER", "No Client Certificate Issuer")
|
|
||||||
} else {
|
|
||||||
certDetails["SSL_CLIENT_CERT"] = "" // Empty string represents "null"
|
|
||||||
certDetails["SSL_CLIENT_SUBJECT"] = "No Client Certificate Subject"
|
|
||||||
certDetails["SSL_CLIENT_ISSUER"] = "No Client Certificate Issuer"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return certDetails
|
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) {
|
func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||||
if req == nil || req.TLS == nil {
|
if req == nil || req.TLS == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -454,11 +457,12 @@ func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||||
|
|
||||||
field := strings.ToLower(key[len(reqTLSReplPrefix):])
|
field := strings.ToLower(key[len(reqTLSReplPrefix):])
|
||||||
|
|
||||||
// Process client and server placeholders
|
// Check if the key refers to client or server placeholders
|
||||||
if strings.HasPrefix(field, "client.") || strings.HasPrefix(field, "server.") {
|
if strings.HasPrefix(field, "client.") || strings.HasPrefix(field, "server.") {
|
||||||
|
// Populate placeholders using handleMTLSEnabledWithExport
|
||||||
handleMTLSEnabledWithExport(req, req.TLS, true)
|
handleMTLSEnabledWithExport(req, req.TLS, true)
|
||||||
|
|
||||||
// Continue processing for specific fields
|
// Handle client-specific placeholders
|
||||||
if strings.HasPrefix(field, "client.") {
|
if strings.HasPrefix(field, "client.") {
|
||||||
cert := getTLSPeerCert(req.TLS)
|
cert := getTLSPeerCert(req.TLS)
|
||||||
if cert == nil {
|
if cert == nil {
|
||||||
|
@ -479,7 +483,9 @@ func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||||
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle general TLS-related placeholders
|
||||||
switch field {
|
switch field {
|
||||||
case "version":
|
case "version":
|
||||||
return caddytls.ProtocolName(req.TLS.Version), true
|
return caddytls.ProtocolName(req.TLS.Version), true
|
||||||
|
@ -498,6 +504,7 @@ func getReqTLSReplacement(req *http.Request, key string) (any, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// marshalPublicKey returns the byte encoding of pubKey.
|
// marshalPublicKey returns the byte encoding of pubKey.
|
||||||
func marshalPublicKey(pubKey any) ([]byte, error) {
|
func marshalPublicKey(pubKey any) ([]byte, error) {
|
||||||
switch key := pubKey.(type) {
|
switch key := pubKey.(type) {
|
||||||
|
|
Loading…
Reference in a new issue