httpsig

package module
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 8, 2026 License: MIT Imports: 24 Imported by: 0

README

CI Codecov Go Reference

Introduction and Scope

httpsig is a library for signing and verifying HTTP requests and responses according to RFC 9421 (HTTP Message Signatures). In addition to the Structured Fields types defined by RFC 8941, it also supports the Date and Display String types introduced by RFC 9651.

Its key features include:

  • Policy-based signing and verification: Reusable policies for covered components, signature parameters, tags, and validity constraints.
  • Message integrity: Automatic generation and verification of Content-Digest to protect HTTP message bodies.
  • Signature negotiation: Support for requesting signatures via Accept-Signature and deriving signature requirements from verification policies.
  • Framework independence: A Message abstraction that enables integration with net/http, Fiber, other HTTP frameworks, and proxy-based services.
  • Cryptographic agility: Support for custom signing and verification implementations, allowing applications to use cryptographic algorithms and key management systems (HSMs and KMSs) independently of the library's built-in support (see Cryptographic Agility).

For API details and option semantics, see the Go reference. For known limitations and the current scope of RFC 9421 support, see Limitations and Compliance.

Usage

Standalone Signing and Verification

The following snippets show two independent flows: signing an outgoing request and verifying a received response. They assume application-provided keys and other values; routine error handling is abbreviated.

To sign a request, configure a Signer with the signing key and the HTTP components to protect:

// Configure the signing policy.
signer, err := httpsig.NewSigner(
    // specify a key
    httpsig.Key{Material: privKey, Algorithm: httpsig.EcdsaP256Sha256},
    // the keyid parameter for the above key
    httpsig.WithKeyID("key1"),
    // specify the required options 
    // duration for which the signature should be valid
    httpsig.WithTTL(5 * time.Second),
    // which components should be protected by a signature 
    httpsig.WithComponents(`"@authority"`, `"@method"`, `"x-my-fancy-header"`),
    // a tag for your specific application
    httpsig.WithTag("myapp"),
    // custom parameter
    httpsig.WithParameter("first", "value 1"),
    // custom parameter
    httpsig.WithParameter("second", httpsig.DisplayString("öäü")),
    // custom parameter
    httpsig.WithParameter("third", httpsig.Date(time.Now())),
)
// error handling goes here

// Create a request
req, err := http.NewRequestWithContext(context.Background(), "GET", "https://some-url.com", nil)
// error handling goes here
req.Header.Set("X-My-Fancy-Header", "example-value")

nonce := ... // generate a nonce

// Sign the request
header, err := signer.Sign(
    httpsig.MessageFromRequest(req),
    // add a nonce if required
    httpsig.WithParameter(httpsig.Nonce, nonce),
)
// error handling goes here

// MessageFromRequest clones the headers; use the headers returned by Sign.
req.Header = header
// send the request

To verify a response, create a Verifier with a KeyResolver that supplies trusted verification keys (see Key Resolution). WithValidateAllSignatures checks every signature present in the message; use WithRequiredTag instead when your protocol expects particular signed tags.

// Receive a response from the server
resp, err := client.Post("https://some-url.com", "application/json", &buf)
// error handling

// Create a verifier
verifier, err := httpsig.NewVerifier(
    // specify a key resolver to resolve the key
    keyResolver,
    // specify the required options
    // which response components are expected to be protected
    httpsig.WithComponents(`"@status"`, `"content-type"`),
    // validity time skew
    httpsig.WithValidityTolerance(5 * time.Second),
    // how old a signature is allowed to be
    httpsig.WithMaxAge(30 * time.Second),
    // whether to validate all signatures present in the message
    httpsig.WithValidateAllSignatures(),
)
// error handling

// Verify the response. No partial result is returned on failure.
verified, err := verifier.Verify(httpsig.MessageFromResponse(resp))
// Each entry in verified contains the covered components, transmitted
// signature parameters, and any metadata returned by the key resolver.

// error handling

Once Verify succeeds, your application can inspect the verified object and enforce protocol-specific rules, such as nonce correlation, replay protection, and authorization.

If a protocol requires a signature with a particular tag, use WithRequiredTag. Unlike WithValidateAllSignatures, tag-based verification selects signatures carrying the required tag; unrelated signatures are not verified unless all-signature verification is also enabled. For example:

verifier, err := httpsig.NewVerifier(
    // specify a key resolver to resolve the key used by the client
    keyResolver,
    // specify the required options
    httpsig.WithRequiredTag(
        // tag of the signature
        "myapp",
        // which components are expected to be protected by a signature
        httpsig.WithComponents(`"@authority"`, `"@method"`, `"x-my-fancy-header"`),
        // validity time skew
        httpsig.WithValidityTolerance(5 * time.Second),
        // how old a signature is allowed to be
        httpsig.WithMaxAge(30 * time.Second),
    ), 
)
// error handling goes here

verified, err := verifier.Verify(msg)
// error handling goes here

Global verifier options act as defaults for required tags. Tag-specific options take precedence (for example, WithComponents replaces the global component list), while required, forbidden, and expected signature-parameter constraints are additive. Automatic signature negotiation uses these effective per-tag requirements.

The same APIs also verify incoming requests and sign outgoing responses. Both Signer.Sign and Verifier.Verify operate on a Message, created for the corresponding HTTP direction:

  • MessageFromRequest — outbound client requests or inbound server requests.
  • MessageFromResponse — responses received by clients.
  • MessageForResponse — responses produced by servers.

For middleware integration, see HTTP Frameworks.

