sigv4a

package
v1.31.0 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: CC0-1.0 Imports: 20 Imported by: 0

Documentation

Overview

Package sigv4a signs and verifies HTTP requests with AWS Signature Version 4A (the AWS4-ECDSA-P256-SHA256 scheme): the same canonical-request construction as classic SigV4 (shared via web/middleware/internal/awssig), but signed with an ECDSA P-256 key derived deterministically from the credential instead of an HMAC key. Verifiers can therefore hold only the public key — material that verifies signatures but can never mint them.

Index

Constants

View Source
const (
	UnsignedPayload  = awssig.UnsignedPayload
	StreamingPayload = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD"
)

Payload-hash sentinels. UnsignedPayload matches exactly (AWS defines it case-sensitively); any STREAMING-* sentinel is rejected inside awssig.ResolvePayloadHash.

Variables

View Source
var (
	ErrMissingAuth          = errors.New("sigv4a: missing or malformed Authorization")
	ErrMissingSignedHost    = errors.New("sigv4a: host must appear in SignedHeaders")
	ErrMissingRegionSet     = errors.New("sigv4a: x-amz-region-set must appear in SignedHeaders")
	ErrUnknownKey           = errors.New("sigv4a: unknown access key id")
	ErrClockSkew            = errors.New("sigv4a: request time outside allowed skew")
	ErrScopeMismatch        = errors.New("sigv4a: credential scope does not match")
	ErrStreamingUnsupported = awssig.ErrStreamingUnsupported
	ErrBodyHash             = awssig.ErrBodyHash
	ErrUnauthorized         = errors.New("sigv4a: signature mismatch")
	ErrBodyTooLarge         = awssig.ErrBodyTooLarge
	ErrNotConfigured        = errors.New("sigv4a: neither Verifier.Lookup nor Verifier.KeyLookup is set")
)

Errors returned by Verify. Callers typically map ErrUnauthorized and ErrUnknownKey to 403 and the rest to 400.

Functions

func DeriveKeyPair

func DeriveKeyPair(accessKeyID, secretAccessKey string) (*ecdsa.PrivateKey, error)

DeriveKeyPair deterministically derives the SigV4A ECDSA P-256 keypair for a credential. It implements AWS's counter-mode KDF (NIST SP 800-108 style, PRF = HMAC-SHA256, key = "AWS4A"+secret) with rejection sampling: a candidate above N-2 retries with the next counter byte (1..254), an accepted candidate is incremented by one to land in [1, N-1]. The per-attempt rejection probability is ~2^-32, so the loop virtually always succeeds on the first pass.

The keypair is a pure function of (accessKeyID, secretAccessKey): unlike the SigV4 HMAC ladder there is no date/region/service scoping, so the same key signs and verifies for the credential's whole lifetime.

The big.Int comparison is not constant-time; that is acceptable because derivation only ever runs over our own stored secret, never comparing against attacker-controlled input.

func KeyID

func KeyID(ctx context.Context) (string, bool)

KeyID returns the verified access key id stored by Middleware, if any. The value is stored via authctx, so it is also visible to sigv4.KeyID and authctx.KeyID directly.

func TwirpError

func TwirpError(ctx context.Context, err error) error

TwirpError maps a verification error to the twirp error middlewares write to clients. Sentinels that describe the caller's own request keep their message; key and signature failures collapse to one opaque message so a probe cannot distinguish unknown, disabled, and mis-signed credentials. Unexpected errors are logged with their cause and surfaced as an opaque internal error.

func User

func User(ctx context.Context) (*iamv1.User, bool)

User returns the IAM user associated with the verified caller, if any. The bool is false when no middleware populated it.

func WithUser

func WithUser(ctx context.Context, u *iamv1.User) context.Context

WithUser stores the IAM user resolved for the verified caller in ctx. It is the local-verification counterpart to iamsts.Caller: middleware resolves the access key id from KeyID to its owning user and stashes it here so downstream code (logging interceptors, handlers) can attribute the call without re-querying the backing store. The value is stored via authctx, so it is also visible to sigv4.User and authctx.User directly.

Types

type Credential

type Credential struct {
	AccessKeyID string
	Date        string
	Service     string
}

Credential is the parsed Credential= component of a SigV4A Authorization header: the access key id plus the literal, unnormalized scope strings.

func ParseCredential

func ParseCredential(authorization string) (*Credential, error)

ParseCredential extracts the credential scope from an AWS4-ECDSA-P256-SHA256 Authorization header value. It returns ErrMissingAuth for anything malformed, matching Verify.

type Lookuper

type Lookuper interface {
	// Lookup resolves an access key id to its secret access key. Return
	// ErrUnknownKey for unknown keys. This is the one piece you must supply.
	Lookup(accessKeyID string) (secretAccessKey string, err error)
}

Lookuper encapsulates the secret access key lookup so that the underlying logic can have arbitrary implementations.

type LookuperFunc

type LookuperFunc func(accessKeyID string) (secretAccessKey string, err error)

LookuperFunc adapts an ordinary function to the Lookuper interface, the same way http.HandlerFunc adapts a function to http.Handler.

