1package v4 2 3import ( 4 "encoding/hex" 5 "strings" 6 "time" 7 8 "github.com/aws/aws-sdk-go/aws/credentials" 9) 10 11type credentialValueProvider interface { 12 Get() (credentials.Value, error) 13} 14 15// StreamSigner implements signing of event stream encoded payloads 16type StreamSigner struct { 17 region string 18 service string 19 20 credentials credentialValueProvider 21 22 prevSig []byte 23} 24 25// NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages 26func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner { 27 return &StreamSigner{ 28 region: region, 29 service: service, 30 credentials: credentials, 31 prevSig: seedSignature, 32 } 33} 34 35// GetSignature takes an event stream encoded headers and payload and returns a signature 36func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) { 37 credValue, err := s.credentials.Get() 38 if err != nil { 39 return nil, err 40 } 41 42 sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date) 43 44 keyPath := buildSigningScope(s.region, s.service, date) 45 46 stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date) 47 48 signature := hmacSHA256(sigKey, []byte(stringToSign)) 49 s.prevSig = signature 50 51 return signature, nil 52} 53 54func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string { 55 return strings.Join([]string{ 56 "AWS4-HMAC-SHA256-PAYLOAD", 57 formatTime(date), 58 scope, 59 hex.EncodeToString(prevSig), 60 hex.EncodeToString(hashSHA256(headers)), 61 hex.EncodeToString(hashSHA256(payload)), 62 }, "\n") 63} 64