To protect a message body, include "content-digest" among the covered components (see RFC 9421's discussion of message content):

  • Signing: The Signer calculates the digest and creates or replaces Content-Digest before signing. By default, it uses both sha-256 and sha-512 (as defined in RFC 9530); WithContentDigestAlgorithm selects a single algorithm.
  • Verification: If the signature covers content-digest, the Verifier also checks the digest against the body. Verification fails if the header is missing, no supported digest is present, or any supported digest mismatches. Only sha-256 and sha-512 are checked.

[!IMPORTANT] Signing or verifying "content-digest" requires reading the message body. Since request and response bodies may be attacker-controlled input, callers are responsible for enforcing appropriate body size limits before passing messages to this library.

For server-side request handling, consider using http.MaxBytesReader; for other contexts, use io.LimitedReader or an equivalent mechanism. The library restores the body after reading it, so it can still be consumed by subsequent handlers, but it does not impose global body size limits on behalf of the application.

Key Resolution

A Verifier uses a KeyResolver to select the key for each signature. ResolveKey receives SignatureInfo before cryptographic verification, so its parameters, components, and message are still unverified.

type trustedKeys map[string]httpsig.Key

func (keys trustedKeys) ResolveKey(_ context.Context, info httpsig.SignatureInfo) (httpsig.KeyInfo, error) {
    keyID, ok := info.Parameters.KeyID()
    if !ok {
        return httpsig.KeyInfo{}, errors.New("missing keyid")
    }

    key, ok := keys[keyID]
    if !ok {
        return httpsig.KeyInfo{}, errors.New("unknown key")
    }

    return httpsig.KeyInfo{Key: key}, nil
}

This example looks up a previously trusted key by keyid. A fixed httpsig.Key can also serve directly as a KeyResolver. KeyInfo can carry optional application-specific Metadata.

Identity

After Verify succeeds, VerifiedSignature provides the verified signature parameters and covered component values. The application uses these values according to its protocol to establish a principal and make authorization decisions. Signature labels are not signed and must not be used as identities.

Signature Negotiation

Signature negotiation uses the Accept-Signature header defined in RFC 9421. A client can explicitly request a signed response; a server can derive a request for missing client signatures from its verification policy.

[!NOTE] RFC 9421 §5.2 requires a negotiated signature to use the requested label, but §7.2.5 permits intermediaries to relabel signatures and warns against assigning labels application semantics. httpsig therefore does not enforce label consistency. Use the signed tag parameter to identify application-specific signatures instead.

Requesting Signatures on the Client-Side from the Server

Use AcceptSignatureBuilder when a client needs to request a signed response. It constructs the Accept-Signature header independently of any verifier policy, so the client can specify the components and parameters it expects the server to sign:

// create a builder (all options are optional)
builder, err := httpsig.NewAcceptSignature(
    // request a key identifier and signing algorithm
    httpsig.WithKeyID("foo"),
    // specify which signature algorithm the peer should use
    httpsig.WithSignatureAlgorithm(httpsig.EcdsaP256Sha256),
    // request the label and covered components
    httpsig.WithLabel("bar"),
    // specify which components should be covered by the signature 
    httpsig.WithComponents(`"@status"`, `"content-digest";req`, `"content-digest"`),
    // specify your content digest algorithm references 
    httpsig.WithContentDigestAlgorithmPreferences(httpsig.AlgorithmPreference{Algorithm: httpsig.Sha256, Preference: 2}),
    // specify which tag the server should use 
    httpsig.WithTag("awesome-app"),
    // specify whether you want the created time stamp to be included 
    httpsig.WithCreatedTimestamp(true),
    // specify whether you want the expires time stamp to be included 
    httpsig.WithExpiresTimestamp(true),
)
// error handling goes here

req := ... // create your request
nonce := ... // application-generated nonce for this request

err = builder.Build(req.Context(), req.Header, httpsig.WithParameter("nonce", nonce))
// error handling goes here

// send the request

This adds an Accept-Signature header with a value such as:

Accept-Signature: bar=("@status" "content-digest";req "content-digest");created;expires;keyid="foo";alg="ecdsa-p256-sha256";nonce="...";tag="awesome-app"
Want-Content-Digest: sha-256=2

The Want-Content-Digest header is also added because the requested signature covers content-digest.

Fulfilling a Signature Request

Use ParseAcceptSignature when a peer requests a signature, for example in a 401 response to your request. It takes an http.Header, so it works independently of signers and verifiers, and returns one SignatureRequest per requested signature:

requests, err := httpsig.ParseAcceptSignature(resp.Header)
// err reports the members that can't be used; requests holds the usable ones

msg := httpsig.MessageFromRequest(req)

for _, request := range requests {
    // decide whether the request is acceptable for your application

    signer, err := httpsig.NewSigner(
        key,
        httpsig.WithLabel(request.Label),
        httpsig.WithComponents(request.Components...),
        httpsig.WithTag(request.Tag),
    )
    // error handling goes here

    var opts []httpsig.SignOption
    if request.Nonce != "" {
        opts = append(opts, httpsig.WithParameter("nonce", request.Nonce))
    }

    _, err := signer.Sign(msg, opts...)
    // error handling goes here

    // ...
}

req.Header = msg.Header

// send the request

Created and Expires report whether these parameters are requested, as Accept-Signature carries no timestamp values. A Signer always includes created; use WithTTL to include expires. Parameters not defined by RFC 9421 are available in Extensions. If the field as a whole isn't valid Structured Fields, no requests are returned. A malformed member or one with an unsupported component identifier doesn't affect the other members: the usable requests are returned together with a joined error that wraps ErrMalformedData for each unusable member. Require err == nil if your application must fulfill every request.

Requesting Signatures on the Server-Side from the Client

On the server side, the Verifier can derive Accept-Signature requirements from its configured policy. This avoids defining component and parameter requirements separately for verification and negotiation. If a required signature, component, or parameter is missing, Verify returns an error wrapping NoApplicableSignatureError; use errors.As to retrieve it and call Negotiate to add the prepared headers to the response. An invalid cryptographic signature is still a verification failure, not a negotiation request.

For example, extending the earlier tag-based verifier:

verifier, err := httpsig.NewVerifier(
    // specify a key resolver
    keyResolver,
    // specify the required options
    httpsig.WithRequiredTag(
        // tag of the signature
        "myapp",
        // which components are expected to be protected by a signature
        httpsig.WithComponents(`"@authority"`, `"@method"`, `"x-my-fancy-header"`),
        // validity time skew
        httpsig.WithValidityTolerance(5 * time.Second),
        // how old a signature is allowed to be
        httpsig.WithMaxAge(30 * time.Second),
        // if there is no signature tagged "myapp", or some of the required components or parameters
        // are not present, request a signature from the client
        httpsig.WithSignatureNegotiation(
            // request a key ID and signature algorithm
            httpsig.WithKeyID("key1"),
            // request a signature algorithm the peer should use
            httpsig.WithSignatureAlgorithm(httpsig.EcdsaP256Sha256),
            // specify the source for the nonce
            httpsig.WithNonceGetter(nonceGetter),
            // specify the label for the signature
            httpsig.WithLabel("bar"),
        ),
    ),
)
// error handling goes here

_, err = verifier.Verify(msg)

var missingSigErr *httpsig.NoApplicableSignatureError
if errors.As(err, &missingSigErr) {
    // if this error is returned, call Negotiate to update the http headers with the 
    // Accept-Signature header
    missingSigErr.Negotiate(resp.Header)
}
// further error handling

For automatic negotiation, the configured NonceGetter runs while Verify prepares the Accept-Signature headers, before NoApplicableSignatureError is returned.

[!NOTE]
The WithSignatureNegotiation option at the top level (outside the WithRequiredTag option) is mutually exclusive with the WithValidateAllSignatures option. However, you can still use WithSignatureNegotiation at the top level if you want to apply the same configuration for all expected tagged signatures, thereby simplifying your code.

Reusing Signers and Verifiers

A Signer or Verifier represents a reusable signing or verification policy. Create an instance once per policy and reuse it across messages. This allows most of the configuration work to happen upfront, keeping the per-message overhead low. Message-specific values can be supplied through per-call options.

Cryptographic Agility

httpsig supports custom signing and verification implementations through the MessageSigner and MessageVerifier interfaces. This allows applications to use cryptographic algorithms (e.g., PQC) and key management systems (HSMs and KMSs) independently of the library's built-in support.

The library constructs the RFC 9421 signature base and passes it unchanged to the application-provided implementation, which is responsible for the entire cryptographic operation, including hashing and signature encoding.

ML-DSA

The following example demonstrates how to use ML-DSA, available in the Go standard library since Go 1.27, without requiring httpsig itself to target that Go version.

First, define adapters for signing and verification:

type mlDSASigner mldsa.PrivateKey

func (s *mlDSASigner) SignMessage(_ context.Context, message []byte) ([]byte, error) {
    return (*mldsa.PrivateKey)(s).Sign(nil, message, &mldsa.Options{})
}

type mlDSAVerifier mldsa.PublicKey

func (v *mlDSAVerifier) VerifyMessage(_ context.Context, message, signature []byte) error {
    return mldsa.Verify((*mldsa.PublicKey)(v), message, signature, &mldsa.Options{})
}

These adapters can then be used directly with the existing signing and verification APIs:

// Generate an ML-DSA key pair.
privateKey, err := mldsa.GenerateKey(mldsa.MLDSA44())
// error handling

// Create a signer.
signer, err := httpsig.NewSigner(
    httpsig.Key{
        Material:  (*mlDSASigner)(privateKey),
        Algorithm: "ml-dsa-44",
    },
    httpsig.WithKeyID("demo-ml-dsa-44"),
    httpsig.WithAlg(),
    httpsig.WithComponents(`"@method"`, `"@path"`),
)
// error handling

req, err := ... // create the request

// Sign the request.
req.Header, err = signer.Sign(httpsig.MessageFromRequest(req))
// error handling

// Create a verifier.
verifier, err := httpsig.NewVerifier(
    httpsig.Key{
        Material:  (*mlDSAVerifier)(privateKey.PublicKey()),
        Algorithm: "ml-dsa-44",
    },
    httpsig.WithValidateAllSignatures(),
    httpsig.WithComponents(`"@method"`, `"@path"`),
)
// error handling

// Verify the request.
result, err := verifier.Verify(httpsig.MessageFromRequest(req))
// error handling

AWS KMS

The same approach works with external key management systems such as AWS KMS. The application-provided adapter handles the KMS interaction and any required cryptographic processing.

For example, an ECDSA signer backed by AWS KMS could look like this:

type awsMessageSigner struct {
    client *kms.Client
    keyID  string
}

func (s awsMessageSigner) SignMessage(ctx context.Context, message []byte) ([]byte, error) {
    digest := sha256.Sum256(message)

    response, err := s.client.Sign(ctx, &kms.SignInput{
        KeyId:            &s.keyID,
        Message:          digest[:],
        MessageType:      types.MessageTypeDigest,
        SigningAlgorithm: types.SigningAlgorithmSpecEcdsaSha256,
    })
    if err != nil {
        return nil, err
    }

    // Convert the ASN.1 DER-encoded ECDSA signature returned by AWS KMS to r || s.
    return ecdsaSignatureToRaw(response.Signature)
}

The adapter can then be passed to httpsig like any other signing key:

client := ... // create the AWS KMS client
keyID := ...  // obtain the key ID

signer, err := httpsig.NewSigner(
    httpsig.Key{
        Material:  awsMessageSigner{client: client, keyID: keyID},
        Algorithm: httpsig.EcdsaP256Sha256,
    },
    httpsig.WithKeyID(keyID),
    httpsig.WithComponents(`"@method"`, `"@path"`),
)
// error handling

req, err := ... // create the request

req.Header, err = signer.Sign(httpsig.MessageFromRequest(req))
// error handling

Protocols and Profiles

WIMSE Workload-to-Workload HTTP Signatures

The WIMSE HTTP Signatures draft binds signed requests to Workload Identity Tokens (WITs). For an ordinary request carrying a Workload-Identity-Token header:

// Sender
signer, err := httpsig.NewSigner(
    httpsig.Key{Material: privateKey, Algorithm: httpsig.Ed25519},
    httpsig.WithTag("wimse-workload-to-workload"),
    httpsig.WithComponents(`"@method"`, `"@path"`, `"@query"`, `"workload-identity-token"`),
)

req.Header, err = signer.Sign(httpsig.MessageFromRequest(req),
    httpsig.WithParameter(httpsig.Nonce, nonce),
    httpsig.WithParameter("wimse-aud", audience),
)

// Recipient
verifier, err := httpsig.NewVerifier(witKeyResolver,
    httpsig.WithRequiredTag("wimse-workload-to-workload",
        httpsig.WithComponents(`"@method"`, `"@path"`, `"@query"`, `"workload-identity-token"`),
        httpsig.WithRequiredParameters(httpsig.Nonce),
        httpsig.WithForbiddenParameters(httpsig.KeyID, httpsig.Alg),
        httpsig.WithParameter("wimse-aud", expectedAudience),
    ),
)

result, err = verifier.Verify(httpsig.MessageFromRequest(req))

Include content-digest for requests with a body and cover any other headers required by the draft when present. The application validates the WIT and enforces replay rules.

Web Bot Auth

The Web Bot Auth draft uses a signed Signature-Agent dictionary member to advertise the signer's key directory.

// Sender: the dictionary member matches the signature label.
req.Header.Set("Signature-Agent", `sig1="https://agent.example/keys.jwks"`)
signer, err := httpsig.NewSigner(
    httpsig.Key{Material: privateKey, Algorithm: httpsig.Ed25519},
    httpsig.WithLabel("sig1"),
    httpsig.WithTag("web-bot-auth"),
    httpsig.WithKeyID(jwkThumbprint),
    httpsig.WithComponents(`"@authority"`, `"signature-agent";key="sig1"`),
)

req.Header, err = signer.Sign(httpsig.MessageFromRequest(req))

// Recipient: resolve the covered Signature-Agent member dynamically.
verifier, err := httpsig.NewVerifier(webBotKeyResolver,
    httpsig.WithRequiredTag("web-bot-auth",
        httpsig.WithComponents(`"@authority"`, `"signature-agent";key="sig1"`),
        httpsig.WithRequiredParameters(httpsig.KeyID),
    ),
)

verified, err := verifier.Verify(httpsig.MessageFromRequest(req))

webBotKeyResolver implementation needs to resolve the signing key using the Signature-Agent member covered by the signature.

AAuth

The AAuth Protocol draft authenticates agents using HTTP Message Signatures and a signed Signature-Key header containing key information.

// Agent
req.Header.Set("Signature-Key", `sig=jwt;jwt="`+agentToken+`"`)
signer, err := httpsig.NewSigner(
    httpsig.Key{Material: privateKey, Algorithm: httpsig.Ed25519},
    httpsig.WithLabel("sig"),
    httpsig.WithTTL(0),
    httpsig.WithComponents(`"@method"`, `"@authority"`, `"@path"`, `"signature-key"`),
)
req.Header, err = signer.Sign(httpsig.MessageFromRequest(req))

// Resource server
verifier, err := httpsig.NewVerifier(aauthKeyResolver,
    httpsig.WithValidateAllSignatures(),
    httpsig.WithComponents(`"@method"`, `"@authority"`, `"@path"`, `"signature-key"`),
    httpsig.WithExpiresTimestamp(false),
    httpsig.WithMaxAge(time.Minute),
)
_, err = verifier.Verify(httpsig.MessageFromRequest(req))

aauthKeyResolver validates the agent token and resolves its signing key via Signature-Key. For requests with bodies to person or access servers and revocation endpoints, also cover content-digest and content-type.

OAuth Proof-of-Possession Tokens

The OAuth HTTP Signature PoP draft binds access tokens to signing keys. For a resource request carrying an Authorization header:

// Client
signer, err := httpsig.NewSigner(
    httpsig.Key{Material: privateKey, Algorithm: httpsig.Ed25519},
    httpsig.WithTag("httpsig-oauth"),
    httpsig.WithTTL(0),
    httpsig.WithComponents(`"@method"`, `"@target-uri"`, `"authorization"`),
)

req.Header, err = signer.Sign(httpsig.MessageFromRequest(req),
    httpsig.WithParameter(httpsig.Nonce, nonce),
)

// Resource server
verifier, err := httpsig.NewVerifier(tokenBoundKeyResolver,
    httpsig.WithRequiredTag("httpsig-oauth",
        httpsig.WithComponents(`"@method"`, `"@target-uri"`, `"authorization"`),
        httpsig.WithExpiresTimestamp(false),
        httpsig.WithRequiredParameters(httpsig.Nonce),
        httpsig.WithForbiddenParameters(httpsig.KeyID, httpsig.Alg, "pub"),
    ),
)

_, err = verifier.Verify(httpsig.MessageFromRequest(req))

The resource server validates the access token, supplies its bound key through KeyResolver, and checks nonce reuse. For requests with bodies, also cover content-digest. When verifying @target-uri on incoming requests, use the externally visible absolute URL, reconstructed from trusted server or proxy configuration.

HTTP Frameworks

The examples below verify incoming requests. The same signing, verification, and signature negotiation APIs can be used in client middleware and for responses as well.

net/http

http.Handle("/api", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    result, err := verifier.Verify(httpsig.MessageFromRequest(r))
    if err != nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)

        return
    }

    // establish a principal from the result object
    // and propagate it downstream

    handler.ServeHTTP(w, r)
}))

