64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
|
package v4
|
||
|
|
||
|
import (
|
||
|
"encoding/hex"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||
|
)
|
||
|
|
||
|
type credentialValueProvider interface {
|
||
|
Get() (credentials.Value, error)
|
||
|
}
|
||
|
|
||
|
// StreamSigner implements signing of event stream encoded payloads.
|
||
|
type StreamSigner struct {
|
||
|
region string
|
||
|
service string
|
||
|
|
||
|
credentials credentialValueProvider
|
||
|
|
||
|
prevSig []byte
|
||
|
}
|
||
|
|
||
|
// NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages.
|
||
|
func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner {
|
||
|
return &StreamSigner{
|
||
|
region: region,
|
||
|
service: service,
|
||
|
credentials: credentials,
|
||
|
prevSig: seedSignature,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GetSignature takes an event stream encoded headers and payload and returns a signature.
|
||
|
func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) {
|
||
|
credValue, err := s.credentials.Get()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date)
|
||
|
|
||
|
keyPath := buildSigningScope(s.region, s.service, date)
|
||
|
|
||
|
stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date)
|
||
|
|
||
|
signature := hmacSHA256(sigKey, []byte(stringToSign))
|
||
|
s.prevSig = signature
|
||
|
|
||
|
return signature, nil
|
||
|
}
|
||
|
|
||
|
func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string {
|
||
|
return strings.Join([]string{
|
||
|
"AWS4-HMAC-SHA256-PAYLOAD",
|
||
|
formatTime(date),
|
||
|
scope,
|
||
|
hex.EncodeToString(prevSig),
|
||
|
hex.EncodeToString(hashSHA256(headers)),
|
||
|
hex.EncodeToString(hashSHA256(payload)),
|
||
|
}, "\n")
|
||
|
}
|