feat: added multiple sig support

This commit is contained in:
Wyatt Johnson 2019-11-15 15:38:27 -07:00 committed by Cameron Moore
parent 569921cd72
commit 11e0031a9f
2 changed files with 68 additions and 11 deletions

View file

@ -17,6 +17,7 @@ import (
"math"
"net"
"net/textproto"
"net/url"
"os"
"reflect"
"regexp"
@ -48,13 +49,19 @@ const (
// SignatureError describes an invalid payload signature passed to Hook.
type SignatureError struct {
Signature string
Signature string
Signatures []string
}
func (e *SignatureError) Error() string {
if e == nil {
return "<nil>"
}
if e.Signatures != nil {
return fmt.Sprintf("invalid payload signatures %s", e.Signatures)
}
return fmt.Sprintf("invalid payload signature %s", e.Signature)
}
@ -94,13 +101,47 @@ func (e *ParseError) Error() string {
return e.Err.Error()
}
// ExtractCommaSeperatedValues will extract the values matching the key.
func ExtractCommaSeperatedValues(source, key string) []string {
parts := strings.Split(source, ",")
values := make([]string, 0)
for _, part := range parts {
m, err := url.ParseQuery(part)
if err != nil {
continue
}
// Try to get the value.
value := m.Get(key)
if value != "" {
values = append(values, value)
}
}
return values
}
func ExtractSignatures(signature, key string) []string {
// If there are multiple possible matches, let the comma seperated extractor
// do it's work.
if strings.Contains(signature, ",") {
return ExtractCommaSeperatedValues(signature, key)
}
// There were no commas, so just trim the prefix (if it even exists) and
// pass it back.
return []string{
strings.TrimPrefix(signature, key+"="),
}
}
// CheckPayloadSignature calculates and verifies SHA1 signature of the given payload
func CheckPayloadSignature(payload []byte, secret string, signature string) (string, error) {
if secret == "" {
return "", errors.New("signature validation secret can not be empty")
}
signature = strings.TrimPrefix(signature, "sha1=")
signatures := ExtractSignatures(signature, "sha1")
mac := hmac.New(sha1.New, []byte(secret))
_, err := mac.Write(payload)
@ -109,10 +150,15 @@ func CheckPayloadSignature(payload []byte, secret string, signature string) (str
}
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
return expectedMAC, &SignatureError{signature}
for _, signature := range signatures {
if hmac.Equal([]byte(signature), []byte(expectedMAC)) {
return expectedMAC, err
}
}
return expectedMAC, &SignatureError{
Signatures: signatures,
}
return expectedMAC, err
}
// CheckPayloadSignature256 calculates and verifies SHA256 signature of the given payload
@ -121,7 +167,7 @@ func CheckPayloadSignature256(payload []byte, secret string, signature string) (
return "", errors.New("signature validation secret can not be empty")
}
signature = strings.TrimPrefix(signature, "sha256=")
signatures := ExtractSignatures(signature, "sha256")
mac := hmac.New(sha256.New, []byte(secret))
_, err := mac.Write(payload)
@ -151,10 +197,15 @@ func CheckPayloadSignature512(payload []byte, secret string, signature string) (
}
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
return expectedMAC, &SignatureError{signature}
for _, signature := range signatures {
if hmac.Equal([]byte(signature), []byte(expectedMAC)) {
return expectedMAC, err
}
}
return expectedMAC, &SignatureError{
Signatures: signatures,
}
return expectedMAC, err
}
func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey string, checkDate bool) (bool, error) {
@ -177,7 +228,7 @@ func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey
expectedSignature := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(providedSignature), []byte(expectedSignature)) {
return false, &SignatureError{providedSignature}
return false, &SignatureError{Signature: providedSignature}
}
if !checkDate {
@ -192,7 +243,7 @@ func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey
delta := math.Abs(now.Sub(date).Seconds())
if delta > 300 {
return false, &SignatureError{"outdated"}
return false, &SignatureError{Signature: "outdated"}
}
return true, nil
}

View file

@ -48,8 +48,11 @@ var checkPayloadSignatureTests = []struct {
}{
{[]byte(`{"a": "z"}`), "secret", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
{[]byte(`{"a": "z"}`), "secret", "sha1=b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
{[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e,sha1=b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
// failures
{[]byte(`{"a": "z"}`), "secret", "XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
{[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
{[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e,sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
{[]byte(`{"a": "z"}`), "secreX", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "900225703e9342328db7307692736e2f7cc7b36e", false},
{[]byte(`{"a": "z"}`), "", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "", false},
}
@ -76,8 +79,11 @@ var checkPayloadSignature256Tests = []struct {
}{
{[]byte(`{"a": "z"}`), "secret", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
{[]byte(`{"a": "z"}`), "secret", "sha256=f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
{[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89,sha256=f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
// failures
{[]byte(`{"a": "z"}`), "secret", "XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
{[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
{[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89,sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
{[]byte(`{"a": "z"}`), "", "XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "", false},
}