code.dwrz.net

Go monorepo.
Log | Files | Refs

stream.go (2537B)


      1 package v4
      2 
      3 import (
      4 	"context"
      5 	"crypto/sha256"
      6 	"encoding/hex"
      7 	"github.com/aws/aws-sdk-go-v2/aws"
      8 	v4Internal "github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4"
      9 	"strings"
     10 	"time"
     11 )
     12 
     13 // EventStreamSigner is an AWS EventStream protocol signer.
     14 type EventStreamSigner interface {
     15 	GetSignature(ctx context.Context, headers, payload []byte, signingTime time.Time, optFns ...func(*StreamSignerOptions)) ([]byte, error)
     16 }
     17 
     18 // StreamSignerOptions is the configuration options for StreamSigner.
     19 type StreamSignerOptions struct{}
     20 
     21 // StreamSigner implements Signature Version 4 (SigV4) signing of event stream encoded payloads.
     22 type StreamSigner struct {
     23 	options StreamSignerOptions
     24 
     25 	credentials aws.Credentials
     26 	service     string
     27 	region      string
     28 
     29 	prevSignature []byte
     30 
     31 	signingKeyDeriver *v4Internal.SigningKeyDeriver
     32 }
     33 
     34 // NewStreamSigner returns a new AWS EventStream protocol signer.
     35 func NewStreamSigner(credentials aws.Credentials, service, region string, seedSignature []byte, optFns ...func(*StreamSignerOptions)) *StreamSigner {
     36 	o := StreamSignerOptions{}
     37 
     38 	for _, fn := range optFns {
     39 		fn(&o)
     40 	}
     41 
     42 	return &StreamSigner{
     43 		options:           o,
     44 		credentials:       credentials,
     45 		service:           service,
     46 		region:            region,
     47 		signingKeyDeriver: v4Internal.NewSigningKeyDeriver(),
     48 		prevSignature:     seedSignature,
     49 	}
     50 }
     51 
     52 // GetSignature signs the provided header and payload bytes.
     53 func (s *StreamSigner) GetSignature(ctx context.Context, headers, payload []byte, signingTime time.Time, optFns ...func(*StreamSignerOptions)) ([]byte, error) {
     54 	options := s.options
     55 
     56 	for _, fn := range optFns {
     57 		fn(&options)
     58 	}
     59 
     60 	prevSignature := s.prevSignature
     61 
     62 	st := v4Internal.NewSigningTime(signingTime)
     63 
     64 	sigKey := s.signingKeyDeriver.DeriveKey(s.credentials, s.service, s.region, st)
     65 
     66 	scope := v4Internal.BuildCredentialScope(st, s.region, s.service)
     67 
     68 	stringToSign := s.buildEventStreamStringToSign(headers, payload, prevSignature, scope, &st)
     69 
     70 	signature := v4Internal.HMACSHA256(sigKey, []byte(stringToSign))
     71 	s.prevSignature = signature
     72 
     73 	return signature, nil
     74 }
     75 
     76 func (s *StreamSigner) buildEventStreamStringToSign(headers, payload, previousSignature []byte, credentialScope string, signingTime *v4Internal.SigningTime) string {
     77 	hash := sha256.New()
     78 	return strings.Join([]string{
     79 		"AWS4-HMAC-SHA256-PAYLOAD",
     80 		signingTime.TimeFormat(),
     81 		credentialScope,
     82 		hex.EncodeToString(previousSignature),
     83 		hex.EncodeToString(makeHash(hash, headers)),
     84 		hex.EncodeToString(makeHash(hash, payload)),
     85 	}, "\n")
     86 }