Gin

router.Use(func(c *gin.Context) {
    result, err := verifier.Verify(httpsig.MessageFromRequest(c.Request))
    if err != nil {
        c.AbortWithStatus(http.StatusUnauthorized)

        return
    }

    // establish a principal from the result object
    // and propagate it downstream

    c.Next()
})

Fiber v3 (fasthttp)

app.Use(func(c fiber.Ctx) error {
    targetURL, err := url.Parse(c.FullURL())
    if err != nil {
        return err
    }

    headers := make(http.Header)
    for name, values := range c.GetReqHeaders() {
        for _, value := range values {
            headers.Add(name, value)
        }
    }

    msg := &httpsig.Message{
        Context:   c.Context(),
        Method:    c.Method(),
        Authority: c.Host(),
        URL:       targetURL,
        Header:    headers,
        Body: func() (io.ReadCloser, error) {
            return io.NopCloser(bytes.NewReader(c.BodyRaw())), nil
        },
        IsRequest: true,
    }

    result, err := verifier.Verify(msg)
    if err != nil {
        return c.SendStatus(fiber.StatusUnauthorized)
    }

    // establish a principal from the result object
    // and propagate it downstream

    return c.Next()
})

Security Considerations

  • Coverage: Require the components your application relies on. For messages with bodies, sign and verify content-digest when body integrity matters.
  • Key trust: KeyResolver receives unverified message data. Select and validate keys according to your application protocol.
  • Signature requests: Accept-Signature is controlled by the peer. Check the components, key, and parameters of a SignatureRequest before signing, so a peer cannot obtain signatures your application did not intend to produce.
  • Replay: Enforce the required nonce checks after successful signature verification.
  • Multiple signatures: Labels are not signed, and VerificationResult has no defined order. Choose the required tags or validate all signatures as appropriate.

