summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-06-11 16:19:07 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2020-06-11 16:19:07 -0600
commitd55c3b31ebb77df65cc052dbddc137cbe07b297e (patch)
tree21c711b6eafb9c05fedc63317fd96e4c7d326c6c /modules
parentb3bff13f7d3635c5c51f71b9e4598d71deab4585 (diff)
caddyhttp: Add client cert SAN placeholders
Diffstat (limited to 'modules')
-rw-r--r--modules/caddyhttp/app.go6
-rw-r--r--modules/caddyhttp/caddyauth/caddyfile.go2
-rw-r--r--modules/caddyhttp/replacer.go64
-rw-r--r--modules/caddyhttp/replacer_test.go20
4 files changed, 87 insertions, 5 deletions
diff --git a/modules/caddyhttp/app.go b/modules/caddyhttp/app.go
index f695276..45845ea 100644
--- a/modules/caddyhttp/app.go
+++ b/modules/caddyhttp/app.go
@@ -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
diff --git a/modules/caddyhttp/caddyauth/caddyfile.go b/modules/caddyhttp/caddyauth/caddyfile.go
index 13e78fc..afa3808 100644
--- a/modules/caddyhttp/caddyauth/caddyfile.go
+++ b/modules/caddyhttp/caddyauth/caddyfile.go
@@ -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>]
// ...
// }
diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go
index 37b53d2..b3c7b5d 100644
--- a/modules/caddyhttp/replacer.go
+++ b/modules/caddyhttp/replacer.go
@@ -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
diff --git a/modules/caddyhttp/replacer_test.go b/modules/caddyhttp/replacer_test.go
index ea9fa65..bc18c5a 100644
--- a/modules/caddyhttp/replacer_test.go
+++ b/modules/caddyhttp/replacer_test.go
@@ -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 {