sigv4

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2023 License: BSD-3-Clause Imports: 16 Imported by: 0

README

AWS Signature V4 for Go

Go Reference BSD 3-Clause License

sigv4 package contains an implementation of AWS Signature V4 signer.

Installation

go get github.com/imacks/aws-sigv4

See doc.go or pkg.go.dev for further documentation and examples.

Issues

Search existing issues before you open a new one. You should mention the version of this package you are using, Go language, and OS. Include code that reproduces your issue where appropriate.

Please DM the code owners directly if you believe you have found a security vulnerability.

Contributing

Please review the contributing guidelines before submitting a pull requests.

Documentation

Overview

Package sigv4 implements AWS Signature Version 4 (sigv4) signer. See authoritative documentation at https://docs.aws.amazon.com/IAM/latest/UserGuide/signing-elements.html for details.

The sigv4 algorithm is briefly described here.

Step 1: make a canonical request string in the format "<METHOD>\n<URI>\n<QUERY>\n<HEADERS>\n<SIGNED_HEADERS>\n<PAYLOAD_HASH>".

  • METHOD: HTTP method in upper case.
  • URI: the URL path component (between host and query), such as "/foo/bar". It must be URI-encoded. Use "/" if this component is empty.
  • QUERY: the URL query component (after the first "?"), such as "Foo=A&Bar=B". For each key-value pair, reserved characters (including space) in both name and value must be percent-encoded. If value is empty, it should end with the "=" character, such as "Foo=". Lastly, sort by key name. If there are multiple key-value pairs with the same key name, they are sorted by their values. Use an empty string if there is no query component.
  • HEADERS: for each header in request that should be protected by the signature, its name and value, followed by newline ("\n"). Header names must be in lower-case and sorted. Values are separated from its header name by ":". Multiple values must be comma separated, with leading and trailing spaces removed. Multiple spaces must be replaced with single space. The "host" header (or ":authority" if HTTP/2) must be included. If the request contains any header with "x-amz-" prefix, they must be included as well. Do not include "authorization" or "x-amzn-trace-id". All other headers are optional.
  • SIGNED_HEADERS: semi-colon (";") delimited list of header names in HEADERS. Like HEADERS, it must be sorted and in lower-case.
  • PAYLOAD_HASH: the value of hex(sha256(BODY)), where BODY is HTTP request body content. If HTTP request body is empty, use the hash value of an empty string.

Step 2: calculate hex(sha256(CANON_REQ_STR)), where CANON_REQ_STR is result of step 1.

Step 3: calculate string to sign "<ALGO>\n<TIMESTAMP>\n<CRED_SCOPE>\n<HASH>", where:

  • ALGO: hardcoded AWS4-HMAC-SHA256
  • TIMESTAMP: ISO8601 format time
  • CRED_SCOPE: "<YYYYMMDD>/<region>/<service>/aws4_request", where "<YYYYMMDD>" is date portion of TIMESTAMP
  • HASH: value from step 2

Step 4: calculate signature "<sig>" per pseudo code here:

    // Secret is user secret key
    // Date is YYYYMMDD date from CRED_SCOPE in step 3
    hDate = hmacsha256("AWS4"+Secret, Date)
    // region and service are the same values in CRED_SCOPE
    hRegion = hmacsha256(hDate, Region)
    hService = hmacsha256(hRegion, Service)
    hSig = hmacsha256(hService, "aws4_request")

	// StringToSign is value from step 3
    // sig is the final result for this step
    sig = hex(hmacsha256(hSig, StringToSign))

Step 5: *either* add signature to request header or query string:

  • Header: add header "Authorization: AWS4-HMAC-SHA256 Credential=<ACCESS_ID>/<CRED_SCOPE>, SignedHeaders=<SIGNED_HEADERS>, Signature=<SIG>"
  • Query string: add these query parameters: "X-Amz-Algorithm=AWS4-HMAC-SHA256", "X-Amz-Credential=<ACCESS_ID>/<CRED_SCOPE>", "X-Amz-Date=<TIMESTAMP>", "X-Amz-SignedHeaders=<SIGNED_HEADERS>", "X-Amz-Signature=<SIG>"

Index

Constants

View Source
const (
	// SigningAlgorithm is the name of the algorithm used in this package.
	SigningAlgorithm = "AWS4-HMAC-SHA256"
	// EmptyStringSHA256 is the hex encoded sha256 value of an empty string.
	EmptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
	// UnsignedPayload indicates that the request payload body is unsigned.
	UnsignedPayload = "UNSIGNED-PAYLOAD"
	// AmzAlgorithmKey indicates the signing algorithm.
	AmzAlgorithmKey = "X-Amz-Algorithm"
	// AmzSecurityTokenKey indicates the security token to be used with temporary
	// credentials.
	AmzSecurityTokenKey = "X-Amz-Security-Token"
	// AmzDateKey is the UTC timestamp for the request in the format YYYYMMDD'T'HHMMSS'Z'.
	AmzDateKey = "X-Amz-Date"
	// AmzCredentialKey is the access key ID and credential scope.
	AmzCredentialKey = "X-Amz-Credential"
	// AmzSignedHeadersKey is the set of headers signed for the request.
	AmzSignedHeadersKey = "X-Amz-SignedHeaders"
	// AmzSignatureKey is the query parameter to store the SigV4 signature.
	AmzSignatureKey = "X-Amz-Signature"
	// TimeFormat is the time format to be used in the X-Amz-Date header or query
	// parameter.
	TimeFormat = "20060102T150405Z"
	// ShortTimeFormat is the shorten time format used in the credential scope.
	ShortTimeFormat = "20060102"
	// ContentSHAKey is the SHA256 of request body.
	ContentSHAKey = "X-Amz-Content-Sha256"
	// StreamingEventsPayload indicates that the request payload body is a signed
	// event stream.
	StreamingEventsPayload = "STREAMING-AWS4-HMAC-SHA256-EVENTS"
)

