diff options
-rw-r--r-- | modules/caddyhttp/replacer.go | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index 670b2e3..37b53d2 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -16,9 +16,14 @@ package caddyhttp import ( "context" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" "crypto/sha256" "crypto/tls" "crypto/x509" + "encoding/asn1" "fmt" "net" "net/http" @@ -243,6 +248,18 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) { 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": @@ -271,6 +288,19 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) { return nil, false } +// marshalPublicKey returns the byte encoding of pubKey. +func marshalPublicKey(pubKey interface{}) ([]byte, error) { + switch key := pubKey.(type) { + case *rsa.PublicKey: + return asn1.Marshal(key) + case *ecdsa.PublicKey: + return elliptic.Marshal(key.Curve, key.X, key.Y), nil + case ed25519.PublicKey: + return key, nil + } + return nil, fmt.Errorf("unrecognized public key type: %T", pubKey) +} + // getTLSPeerCert retrieves the first peer certificate from a TLS session. // Returns nil if no peer cert is in use. func getTLSPeerCert(cs *tls.ConnectionState) *x509.Certificate { |