See also RFC 9421 Security Considerations.

Limitations and Compliance

RFC 9421 Compliance

Following are the known limitations and deviations:

  • HTTP trailers: The ;tr component identifier parameter is not supported. Signature and Signature-Input fields cannot be processed as trailers.
  • Query parameter parsing: @query-param uses Go's url.URL.Query() to parse form parameters. Its handling of malformed percent escapes, raw semicolons, and invalid UTF-8 differs from WHATWG form parsing. For ambiguous or repeated parameters, cover the entire query with @query instead. The @query-param component uses %20 for spaces, following the RFC 9421 examples and other HMS implementations.

Other Limitations

  • Body streaming: Content-Digest generation and verification currently require buffering the complete message body in memory. Streaming digest calculation is not yet supported.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupportedKeyType indicates that the supplied key material has an unsupported Go type.
	ErrUnsupportedKeyType = errors.New("unsupported key type/format")

	// ErrUnsupportedAlgorithm indicates that the requested signature or digest algorithm is unsupported.
	ErrUnsupportedAlgorithm = errors.New("unknown/unsupported algorithm")

	// ErrInvalidKeySize indicates that a key has an incompatible size or curve for its algorithm.
	ErrInvalidKeySize = errors.New("invalid key size")

	// ErrNoKeyProvided indicates that required key material was not supplied.
	ErrNoKeyProvided = errors.New("no key provided")

	// ErrInvalidSignature indicates that cryptographic signature verification failed.
	ErrInvalidSignature = errors.New("invalid signature")

	// ErrVerificationFailed indicates that verifying the selected signatures failed; it wraps the underlying error.
	ErrVerificationFailed = errors.New("verification failed")

	// ErrContentDigestMismatch indicates that a covered Content-Digest does not match the message body.
	ErrContentDigestMismatch = errors.New("content digest mismatch")

	// ErrMalformedData indicates malformed signature or other structured HTTP message data.
	ErrMalformedData = errors.New("malformed data")

	// ErrUnsupportedComponentIdentifier indicates that a covered component identifier is unsupported.
	ErrUnsupportedComponentIdentifier = errors.New("unsupported component identifier")

	// ErrInvalidComponentIdentifier indicates a malformed component identifier or invalid component parameters.
	ErrInvalidComponentIdentifier = errors.New("invalid component identifier")

	// ErrCanonicalization indicates that a covered HTTP message component could not be canonicalized.
	ErrCanonicalization = errors.New("failed to canonicalize component")

	// ErrMalformedSignatureParameter indicates a signature parameter with an invalid type or value.
	ErrMalformedSignatureParameter = errors.New("malformed signature parameter")

	// ErrNoApplicableDigestFound indicates that no supported digest could be checked in Content-Digest.
	ErrNoApplicableDigestFound = errors.New("no applicable digest found")

	// ErrVerifierCreation indicates that the verifier configuration could not be constructed.
	ErrVerifierCreation = errors.New("verifier creation failed")

	// ErrParameter indicates a failed signature parameter check or invalid option.
	ErrParameter = errors.New("parameter error")

	// ErrValidity indicates that a signature failed its time validity checks.
	ErrValidity = errors.New("validity error")

	// ErrMissingParameter indicates that a required signature parameter or covered component is missing.
	ErrMissingParameter = errors.New("missing parameter error")

	// ErrSignatureNegotiationError indicates a failure while preparing signature negotiation.
	ErrSignatureNegotiationError = errors.New("signature negotiation error")
)

