Files
ddns-updater-qdm12-3/internal/provider/providers/route53/signer.go
2024-10-20 13:12:33 +00:00

94 lines
2.5 KiB
Go

package route53
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"time"
)
const (
route53Domain = "route53.amazonaws.com"
dateTimeFormat = "20060102T150405Z"
dateFormat = "20060102"
)
// signer implements the signature v4 header based to upsert route53 domains
// https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
type signer struct {
accessKey string
secretkey string
region string
service string
signatureVersion string
}
func (s *signer) sign(method, urlPath string, payload []byte, date time.Time) (
headerValue string,
) {
credentialScope := fmt.Sprintf("%s/%s/%s/%s", date.Format(dateFormat),
s.region, s.service, s.signatureVersion)
credential := fmt.Sprintf("%s/%s", s.accessKey, credentialScope)
const signedHeaders = "content-type;host"
canonicalRequest := buildCanonicalRequest(method, urlPath, signedHeaders, payload)
stringToSign := buildStringToSign(date, canonicalRequest, credentialScope)
signingKey := s.buildPrivateKey(date)
signature := hmacSha256Sum([]byte(signingKey), []byte(stringToSign))
signatureString := hex.EncodeToString(signature)
return fmt.Sprintf("AWS4-HMAC-SHA256 Credential=%s,SignedHeaders=%s,Signature=%s",
credential, signedHeaders, signatureString)
}
func buildCanonicalRequest(method, path, headers string, payload []byte) (
canonicalRequest string,
) {
canonicalHeaders := "content-type:application/xml\nhost:" + route53Domain + "\n"
const canonicalQuery = "" // no query arg used
payloadHashDigest := hex.EncodeToString(sha256Sum(payload))
canonicalRequest = strings.Join([]string{
strings.ToUpper(method),
path,
canonicalQuery,
canonicalHeaders,
headers,
payloadHashDigest,
}, "\n")
return canonicalRequest
}
func buildStringToSign(date time.Time,
canonicalRequest, credentialScope string,
) string {
return "AWS4-HMAC-SHA256\n" +
date.Format(dateTimeFormat) + "\n" +
credentialScope + "\n" +
hex.EncodeToString(sha256Sum([]byte(canonicalRequest)))
}
func (s *signer) buildPrivateKey(date time.Time) string {
signingKey := []byte("AWS4" + s.secretkey)
for _, value := range [][]byte{
[]byte(date.Format(dateFormat)),
[]byte(s.region),
[]byte(s.service),
[]byte(s.signatureVersion),
} {
signingKey = hmacSha256Sum(signingKey, value)
}
return string(signingKey)
}
func sha256Sum(d []byte) []byte {
hasher := sha256.New()
hasher.Write(d)
return hasher.Sum(nil)
}
func hmacSha256Sum(key, value []byte) []byte {
hasher := hmac.New(sha256.New, key)
hasher.Write(value)
return hasher.Sum(nil)
}