func (LookuperFunc) Lookup

func (f LookuperFunc) Lookup(accessKeyID string) (secretAccessKey string, err error)

Lookup calls f(accessKeyID).

type PublicKeyLookuper

type PublicKeyLookuper interface {
	LookupPublicKey(ctx context.Context, accessKeyID string) (*ecdsa.PublicKey, error)
}

PublicKeyLookuper resolves an access key id to the credential's SigV4A ECDSA P-256 public key. Return ErrUnknownKey when the key does not exist or may not sign (disabled key or user); any other error is treated as a server fault. Public keys are verification-only material: an implementation can hold and cache them without ever being able to mint a signature.

type PublicKeyLookuperFunc

type PublicKeyLookuperFunc func(ctx context.Context, accessKeyID string) (*ecdsa.PublicKey, error)

PublicKeyLookuperFunc adapts an ordinary function to PublicKeyLookuper.

func (PublicKeyLookuperFunc) LookupPublicKey

func (f PublicKeyLookuperFunc) LookupPublicKey(ctx context.Context, accessKeyID string) (*ecdsa.PublicKey, error)

LookupPublicKey calls f.

type Signer

type Signer struct {

	// Now is overridable for tests. Defaults to time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

Signer signs outgoing HTTP requests with AWS Signature Version 4A. It is the client-side counterpart to Verifier and shares its canonicalization through awssig, so the two agree by construction.

The ECDSA keypair is derived once at construction; the secret access key is not retained. Application code usually wants the sigv4aclient subpackage, which wraps a Signer in an http.RoundTripper.

func NewSigner

func NewSigner(accessKeyID, secretAccessKey, region, service string) (*Signer, error)

NewSigner derives the SigV4A keypair for the credential and returns a Signer that signs for the given region (the X-Amz-Region-Set value; a single region name for within.website services) and service.

func (*Signer) Sign

func (s *Signer) Sign(r *http.Request, body []byte) error

Sign signs r in place: it hashes body (which must be the full request payload; nil means empty), declares it in X-Amz-Content-Sha256, and signs the host, x-amz-content-sha256, x-amz-date, and x-amz-region-set headers. It does not touch r.Body.

type Verifier

type Verifier struct {
	// Region must be covered by the request's signed X-Amz-Region-Set;
	// Service must match the credential scope.
	Region  string
	Service string

	// Lookup resolves an access key id to its secret. Return ErrUnknownKey
	// for unknown keys. This is the one piece you must supply.
	Lookup Lookuper

	// KeyLookup resolves an access key id to its ECDSA public key. When set
	// it takes precedence over Lookup, and the verifier never sees the raw
	// secret — this is how services that must not hold secrets verify
	// locally (see web/middleware/sigv4a/iamsts). Exactly one of Lookup or
	// KeyLookup must be set.
	KeyLookup PublicKeyLookuper

	// MaxClockSkew bounds how far the request's X-Amz-Date may be from now.
	// Defaults to 15 minutes (matching AWS) when zero.
	MaxClockSkew time.Duration

	// DisablePathEscaping selects S3-style canonicalization, where the path
	// is used as-is rather than being URI-encoded a second time. Set true
	// when emulating S3; leave false for every other AWS service.
	DisablePathEscaping bool

	// MaxBodySize caps how many bytes of the body will be buffered to verify
	// the payload hash. Zero means unlimited. Requests that exceed it are
	// rejected with ErrBodyTooLarge.
	MaxBodySize int64

	// Now is overridable for tests. Defaults to time.Now.
	Now func() time.Time
}

Verifier validates SigV4A-signed requests for a single region/service.

func (*Verifier) Middleware

func (v *Verifier) Middleware(next http.Handler) http.Handler

Middleware returns net/http middleware that rejects unsigned or invalid requests with 401/403 and otherwise passes them through. On success it stores the verified access key id in the request context.

func (*Verifier) Verify

func (v *Verifier) Verify(r *http.Request) (string, error)

Verify checks a single request. On success it returns the access key id of the caller. The request body is buffered and reset so downstream handlers can read it normally.

Directories

Path Synopsis
Package iamsts authenticates HTTP requests signed with AWS Signature Version 4A by verifying them locally against a cached ECDSA public key fetched from IAM's key service.
Package iamsts authenticates HTTP requests signed with AWS Signature Version 4A by verifying them locally against a cached ECDSA public key fetched from IAM's key service.
Package sigv4aclient provides an http.RoundTripper that signs outgoing requests with AWS Signature Version 4A. It is the SigV4A counterpart to web/middleware/sigv4/sigv4client (which signs classic SigV4 for real AWS services): use this package for within.website services verified by web/middleware/sigv4a.
Package sigv4aclient provides an http.RoundTripper that signs outgoing requests with AWS Signature Version 4A. It is the SigV4A counterpart to web/middleware/sigv4/sigv4client (which signs classic SigV4 for real AWS services): use this package for within.website services verified by web/middleware/sigv4a.

Jump to

Keyboard shortcuts

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