Functions

func WithComponents

func WithComponents(identifiers ...string) componentsOption

WithComponents specifies component identifiers to cover when signing, require during verification, or request in Accept-Signature. Each identifier must be a serialized Structured Fields String Item, such as `"@method"` or `"content-digest";req`. For `@query-param`, the `name` component parameter must contain the canonical percent-encoded parameter name. For example, use `"@query-param";name="x%2By"` for a query parameter named `x+y`; a literal `+` in `name` is rejected.

func WithContentDigestAlgorithmPreferences

func WithContentDigestAlgorithmPreferences(prefs ...AlgorithmPreference) contentDigestAlgorithmPreferencesOption

WithContentDigestAlgorithmPreferences specifies the algorithms and preferences to request in Want-Content-Digest.

func WithCreatedTimestamp added in v0.10.0

func WithCreatedTimestamp(flag bool) createdTimestampOption

WithCreatedTimestamp specifies whether the created parameter is required during verification or requested in Accept-Signature. False makes it optional during verification and omits it from Accept-Signature.

func WithExpiresTimestamp added in v0.10.0

func WithExpiresTimestamp(flag bool) expiredTimestampOption

WithExpiresTimestamp specifies whether the expires parameter is required during verification or requested in Accept-Signature. False makes it optional during verification and omits it from Accept-Signature.

func WithForbiddenParameters added in v0.10.0

func WithForbiddenParameters(names ...SignatureParameter) forbiddenParametersOption

WithForbiddenParameters rejects signatures containing any named parameter.

func WithKeyID added in v0.10.0

func WithKeyID(keyID string) keyIDOption

WithKeyID specifies the keyid parameter for signing or Accept-Signature. An empty value is ignored when signing and omitted from Accept-Signature.

func WithLabel

func WithLabel(label string) labelOption

WithLabel specifies the technical label for a signature or an Accept-Signature request. An empty label leaves the current label unchanged.

func WithNonceGetter added in v0.10.0

func WithNonceGetter(ng NonceGetter) nonceGetterOption

WithNonceGetter configures a nonce source for Accept-Signature, including verifier-based negotiation. A nil getter leaves the source unchanged.

func WithParameter added in v0.10.0

func WithParameter(name SignatureParameter, value any) parameterOption

WithParameter specifies an extension parameter for signing, verifying, or requesting a signature, either statically or for a single call. It can also be used in WithSignatureNegotiation. Extension values may be string, Token, DisplayString, time.Time (RFC 9651 Date), bool, int, int64, float64, or []byte. DisplayString must contain valid UTF-8, and Date values are transmitted with second precision. Standard RFC 9421 parameter names are reserved, except for a non-empty string nonce on Verify, Sign, or AcceptSignatureBuilder.Build. Verification requirements are additive; an invocation cannot override static requirements. Duplicate signing or builder parameters are rejected.

func WithRequiredParameters added in v0.10.0

func WithRequiredParameters(names ...SignatureParameter) requiredParametersOption

WithRequiredParameters requires the named signature parameters to be present. It does not check their application-specific semantics.

func WithSignatureAlgorithm added in v0.10.0

func WithSignatureAlgorithm(alg SignatureAlgorithm) signatureAlgorithmOption

WithSignatureAlgorithm specifies an alg parameter to request in Accept-Signature. It does not select a signing algorithm.

func WithTag

func WithTag(tag string) tagOption

WithTag specifies an application-defined tag for signing or Accept-Signature requests.

Types

type AcceptSignatureBuildOption added in v0.10.0

type AcceptSignatureBuildOption interface {
	// contains filtered or unexported methods
}

AcceptSignatureBuildOption configures a single AcceptSignatureBuilder.Build call.

type AcceptSignatureBuilder

type AcceptSignatureBuilder struct {
	// contains filtered or unexported fields
}

AcceptSignatureBuilder constructs an Accept-Signature request from the configured parameters and component requirements. Use NewAcceptSignature to create a builder with defaults, then call Build to add headers.

func NewAcceptSignature

func NewAcceptSignature(opts ...AcceptSignatureOption) (*AcceptSignatureBuilder, error)

NewAcceptSignature creates an AcceptSignatureBuilder for requesting a signature from a peer. By default, it uses label "sig", requests created and expires parameters, and does not request a nonce. If Content-Digest is requested, the default digest preferences are SHA-256 and SHA-512.

func (*AcceptSignatureBuilder) Build

Build appends an Accept-Signature header to header using the configured signature requirements. If Content-Digest is requested, it also appends Want-Content-Digest preferences. Additional extension parameters can be supplied with WithParameter. A non-empty nonce may be provided for this call with WithParameter("nonce", value), overriding a configured WithNonceGetter without invoking it. Otherwise, the configured getter is used if present; if neither is provided, no nonce is requested. Options do not modify the builder. The caller must provide a writable, non-nil http.Header.

type AcceptSignatureOption