Signature Version 4 (SigV4) Constants

Variables

View Source
var ErrInvalidOption = errors.New("cannot apply option to HTTPSigner")

ErrInvalidOption means the option parameter is incompatible with the HTTPSigner.

Functions

func ContentSHA256Sum

func ContentSHA256Sum(r *http.Request) (string, error)

ContentSHA256Sum calculates the hex-encoded SHA256 checksum of r.Body. It returns EmptyStringSHA256 if r.Body is nil, r.Method is TRACE or r.ContentLength is zero. Returns non-nil error if r.Body cannot be read.

Types

type HTTPSigner

type HTTPSigner interface {
	// Sign AWS v4 requests with the provided payload hash, service name, region
	// the request is made to, and time the request is signed at. Set sigtime
	// to the future to create a request that cannot be used until the future time.
	//
	// payloadHash is the hex encoded SHA-256 hash of the request payload, and must
	// not be empty, even if the request has no payload (aka body). If the request
	// has no payload, use the hex encoded SHA-256 of an empty string, or the constant
	// EmptyStringSHA256. You can use the utility function ContentSHA256Sum to
	// calculate the hash of a http.Request body.
	//
	// Some services such as Amazon S3 accept alternative values for the payload
	// hash, such as "UNSIGNED-PAYLOAD" for requests where the body will not be
	// protected by sigv4. See https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html.
	//
	// Sign differs from Presign in that it will sign the request using HTTP headers.
	// The passed in request r will be modified in place: modified fields include
	// r.Host and r.Header.
	Sign(r *http.Request, payloadHash string, sigtime Time) error
	// Presign is like Sign, but does not modify request r. It returns a copy of
	// r.URL with additional query parameters that contains signing information.
	// The URL can be used to recreate an authenticated request without specifying
	// headers. It also returns http.Header as a second result, which must be
	// included in the reconstructed request.
	//
	// Header hoisting: use WithHeaderHoisting option function to specify whether
	// headers in request r should be added as query parameters. Some headers cannot
	// be hoisted, and are returned as the second result.
	//
	// Presign will not set the expires time of the presigned request automatically.
	// To specify the expire duration for a request, add the "X-Amz-Expires" query
	// parameter on the request with the value as the duration in seconds the
	// presigned URL should be considered valid for. This parameter is not used
	// by all AWS services, and is most notable used by Amazon S3 APIs.
	//
	//     expires := 20*time.Minute
	//     query := req.URL.Query()
	//     query.Set("X-Amz-Expires", strconv.FormatInt(int64(expires/time.Second), 10)
	//     req.URL.RawQuery = query.Encode()
	Presign(r *http.Request, payloadHash string, sigtime Time) (*url.URL, http.Header, error)
}

HTTPSigner is an AWS SigV4 signer that can sign HTTP requests.

func New

func New(opts ...HTTPSignerOption) (HTTPSigner, error)

New creates a HTTPSigner.

type HTTPSignerOption

type HTTPSignerOption func(HTTPSigner) error

HTTPSignerOption is an option parameter for HTTPSigner constructor function.

func WithCredential

func WithCredential(accessKey, secret, sessionToken string) HTTPSignerOption

WithCredential sets HTTPSigner credential fields.

func WithEscapeURLPath

func WithEscapeURLPath(enable bool) HTTPSignerOption

WithEscapeURLPath specifies whether HTTPSigner automatically escapes URL paths. Default is enabled.

func WithHeaderHoisting

func WithHeaderHoisting(enable bool) HTTPSignerOption

WithHeaderHoisting specifies whether HTTPSigner automatically hoist headers. Default is enabled.

func WithRegionService

func WithRegionService(region, service string) HTTPSignerOption

WithRegionService sets HTTPSigner region and service fields.

type Time

type Time struct {
	gotime.Time
	// contains filtered or unexported fields
}

Time wraps time.Time to cache its string format result.

func NewTime

func NewTime(t gotime.Time) Time

NewTime creates a new signingTime with the specified time.Time.

func (*Time) ShortTimeFormat

func (m *Time) ShortTimeFormat() string

ShortTimeFormat provides a time formatted in short time format.

func (*Time) TimeFormat

func (m *Time) TimeFormat() string

TimeFormat provides a time formatted in the X-Amz-Date format.

Jump to

Keyboard shortcuts

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