Documentation
¶
Overview ¶
Package httpsig implements HTTP Message Signatures per RFC 9421 with optional Content-Digest support per RFC 9530.
It provides both client-side signing (via Transport) and server-side verification (via Middleware) for the kasper HTTP toolkit.
Supported Algorithms ¶
Six signature algorithms are supported:
- ed25519 (Edwards-Curve DSA)
- ecdsa-p256-sha256 (ECDSA P-256)
- ecdsa-p384-sha384 (ECDSA P-384)
- rsa-pss-sha512 (RSASSA-PSS)
- rsa-v1_5-sha256 (RSASSA-PKCS1-v1_5)
- hmac-sha256 (HMAC)
Signing Requests ¶
Use SignRequest to add Signature and Signature-Input headers to an HTTP request:
signer, err := httpsig.NewEd25519Signer("my-key-id", privateKey)
if err != nil {
log.Fatal(err)
}
err = httpsig.SignRequest(req, httpsig.SignConfig{
Signer: signer,
CoveredComponents: []string{httpsig.ComponentMethod, httpsig.ComponentAuthority, httpsig.ComponentPath},
})
if err != nil {
log.Fatal(err)
}
Verifying Requests ¶
Use VerifyRequest to verify the signature on an incoming request:
resolver := func(r *http.Request, keyID string, alg httpsig.Algorithm) (httpsig.Verifier, error) {
// Look up the verifier for the given key ID and algorithm.
return verifier, nil
}
err := httpsig.VerifyRequest(req, httpsig.VerifyConfig{
Resolver: resolver,
RequiredComponents: []string{httpsig.ComponentMethod, httpsig.ComponentAuthority},
MaxAge: 5 * time.Minute,
})
Client Transport ¶
NewTransport creates an http.RoundTripper that automatically signs all outgoing requests. Pass an *http.Transport to configure proxy, TLS, and timeout settings. Pass nil for sensible defaults:
client := &http.Client{
Transport: httpsig.NewTransport(nil, httpsig.SignConfig{
Signer: signer,
}),
}
resp, err := client.Get("https://api.example.com/resource")
With custom proxy and TLS:
base := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS13},
}
client := &http.Client{
Transport: httpsig.NewTransport(base, httpsig.SignConfig{
Signer: signer,
}),
}
Server Middleware ¶
Middleware returns a mux.MiddlewareFunc that verifies signatures on incoming requests. It integrates with the kasper/mux router:
mw, err := httpsig.Middleware(httpsig.MiddlewareConfig{
Verify: httpsig.VerifyConfig{
Resolver: resolver,
},
})
if err != nil {
log.Fatal(err)
}
router.Use(mw)
Content-Digest ¶
Optional Content-Digest support (RFC 9530) can be used standalone or integrated with signing:
// Standalone usage:
err := httpsig.SetContentDigest(req, httpsig.DigestSHA256)
// Integrated with signing (adds Content-Digest and includes it
// in covered components automatically):
err := httpsig.SignRequest(req, httpsig.SignConfig{
Signer: signer,
DigestAlgorithm: httpsig.DigestSHA256,
})
Index ¶
- Constants
- Variables
- func GenerateNonce() (string, error)
- func Middleware(cfg MiddlewareConfig) (mux.MiddlewareFunc, error)
- func SetContentDigest(r *http.Request, alg DigestAlgorithm) error
- func SignRequest(r *http.Request, cfg SignConfig) error
- func VerifyContentDigest(r *http.Request) error
- func VerifyRequest(r *http.Request, cfg VerifyConfig) error
- type Algorithm
- type DigestAlgorithm
- type KeyResolver
- type MiddlewareConfig
- type SignConfig
- type Signer
- func NewECDSAP256Signer(keyID string, key *ecdsa.PrivateKey) (Signer, error)
- func NewECDSAP384Signer(keyID string, key *ecdsa.PrivateKey) (Signer, error)
- func NewEd25519Signer(keyID string, key ed25519.PrivateKey) (Signer, error)
- func NewHMACSHA256Signer(keyID string, key []byte) (Signer, error)
- func NewRSAPSSSigner(keyID string, key *rsa.PrivateKey) (Signer, error)
- func NewRSAv15Signer(keyID string, key *rsa.PrivateKey) (Signer, error)
- type Transport
- type Verifier
- func NewECDSAP256Verifier(keyID string, key *ecdsa.PublicKey) (Verifier, error)
- func NewECDSAP384Verifier(keyID string, key *ecdsa.PublicKey) (Verifier, error)
- func NewEd25519Verifier(keyID string, key ed25519.PublicKey) (Verifier, error)
- func NewHMACSHA256Verifier(keyID string, key []byte) (Verifier, error)
- func NewRSAPSSVerifier(keyID string, key *rsa.PublicKey) (Verifier, error)
- func NewRSAv15Verifier(keyID string, key *rsa.PublicKey) (Verifier, error)
- type VerifyConfig
Constants ¶
const ( ComponentMethod = "@method" ComponentAuthority = "@authority" ComponentPath = "@path" ComponentQuery = "@query" ComponentTargetURI = "@target-uri" ComponentScheme = "@scheme" ComponentRequestTarget = "@request-target" )
Derived component identifiers per RFC 9421 Section 2.2.
Variables ¶
var ( // ErrNoSigner is returned when SignConfig has no Signer configured. ErrNoSigner = errors.New("httpsig: signer must not be nil") // ErrNoCoveredComponents is returned when SignConfig has an empty // CoveredComponents slice. ErrNoCoveredComponents = errors.New("httpsig: covered components must not be empty") )
Signing errors.
var ( // ErrNoResolver is returned when VerifyConfig has no KeyResolver configured. ErrNoResolver = errors.New("httpsig: key resolver must not be nil") // ErrSignatureNotFound is returned when the expected signature label is // not present in the Signature-Input header. ErrSignatureNotFound = errors.New("httpsig: signature not found") // ErrSignatureInvalid is returned when signature verification fails. ErrSignatureInvalid = errors.New("httpsig: signature verification failed") // ErrSignatureExpired is returned when the signature has exceeded its // maximum allowed age. ErrSignatureExpired = errors.New("httpsig: signature expired") // ErrCreatedRequired is returned when MaxAge is set but the signature // does not contain a created parameter. ErrCreatedRequired = errors.New("httpsig: created parameter required when MaxAge is set") // ErrMissingComponent is returned when a required covered component // is absent from the signature. ErrMissingComponent = errors.New("httpsig: required component missing from signature") // ErrMalformedHeader is returned when Signature or Signature-Input // headers cannot be parsed. ErrMalformedHeader = errors.New("httpsig: malformed signature header") )
Verification errors.
var ( // ErrDigestMismatch is returned when Content-Digest verification fails. ErrDigestMismatch = errors.New("httpsig: content digest mismatch") // ErrDigestNotFound is returned when Content-Digest header is required // but not present. ErrDigestNotFound = errors.New("httpsig: content digest not found") // ErrUnsupportedDigest is returned when the digest algorithm is not // supported. ErrUnsupportedDigest = errors.New("httpsig: unsupported digest algorithm") )
Digest errors.
var ( // ErrInvalidKey is returned when key material is invalid (nil, wrong // curve, insufficient size, etc.). ErrInvalidKey = errors.New("httpsig: invalid key material") )
Key material errors.
var ( // ErrUnknownComponent is returned when an unrecognized derived component // identifier is used. ErrUnknownComponent = errors.New("httpsig: unknown component identifier") )
Component errors.
Functions ¶
func GenerateNonce ¶
GenerateNonce returns a cryptographically random nonce string suitable for use in SignConfig.Nonce. The returned value is 16 random bytes encoded as unpadded base64url (22 characters).
func Middleware ¶
func Middleware(cfg MiddlewareConfig) (mux.MiddlewareFunc, error)
Middleware returns a mux.MiddlewareFunc that verifies HTTP message signatures on incoming requests per RFC 9421.
It returns ErrNoResolver if VerifyConfig.Resolver is nil.
func SetContentDigest ¶
func SetContentDigest(r *http.Request, alg DigestAlgorithm) error
SetContentDigest reads the request body, computes the digest using the specified algorithm, sets the Content-Digest header per RFC 9530, and replaces the body so it can be read again.
func SignRequest ¶
func SignRequest(r *http.Request, cfg SignConfig) error
SignRequest signs an HTTP request in-place by adding Signature and Signature-Input headers per RFC 9421.
func VerifyContentDigest ¶
VerifyContentDigest verifies the Content-Digest header against the request body per RFC 9530. It supports multiple digest values in the header and verifies the first recognized algorithm.
func VerifyRequest ¶
func VerifyRequest(r *http.Request, cfg VerifyConfig) error
VerifyRequest verifies an HTTP request signature per RFC 9421.
Types ¶
type Algorithm ¶
type Algorithm string
Algorithm identifies the HTTP message signature algorithm per RFC 9421 Section 3.3.
const ( // AlgorithmRSAPSSSHA512 is RSASSA-PSS using SHA-512. AlgorithmRSAPSSSHA512 Algorithm = "rsa-pss-sha512" // AlgorithmRSAv15SHA256 is RSASSA-PKCS1-v1_5 using SHA-256. AlgorithmRSAv15SHA256 Algorithm = "rsa-v1_5-sha256" // AlgorithmHMACSHA256 is HMAC using SHA-256. AlgorithmHMACSHA256 Algorithm = "hmac-sha256" // AlgorithmECDSAP256SHA256 is ECDSA using curve P-256 and SHA-256. AlgorithmECDSAP256SHA256 Algorithm = "ecdsa-p256-sha256" // AlgorithmECDSAP384SHA384 is ECDSA using curve P-384 and SHA-384. AlgorithmECDSAP384SHA384 Algorithm = "ecdsa-p384-sha384" // AlgorithmEd25519 is Edwards-Curve Digital Signature Algorithm // using curve 25519. AlgorithmEd25519 Algorithm = "ed25519" )
type DigestAlgorithm ¶
type DigestAlgorithm string
DigestAlgorithm identifies the hash algorithm for Content-Digest per RFC 9530.
const ( // DigestSHA256 uses SHA-256 for content digest. DigestSHA256 DigestAlgorithm = "sha-256" // DigestSHA512 uses SHA-512 for content digest. DigestSHA512 DigestAlgorithm = "sha-512" )
type KeyResolver ¶
KeyResolver returns a Verifier for the given key ID and algorithm. It is called during request verification to look up the appropriate key. The request is provided for context (e.g., to select keys based on the request host or path).
type MiddlewareConfig ¶
type MiddlewareConfig struct {
// Verify configures how signatures are verified.
Verify VerifyConfig
// OnError is called when verification fails. When nil, a plain 401
// Unauthorized response is sent.
OnError func(w http.ResponseWriter, r *http.Request, err error)
}
MiddlewareConfig configures the server-side signature verification middleware.
type SignConfig ¶
type SignConfig struct {
// Signer produces signatures. Required.
Signer Signer
// Label identifies the signature in Signature/Signature-Input headers.
// Defaults to "sig1".
Label string
// CoveredComponents lists the component identifiers to include in the
// signature base. Defaults to [ComponentMethod, ComponentAuthority, ComponentPath].
CoveredComponents []string
// Nonce is an optional nonce value included in signature parameters.
Nonce string
// Tag is an optional application-specific tag for the signature.
Tag string
// Created sets the signature creation time. When zero, time.Now() is
// used.
Created time.Time
// Expires sets the signature expiration time. When zero, no expiration
// is set.
Expires time.Time
// DigestAlgorithm, when set, causes SignRequest to compute and set a
// Content-Digest header (RFC 9530) before signing. The
// "content-digest" component is automatically added to covered
// components if not already present.
DigestAlgorithm DigestAlgorithm
}
SignConfig configures HTTP request signing per RFC 9421.
type Signer ¶
type Signer interface {
// Sign produces a signature over the given message bytes.
Sign(message []byte) ([]byte, error)
// Algorithm returns the algorithm identifier for this signer.
Algorithm() Algorithm
// KeyID returns the key identifier included in signature parameters.
KeyID() string
}
Signer creates signatures over HTTP message signature base strings.
func NewECDSAP256Signer ¶
func NewECDSAP256Signer(keyID string, key *ecdsa.PrivateKey) (Signer, error)
NewECDSAP256Signer creates a Signer using ECDSA with curve P-256 and SHA-256.
func NewECDSAP384Signer ¶
func NewECDSAP384Signer(keyID string, key *ecdsa.PrivateKey) (Signer, error)
NewECDSAP384Signer creates a Signer using ECDSA with curve P-384 and SHA-384.
func NewEd25519Signer ¶
func NewEd25519Signer(keyID string, key ed25519.PrivateKey) (Signer, error)
NewEd25519Signer creates a Signer using Ed25519.
func NewHMACSHA256Signer ¶
NewHMACSHA256Signer creates a Signer using HMAC-SHA256. The key must be at least 32 bytes.
func NewRSAPSSSigner ¶
func NewRSAPSSSigner(keyID string, key *rsa.PrivateKey) (Signer, error)
NewRSAPSSSigner creates a Signer using RSASSA-PSS with SHA-512.
func NewRSAv15Signer ¶
func NewRSAv15Signer(keyID string, key *rsa.PrivateKey) (Signer, error)
NewRSAv15Signer creates a Signer using RSASSA-PKCS1-v1_5 with SHA-256.
type Transport ¶
type Transport struct {
// contains filtered or unexported fields
}
Transport is an http.RoundTripper that signs outgoing requests using HTTP Message Signatures (RFC 9421).
Use NewTransport to create a Transport with a configured *http.Transport for proxy, TLS, and timeout settings.
func NewTransport ¶
func NewTransport(base *http.Transport, cfg SignConfig) *Transport
NewTransport creates a signing Transport that delegates to base after signing each request. When base is nil, a clone of http.DefaultTransport is used, giving an independent connection pool with default proxy, TLS, and timeout settings.
Configure base for custom proxy (HTTP/SOCKS), TLS, timeouts, and connection pool settings:
base := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS13},
IdleConnTimeout: 90 * time.Second,
}
transport := httpsig.NewTransport(base, httpsig.SignConfig{Signer: signer})
type Verifier ¶
type Verifier interface {
// Verify checks that signature is valid for the given message bytes.
// Returns nil on success, non-nil on failure.
Verify(message, signature []byte) error
// Algorithm returns the algorithm identifier for this verifier.
Algorithm() Algorithm
// KeyID returns the key identifier for this verifier.
KeyID() string
}
Verifier validates signatures over HTTP message signature base strings.
func NewECDSAP256Verifier ¶
NewECDSAP256Verifier creates a Verifier using ECDSA with curve P-256 and SHA-256.
func NewECDSAP384Verifier ¶
NewECDSAP384Verifier creates a Verifier using ECDSA with curve P-384 and SHA-384.
func NewEd25519Verifier ¶
NewEd25519Verifier creates a Verifier using Ed25519.
func NewHMACSHA256Verifier ¶
NewHMACSHA256Verifier creates a Verifier using HMAC-SHA256. The key must be at least 32 bytes.
func NewRSAPSSVerifier ¶
NewRSAPSSVerifier creates a Verifier using RSASSA-PSS with SHA-512.
type VerifyConfig ¶
type VerifyConfig struct {
// Resolver looks up a Verifier for a given key ID and algorithm.
// Required.
Resolver KeyResolver
// Label identifies which signature to verify. When empty, the first
// signature found in the Signature-Input header is used.
Label string
// RequiredComponents lists component identifiers that must be present
// in the signature's covered components. Verification fails if any
// required component is missing.
RequiredComponents []string
// MaxAge is the maximum acceptable age of the signature. When non-zero,
// signatures older than MaxAge are rejected. Requires the "created"
// parameter in the signature.
MaxAge time.Duration
// RequireDigest, when true, requires a Content-Digest header and
// verifies it against the request body before signature verification.
RequireDigest bool
}
VerifyConfig configures HTTP request signature verification per RFC 9421.