type AcceptSignatureOption interface {
	// contains filtered or unexported methods
}

AcceptSignatureOption configures an AcceptSignatureBuilder.

type AlgorithmPreference

type AlgorithmPreference struct {
	// Algorithm is the desired digest algorithm.
	Algorithm DigestAlgorithm
	// Preference is the preference value serialized alongside the algorithm.
	Preference int
}

AlgorithmPreference associates a Content-Digest algorithm with a numeric preference value for the Want-Content-Digest header.

func (AlgorithmPreference) String

func (p AlgorithmPreference) String() string

String formats the preference as "algorithm=preference".

type DigestAlgorithm

type DigestAlgorithm string

DigestAlgorithm identifies a hash algorithm supported for HTTP Content-Digest generation and verification.

const (
	// Sha256 selects SHA-256.
	Sha256 DigestAlgorithm = "sha-256"

	// Sha512 selects SHA-512.
	Sha512 DigestAlgorithm = "sha-512"
)

type DisplayString added in v0.12.0

type DisplayString string

DisplayString represents an RFC 9651 Structured Fields Display String. Unlike an ordinary Structured Fields string, it may contain Unicode.

type Key

type Key struct {
	// Algorithm is the signature algorithm to use with Material.
	// It must be compatible with the supplied key material.
	Algorithm SignatureAlgorithm

	// Material is the private, public, or symmetric key material used by the
	// chosen algorithm. The built-in implementations accept the
	// corresponding Go crypto key types or []byte for HMAC. Applications
	// may also provide a MessageSigner or MessageVerifier implementation.
	Material any
}

Key combines cryptographic key material with the concrete signature algorithm to use. Signing requires private or symmetric key material (or a signer interface); verification requires public or symmetric key material (or a verifier interface).

func (Key) ResolveKey

func (k Key) ResolveKey(_ context.Context, _ SignatureInfo) (KeyInfo, error)

ResolveKey makes a statically configured Key usable as a KeyResolver.

type KeyInfo added in v0.10.0

type KeyInfo struct {
	// Key is the trusted key and algorithm selected for this signature.
	Key Key
	// Metadata is application-specific information returned alongside the key.
	// It is passed through to VerifiedSignature only on successful verification.
	Metadata any
}

KeyInfo is returned by a KeyResolver and contains the accepted verification key and optional application-defined information about its resolution.

type KeyResolver

type KeyResolver interface {
	// ResolveKey returns the trusted key and optional metadata for info.
	// It is called before cryptographic verification. SignatureInfo and its
	// Message contain unverified, sender-controlled data. The implementation
	// must not mutate SignatureInfo.Message, Components, Parameters, or their
	// mutable contents: these are shared with the verification process and, on
	// success, with VerifiedSignature.
	ResolveKey(ctx context.Context, info SignatureInfo) (KeyInfo, error)
}

KeyResolver resolves a trusted verification key for a specific HTTP message signature.

type Message

type Message struct {
	// Context is passed to key resolution and Accept-Signature nonce generation.
	Context context.Context //nolint: containedctx

	// Method is the associated HTTP request method.
	Method string

	// Authority is the authority (host and optional port) of the request.
	Authority string

	// URL is the associated HTTP request URL.
	URL *url.URL

	// Header contains the headers of the request or response being processed.
	// The signer may update this map with signatures and a Content-Digest.
	Header http.Header

	// Body opens the body of the request or response being processed.
	Body func() (io.ReadCloser, error)

	// RequestHeader contains the associated request headers for a response.
	RequestHeader http.Header

	// RequestBody opens the associated request body for response ;req components.
	RequestBody func() (io.ReadCloser, error)

	// StatusCode is the HTTP response status code (unused for requests).
	StatusCode int

	// IsRequest distinguishes requests from responses for canonicalization.
	IsRequest bool
	// contains filtered or unexported fields
}

Message represents the HTTP request or response data needed to construct and verify an HTTP message signature. For a response, request-related fields supply data used by component identifiers with the ;req parameter. Not every field is necessarily covered by the signature. Message data must remain stable after it is prepared for signing or verification, apart from headers added by signing. A Message must not be copied after its first use.

func MessageForResponse

func MessageForResponse(req *http.Request, respHeader http.Header, body []byte, respCode int) *Message

MessageForResponse creates a Message for signing a response to req. It clones the response and request headers and makes the supplied body available for Content-Digest and other covered components. The request body may be buffered and restored when a ;req component requires it.

func MessageFromRequest

func MessageFromRequest(req *http.Request) *Message

MessageFromRequest creates a Message for signing or verifying an HTTP request. Request headers are cloned. If the body must be read and req.GetBody is unavailable, the original body is buffered and replaced so it remains readable. Callers must enforce size limits for untrusted request bodies.

func MessageFromResponse

func MessageFromResponse(rw *http.Response) *Message

MessageFromResponse creates a Message from a received HTTP response and its associated request. Response and request headers are cloned. The response body may be buffered and restored when a covered component needs it. The request body is available for ;req components only when the associated request has a GetBody function.

type MessageSigner added in v0.11.0

type MessageSigner interface {
	SignMessage(ctx context.Context, message []byte) ([]byte, error)
}

MessageSigner signs the complete HTTP signature base using an application-provided implementation. The implementation is responsible for all cryptographic processing and must return signature bytes in the format required by the selected HTTP Message Signatures algorithm. Context is supplied by the message being signed.

type MessageVerifier added in v0.11.0

type MessageVerifier interface {
	VerifyMessage(ctx context.Context, message, signature []byte) error
}

MessageVerifier verifies the complete HTTP signature base using an application-provided implementation. The signature bytes are passed through unchanged; the implementation is responsible for the algorithm and encoding. Context is supplied by the message being verified.

type NoApplicableSignatureError

type NoApplicableSignatureError struct {
	// contains filtered or unexported fields
}

NoApplicableSignatureError indicates that a message does not contain all required signatures or any signature selected by the verifier. If signature negotiation was configured, Negotiate can add the requested headers to a response. It can be recognized with errors.As or errors.Is.

func (*NoApplicableSignatureError) Error

Error returns a description of the missing applicable signature.

func (*NoApplicableSignatureError) Is

Is matches another NoApplicableSignatureError for use with errors.Is.

func (*NoApplicableSignatureError) Negotiate

func (e *NoApplicableSignatureError) Negotiate(header http.Header)

Negotiate appends any prepared Accept-Signature and related negotiation headers to header. If no negotiation was configured, it adds nothing. The caller must supply a writable, non-nil http.Header.

type NonceGetter

type NonceGetter interface {
	// GetNonce returns a nonce or an error for the given context.
	GetNonce(ctx context.Context) (string, error)
}

