mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
caddyhttp: Add client cert SAN placeholders
This commit is contained in:
parent
b3bff13f7d
commit
d55c3b31eb
4 changed files with 87 additions and 5 deletions
|
@ -72,9 +72,15 @@ func init() {
|
|||
// `{http.request.tls.proto_mutual}` | The negotiated next protocol was advertised by the server
|
||||
// `{http.request.tls.server_name}` | The server name requested by the client, if any
|
||||
// `{http.request.tls.client.fingerprint}` | The SHA256 checksum of the client certificate
|
||||
// `{http.request.tls.client.public_key}` | The public key of the client certificate.
|
||||
// `{http.request.tls.client.public_key_sha256}` | The SHA256 checksum of the client's public key.
|
||||
// `{http.request.tls.client.issuer}` | The issuer DN of the client certificate
|
||||
// `{http.request.tls.client.serial}` | The serial number of the client certificate
|
||||
// `{http.request.tls.client.subject}` | The subject DN of the client certificate
|
||||
// `{http.request.tls.client.san.dns_names.*}` | SAN DNS names(index optional)
|
||||
// `{http.request.tls.client.san.emails.*}` | SAN email addresses (index optional)
|
||||
// `{http.request.tls.client.san.ips.*}` | SAN IP addresses (index optional)
|
||||
// `{http.request.tls.client.san.uris.*}` | SAN URIs (index optional)
|
||||
// `{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left)
|
||||
// `{http.request.uri.path.dir}` | The directory, excluding leaf filename
|
||||
// `{http.request.uri.path.file}` | The filename of the path, excluding directory
|
||||
|
|
|
@ -27,7 +27,7 @@ func init() {
|
|||
|
||||
// parseCaddyfile sets up the handler from Caddyfile tokens. Syntax:
|
||||
//
|
||||
// basicauth [<matcher>] [<hash_algorithm>] {
|
||||
// basicauth [<matcher>] [<hash_algorithm> [<realm>]] {
|
||||
// <username> <hashed_password_base64> [<salt_base64>]
|
||||
// ...
|
||||
// }
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -163,7 +164,7 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
|||
if strings.HasPrefix(key, reqHostLabelsReplPrefix) {
|
||||
idxStr := key[len(reqHostLabelsReplPrefix):]
|
||||
idx, err := strconv.Atoi(idxStr)
|
||||
if err != nil {
|
||||
if err != nil || idx < 0 {
|
||||
return "", false
|
||||
}
|
||||
reqHost, _, err := net.SplitHostPort(req.Host)
|
||||
|
@ -171,9 +172,6 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
|||
reqHost = req.Host // OK; assume there was no port
|
||||
}
|
||||
hostLabels := strings.Split(reqHost, ".")
|
||||
if idx < 0 {
|
||||
return "", false
|
||||
}
|
||||
if idx > len(hostLabels) {
|
||||
return "", true
|
||||
}
|
||||
|
@ -245,6 +243,64 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
// subject alternate names (SANs)
|
||||
if strings.HasPrefix(field, "client.san.") {
|
||||
field = field[len("client.san."):]
|
||||
var fieldName string
|
||||
var fieldValue interface{}
|
||||
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
|
||||
|
|
|
@ -147,6 +147,26 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
|
|||
input: "{http.request.tls.client.subject}",
|
||||
expect: "CN=client.localdomain",
|
||||
},
|
||||
{
|
||||
input: "{http.request.tls.client.san.dns_names}",
|
||||
expect: "[localhost]",
|
||||
},
|
||||
{
|
||||
input: "{http.request.tls.client.san.dns_names.0}",
|
||||
expect: "localhost",
|
||||
},
|
||||
{
|
||||
input: "{http.request.tls.client.san.dns_names.1}",
|
||||
expect: "<empty>",
|
||||
},
|
||||
{
|
||||
input: "{http.request.tls.client.san.ips}",
|
||||
expect: "[127.0.0.1]",
|
||||
},
|
||||
{
|
||||
input: "{http.request.tls.client.san.ips.0}",
|
||||
expect: "127.0.0.1",
|
||||
},
|
||||
} {
|
||||
actual := repl.ReplaceAll(tc.input, "<empty>")
|
||||
if actual != tc.expect {
|
||||
|
|
Loading…
Reference in a new issue