NonceGetter supplies a nonce for an Accept-Signature request. An empty result omits the nonce parameter. Generating and correlating nonce values is the responsibility of the calling application.

type NonceGetterFunc

type NonceGetterFunc func(ctx context.Context) (string, error)

NonceGetterFunc adapts a function to the NonceGetter interface.

func (NonceGetterFunc) GetNonce

func (ng NonceGetterFunc) GetNonce(ctx context.Context) (string, error)

GetNonce calls the wrapped function.

type SignOption added in v0.10.0

type SignOption interface {
	// contains filtered or unexported methods
}

SignOption configures a single Sign call.

type SignatureAlgorithm

type SignatureAlgorithm string

SignatureAlgorithm identifies the concrete cryptographic algorithm used to create or verify an HTTP message signature. The constants below are supported by the built-in implementations. Other algorithms can be used with an application-provided MessageSigner or MessageVerifier. The selected algorithm must be compatible with the supplied Key.Material.

const (
	// RsaPkcs1v15Sha256 selects RSA PKCS#1 v1.5 with SHA-256.
	RsaPkcs1v15Sha256 SignatureAlgorithm = "rsa-v1_5-sha256"

	// RsaPkcs1v15Sha384 selects RSA PKCS#1 v1.5 with SHA-384.
	RsaPkcs1v15Sha384 SignatureAlgorithm = "rsa-v1_5-sha384"

	// RsaPkcs1v15Sha512 selects RSA PKCS#1 v1.5 with SHA-512.
	RsaPkcs1v15Sha512 SignatureAlgorithm = "rsa-v1_5-sha512"

	// RsaPssSha256 selects RSA-PSS with SHA-256.
	RsaPssSha256 SignatureAlgorithm = "rsa-pss-sha256"

	// RsaPssSha384 selects RSA-PSS with SHA-384.
	RsaPssSha384 SignatureAlgorithm = "rsa-pss-sha384"

	// RsaPssSha512 selects RSA-PSS with SHA-512.
	RsaPssSha512 SignatureAlgorithm = "rsa-pss-sha512"

	// EcdsaP256Sha256 selects ECDSA using P-256 and SHA-256.
	EcdsaP256Sha256 SignatureAlgorithm = "ecdsa-p256-sha256"

	// EcdsaP384Sha384 selects ECDSA using P-384 and SHA-384.
	EcdsaP384Sha384 SignatureAlgorithm = "ecdsa-p384-sha384"

	// EcdsaP521Sha512 selects ECDSA using P-521 and SHA-512.
	EcdsaP521Sha512 SignatureAlgorithm = "ecdsa-p521-sha512"

	// Ed25519 selects Ed25519 signatures.
	Ed25519 SignatureAlgorithm = "ed25519"

	// HmacSha256 selects HMAC with SHA-256.
	HmacSha256 SignatureAlgorithm = "hmac-sha256"

	// HmacSha384 selects HMAC with SHA-384.
	HmacSha384 SignatureAlgorithm = "hmac-sha384"

	// HmacSha512 selects HMAC with SHA-512.
	HmacSha512 SignatureAlgorithm = "hmac-sha512"
)

type SignatureInfo added in v0.10.0

type SignatureInfo struct {
	// Label is the current Signature-Input dictionary member name. It is not
	// signed and can be changed by intermediaries; it is only a technical
	// reference.
	Label string

	// Message is the HTTP message being verified. Not all of its fields are
	// necessarily covered by the signature, and it must not be modified.
	Message *Message

	// Components maps covered component identifiers to the canonicalized
	// values used to construct the signature base. Map keys are serialized
	// Structured Fields String Items (e.g. `"@method"` or `"content-digest";req`),
	// including identifier parameters. It excludes the synthetic
	// @signature-params component.
	Components map[string]string

	// Parameters contains the transmitted, decoded signature parameters.
	Parameters SignatureParameters
}

SignatureInfo describes one signature being considered for verification. All its values are unverified and may be sender-controlled. The resolver implementation must treat them as untrusted input when selecting key material. The message and maps are shared with the verification process and must not be modified by the resolver (including mutable values within the maps).

type SignatureNegotiationOption

type SignatureNegotiationOption interface {
	// contains filtered or unexported methods
}

SignatureNegotiationOption configures requests additional to the verifier's signature requirements.

type SignatureParameter

type SignatureParameter string

SignatureParameter names an RFC 9421 signature parameter or a profile-specific extension parameter.

const (
	// KeyID names the keyid signature parameter.
	KeyID SignatureParameter = "keyid"

	// Alg names the alg signature parameter.
	Alg SignatureParameter = "alg"

	// Created names the created timestamp parameter.
	Created SignatureParameter = "created"

	// Expires names the expires timestamp parameter.
	Expires SignatureParameter = "expires"

	// Nonce names the nonce signature parameter.
	Nonce SignatureParameter = "nonce"

	// Tag names the tag signature parameter.
	Tag SignatureParameter = "tag"
)

type SignatureParameters added in v0.10.0

type SignatureParameters map[SignatureParameter]any

SignatureParameters contains all signature parameters transmitted in a Signature-Input entry, including profile-specific extensions. Keys are the parameter names; values are decoded Structured Fields bare items (for example string, Token, DisplayString, time.Time, int64, float64, bool, or []byte).

func (SignatureParameters) Alg added in v0.10.0

Alg returns the alg parameter if present and of the expected type.

func (SignatureParameters) Created added in v0.10.0

func (p SignatureParameters) Created() (int64, bool)

Created returns the created parameter as a Unix timestamp if it has the expected type.

func (SignatureParameters) Expires added in v0.10.0

func (p SignatureParameters) Expires() (int64, bool)

Expires returns the expires parameter as a Unix timestamp if it has the expected type.

func (SignatureParameters) KeyID added in v0.10.0

func (p SignatureParameters) KeyID() (string, bool)

KeyID returns the keyid parameter if present and of the expected type.

func (SignatureParameters) Nonce added in v0.10.0

func (p SignatureParameters) Nonce() (string, bool)

Nonce returns the nonce parameter if present and of the expected type.

func (SignatureParameters) Tag added in v0.10.0

func (p SignatureParameters) Tag() (string, bool)

Tag returns the tag parameter if present and of the expected type.

type SignatureRequest added in v0.11.0

type SignatureRequest struct {
	// Label is the label of the requested signature.
	Label string

	// Components lists the requested component identifiers in their requested
	// order, serialized as Structured Fields Items. Each identifier can be
	// passed to WithComponents.
	Components []string

	// KeyID is the requested keyid parameter. It is empty if not requested.
	KeyID string

	// Algorithm is the requested alg parameter. It is empty if not requested.
	// It is not checked against the supported signature algorithms.
	Algorithm SignatureAlgorithm

	// Tag is the requested tag parameter. It is empty if not requested.
	Tag string

	// Nonce is the requested nonce parameter. It is empty if not requested.
	Nonce string

	// Created reports whether a created timestamp is requested.
	Created bool

	// Expires reports whether an expires timestamp is requested.
	Expires bool

	// Extensions contains the requested parameters not defined by RFC 9421.
	// It is nil if there are none. Its values are decoded as described for
	// SignatureParameters.
	Extensions SignatureParameters
}

SignatureRequest describes a single signature requested by a member of an Accept-Signature field. All its values are controlled by the peer. The application must decide whether a request is acceptable before signing.

func ParseAcceptSignature added in v0.11.0

func ParseAcceptSignature(header http.Header) ([]SignatureRequest, error)

ParseAcceptSignature parses the Accept-Signature fields in header and returns the signature requests in the order they appear. It returns an empty result if header contains no Accept-Signature field.

If the fields as a whole are not a valid Structured Fields Dictionary, it returns no requests and an error wrapping ErrMalformedData. A member that cannot be used, for example because it is malformed or names an unsupported component, does not affect the other members: the requests of the usable members are returned together with a joined error that has an entry wrapping ErrMalformedData for each unusable member. RFC 9421 permits ignoring requests that cannot be fulfilled, so a non-nil error does not invalidate the returned requests. Applications requiring all requests to be usable must check it.

type Signer

type Signer interface {
	// Sign signs msg and returns its updated HTTP headers, including the
	// Signature and Signature-Input fields. It also updates msg.Header and
	// may update Content-Digest when that component is covered.
	// Options apply only to this invocation and do not modify the Signer.
	Sign(msg *Message, opts ...SignOption) (http.Header, error)
}

Signer creates HTTP message signatures using a configured key, set of covered components, and signature parameters.

func NewSigner

func NewSigner(key Key, opts ...SignerOption) (Signer, error)

NewSigner creates a Signer using key for cryptographic signing. The key must contain compatible private, symmetric, or application-provided signing material. By default, signatures use label "sig", include created, and expire after 30 seconds. The alg, keyid, tag, and nonce parameters are omitted. When generating Content-Digest, the signer uses both SHA-256 and SHA-512 unless WithContentDigestAlgorithm selects one.

type SignerOption

type SignerOption interface {
	// contains filtered or unexported methods
}

SignerOption configures the signing policy of a Signer.

func WithAlg added in v0.10.0

func WithAlg() SignerOption

WithAlg includes the selected Key.Algorithm as the alg signature parameter. It does not select or change the signing algorithm.

func WithContentDigestAlgorithm

func WithContentDigestAlgorithm(alg DigestAlgorithm) SignerOption

WithContentDigestAlgorithm selects the algorithm for generating a covered Content-Digest. An unsupported algorithm causes ErrUnsupportedAlgorithm.

func WithTTL

func WithTTL(ttl time.Duration) SignerOption

WithTTL specifies the interval between the created and expires signature parameters. A non-positive duration omits expires.

type Token added in v0.10.0

type Token string

Token represents a Structured Fields token. It is distinct from string so applications can distinguish token values from quoted Structured Fields strings when validating profile-specific signature parameters.

type VerificationResult added in v0.10.0

type VerificationResult []VerifiedSignature

VerificationResult contains the signatures selected and successfully verified during one call to Verifier.Verify. The order of the signatures is not guaranteed.

type VerifiedSignature added in v0.10.0

type VerifiedSignature struct {
	// Label is the received signature label. It is not cryptographically
	// protected and must not be used as an identity or authorization claim.
	Label string

	// Components contains the canonicalized values of the covered HTTP
	// message components, without the synthetic @signature-params component.
	// Map keys are serialized Structured Fields String Items (e.g. `"@method"`
	// or `"content-digest";req`).
	Components map[string]string

	// Parameters contains the actual transmitted signature parameters,
	// including extensions, without synthetic defaults.
	Parameters SignatureParameters

	// Metadata is the application-defined metadata provided by the KeyResolver
	// for this signature.
	Metadata any
}

VerifiedSignature contains the attributes of a successfully verified HTTP message signature and the metadata returned by the KeyResolver.

type Verifier

type Verifier interface {
	// Verify returns information about the successfully verified signatures
	// or an error. Per-call requirements do not change the Verifier.
	Verify(msg *Message, opts ...VerifyOption) (VerificationResult, error)
}

Verifier verifies HTTP message signatures according to its configured requirements. A call succeeds only if all selected signatures pass.

func NewVerifier

func NewVerifier(resolver KeyResolver, opts ...VerifierOption) (Verifier, error)

NewVerifier creates a Verifier instance. Without WithValidateAllSignatures, at least one WithRequiredTag is necessary. By default, created and expires are required and signatures may be at most 30 seconds old. Optional created or expires parameters are still checked when present. Global WithSignatureNegotiation cannot be combined with WithValidateAllSignatures. More specific requirements can be set through opts.

type VerifierOption

type VerifierOption interface {
	// contains filtered or unexported methods
}

VerifierOption configures signature selection or verification requirements. It can also be used within WithRequiredTag for per-tag requirements.

func WithMaxAge

func WithMaxAge(age time.Duration) VerifierOption

WithMaxAge specifies the maximum allowed age of a signature with a created timestamp. The duration must be positive.

func WithRequiredTag

func WithRequiredTag(tag string, opts ...VerifierOption) VerifierOption

WithRequiredTag specifies a required application-defined tag and its per-tag verifier options. Each non-empty tag may be configured only once.

func WithSignatureNegotiation

func WithSignatureNegotiation(opts ...SignatureNegotiationOption) VerifierOption

WithSignatureNegotiation enables Accept-Signature negotiation based on the verifier's requirements. Its options specify additional requests that cannot be derived from those requirements.

func WithValidateAllSignatures

func WithValidateAllSignatures() VerifierOption

WithValidateAllSignatures selects all signatures for verification, rather than only those with required tags.

func WithValidityTolerance

func WithValidityTolerance(tolerance time.Duration) VerifierOption

WithValidityTolerance specifies the allowed clock skew for created and expires timestamp checks. The duration must not be negative; zero allows no clock skew.

func WithoutMaxAge added in v0.11.0

func WithoutMaxAge() VerifierOption

WithoutMaxAge disables the maximum age check for signatures with a created timestamp. Checks for future created timestamps and signature expiration remain active.

type VerifyOption added in v0.10.0

type VerifyOption interface {
	// contains filtered or unexported methods
}

VerifyOption adds requirements for a single Verify call.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址