Skip to content

Commit

Permalink
Merge branch 'master' of github.com:igor-pavlenko/httpsignatures-go
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-pavlenko committed Nov 4, 2020
2 parents 6fc8733 + 8a2775b commit c332876
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 106 deletions.
68 changes: 34 additions & 34 deletions httpsignatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,46 +133,46 @@ func (hs *HTTPSignatures) Verify(r *http.Request) error {
}

// Verify expires (must be lower than now() +/- time gap)
if hs.inHeaders(expires, sh.headers) {
if hs.inHeaders(expires, sh.Headers) {
now := time.Now()
max := sh.expires.Add(hs.defaultTimeGap)
max := sh.Expires.Add(hs.defaultTimeGap)
if now.After(max) {
return &ErrHS{"signature expired", nil}
}
}

// Verify created (can not be in future)
if hs.inHeaders(created, sh.headers) {
if hs.inHeaders(created, sh.Headers) {
now := time.Now()
max := now.Add(hs.defaultTimeGap)
if sh.created.After(max) {
if sh.Created.After(max) {
return &ErrHS{"signature in future", nil}
}
}

// Verify digest
if hs.defaultVerifyDigest {
err := hs.verifyDigest(sh.headers, r)
err := hs.verifyDigest(sh.Headers, r)
if err != nil {
return err
}
}

// Check keyID & algorithm
secret, err := hs.ss.Get(sh.keyID)
secret, err := hs.ss.Get(sh.KeyID)
if err != nil {
return &ErrHS{fmt.Sprintf("keyID '%s' not found", sh.keyID), err}
return &ErrHS{fmt.Sprintf("keyID '%s' not found", sh.KeyID), err}
}
if !strings.EqualFold(secret.Algorithm, sh.algorithm) {
if !strings.EqualFold(secret.Algorithm, sh.Algorithm) {
return &ErrHS{
fmt.Sprintf("wrong algorithm '%s' for keyId '%s'", sh.algorithm, sh.keyID),
fmt.Sprintf("wrong algorithm '%s' for keyId '%s'", sh.Algorithm, sh.KeyID),
nil,
}
}
alg, ok := hs.alg[strings.ToUpper(secret.Algorithm)]
if !ok {
return &ErrHS{
fmt.Sprintf("algorithm '%s' not supported", sh.algorithm),
fmt.Sprintf("algorithm '%s' not supported", sh.Algorithm),
nil,
}
}
Expand All @@ -187,7 +187,7 @@ func (hs *HTTPSignatures) Verify(r *http.Request) error {
}

// Verify signature
signatureDecoded, err := base64.StdEncoding.DecodeString(sh.signature)
signatureDecoded, err := base64.StdEncoding.DecodeString(sh.Signature)
if err != nil {
return &ErrHS{
"error decode signature from base64",
Expand Down Expand Up @@ -221,21 +221,21 @@ func (hs *HTTPSignatures) Sign(secretKeyID string, r *http.Request) error {

// Build signature string
headers := Headers{
keyID: secret.KeyID,
algorithm: secret.Algorithm,
created: time.Now(),
expires: time.Time{},
headers: hs.defaultHeaders,
KeyID: secret.KeyID,
Algorithm: secret.Algorithm,
Created: time.Now(),
Expires: time.Time{},
Headers: hs.defaultHeaders,
}
// Expires
if hs.defaultExpiresSec != 0 {
headers.expires = time.Now().Add(time.Second * time.Duration(hs.defaultExpiresSec))
headers.Expires = time.Now().Add(time.Second * time.Duration(hs.defaultExpiresSec))
}
// Create digest & set it to request header
// Proceed only if digest header not set
digest := r.Header.Get(digestHeader)
if len(digest) == 0 {
d, err := hs.createDigest(headers.headers, r)
d, err := hs.createDigest(headers.Headers, r)
if err != nil {
return err
}
Expand All @@ -252,7 +252,7 @@ func (hs *HTTPSignatures) Sign(secretKeyID string, r *http.Request) error {
if err != nil {
return &ErrHS{"error creating signature", err}
}
headers.signature = base64.StdEncoding.EncodeToString(s)
headers.Signature = base64.StdEncoding.EncodeToString(s)

// Build Signature header
sigHeader := hs.buildSignatureHeader(headers)
Expand All @@ -262,29 +262,29 @@ func (hs *HTTPSignatures) Sign(secretKeyID string, r *http.Request) error {
}

func (hs *HTTPSignatures) buildSignatureString(sh Headers, r *http.Request) ([]byte, error) {
j := len(sh.headers)
j := len(sh.Headers)
headers := r.Header.Clone()
var b bytes.Buffer
for i, h := range sh.headers {
for i, h := range sh.Headers {
switch h {
case requestTarget:
b.WriteString(fmt.Sprintf("%s: %s %s", requestTarget, strings.ToLower(r.Method), r.URL.RequestURI()))
case created:
if sh.created == time.Unix(0, 0) {
if sh.Created == time.Unix(0, 0) {
return nil, &ErrHS{
fmt.Sprintf("param '%s', required in signature, not found", created),
nil,
}
}
b.WriteString(fmt.Sprintf("%s: %d", created, sh.created.Unix()))
b.WriteString(fmt.Sprintf("%s: %d", created, sh.Created.Unix()))
case expires:
if sh.expires == time.Unix(0, 0) {
if sh.Expires == time.Unix(0, 0) {
return nil, &ErrHS{
fmt.Sprintf("param '%s', required in signature, not found", expires),
nil,
}
}
b.WriteString(fmt.Sprintf("%s: %d", expires, sh.expires.Unix()))
b.WriteString(fmt.Sprintf("%s: %d", expires, sh.Expires.Unix()))
default:
reqHeader, ok := headers[textproto.CanonicalMIMEHeaderKey(h)]
if !ok {
Expand All @@ -304,18 +304,18 @@ func (hs *HTTPSignatures) buildSignatureString(sh Headers, r *http.Request) ([]b
}

func (hs *HTTPSignatures) buildSignatureHeader(h Headers) string {
header := fmt.Sprintf(`%s="%s",`, paramKeyID, h.keyID)
header += fmt.Sprintf(`%s="%s",`, paramAlgorithm, h.algorithm)
if hs.inHeaders(fmt.Sprintf("(%s)", paramCreated), h.headers) {
header += fmt.Sprintf(`%s=%d,`, paramCreated, h.created.Unix())
header := fmt.Sprintf(`%s="%s",`, paramKeyID, h.KeyID)
header += fmt.Sprintf(`%s="%s",`, paramAlgorithm, h.Algorithm)
if hs.inHeaders(fmt.Sprintf("(%s)", paramCreated), h.Headers) {
header += fmt.Sprintf(`%s=%d,`, paramCreated, h.Created.Unix())
}
if hs.inHeaders(fmt.Sprintf("(%s)", paramExpires), h.headers) && hs.defaultExpiresSec > 0 {
header += fmt.Sprintf(`%s=%d,`, paramExpires, h.expires.Unix())
if hs.inHeaders(fmt.Sprintf("(%s)", paramExpires), h.Headers) && hs.defaultExpiresSec > 0 {
header += fmt.Sprintf(`%s=%d,`, paramExpires, h.Expires.Unix())
}
if len(h.headers) > 0 {
header += fmt.Sprintf(`%s="%s",`, paramHeaders, strings.Join(h.headers, " "))
if len(h.Headers) > 0 {
header += fmt.Sprintf(`%s="%s",`, paramHeaders, strings.Join(h.Headers, " "))
}
header += fmt.Sprintf(`%s="%s"`, paramSignature, h.signature)
header += fmt.Sprintf(`%s="%s"`, paramSignature, h.Signature)

return header
}
Expand Down
52 changes: 26 additions & 26 deletions httpsignatures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ func TestHSBuildSignatureString(t *testing.T) {
name: "Valid signature string",
args: args{
ph: Headers{
algorithm: "md5",
headers: []string{
Algorithm: "md5",
Headers: []string{
"(request-target)",
"(created)",
"(expires)",
Expand All @@ -517,8 +517,8 @@ func TestHSBuildSignatureString(t *testing.T) {
"digest",
"content-length",
},
created: time.Unix(1402170695, 0),
expires: time.Unix(1402170995, 0),
Created: time.Unix(1402170695, 0),
Expires: time.Unix(1402170995, 0),
},
r: (func() *http.Request {
r, _ := http.NewRequest(http.MethodPost, testHostExamplePath, strings.NewReader(testBodyExample))
Expand All @@ -544,11 +544,11 @@ func TestHSBuildSignatureString(t *testing.T) {
name: "Has created header with 0 value",
args: args{
ph: Headers{
algorithm: "md5",
headers: []string{
Algorithm: "md5",
Headers: []string{
"(created)",
},
created: time.Unix(0, 0),
Created: time.Unix(0, 0),
},
r: (func() *http.Request {
r, _ := http.NewRequest(http.MethodPost, testHostExamplePath, strings.NewReader(testBodyExample))
Expand All @@ -563,11 +563,11 @@ func TestHSBuildSignatureString(t *testing.T) {
name: "Has expires header with 0 value",
args: args{
ph: Headers{
algorithm: "sha-256",
headers: []string{
Algorithm: "sha-256",
Headers: []string{
"(expires)",
},
expires: time.Unix(0, 0),
Expires: time.Unix(0, 0),
},
r: (func() *http.Request {
r, _ := http.NewRequest(http.MethodPost, testHostExamplePath, strings.NewReader(testBodyExample))
Expand All @@ -582,8 +582,8 @@ func TestHSBuildSignatureString(t *testing.T) {
name: "Header with 0 length",
args: args{
ph: Headers{
algorithm: "md5",
headers: []string{
Algorithm: "md5",
Headers: []string{
"host",
"digest",
},
Expand All @@ -605,8 +605,8 @@ func TestHSBuildSignatureString(t *testing.T) {
name: "Header not found",
args: args{
ph: Headers{
algorithm: "md5",
headers: []string{
Algorithm: "md5",
Headers: []string{
"host",
"digest",
},
Expand Down Expand Up @@ -751,24 +751,24 @@ func TestHSBuildSignatureHeader(t *testing.T) {
{
name: "Signature string OK",
arg: Headers{
keyID: "key1",
algorithm: "alg",
created: time.Unix(1591130723, 0),
expires: time.Unix(1591130723, 0),
headers: []string{"digest", "host"},
signature: "signature",
KeyID: "key1",
Algorithm: "alg",
Created: time.Unix(1591130723, 0),
Expires: time.Unix(1591130723, 0),
Headers: []string{"digest", "host"},
Signature: "signature",
},
want: `keyId="key1",algorithm="alg",headers="digest host",signature="signature"`,
},
{
name: "Signature string with created & expires OK",
arg: Headers{
keyID: "key2",
algorithm: "alg",
created: time.Unix(1591130723, 0),
expires: time.Unix(1591130723, 0),
headers: []string{"(created)", "(expires)"},
signature: "signature",
KeyID: "key2",
Algorithm: "alg",
Created: time.Unix(1591130723, 0),
Expires: time.Unix(1591130723, 0),
Headers: []string{"(created)", "(expires)"},
Signature: "signature",
},
want: `keyId="key2",algorithm="alg",created=1591130723,expires=1591130723,headers="(created) (expires)",` +
`signature="signature"`,
Expand Down
28 changes: 14 additions & 14 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ const (

// Headers Signature headers & params
type Headers struct {
keyID string // REQUIRED
algorithm string // RECOMMENDED
created time.Time // RECOMMENDED
expires time.Time // OPTIONAL (Not implemented: "Subsecond precision is allowed using decimal notation.")
headers []string // OPTIONAL
signature string // REQUIRED
KeyID string // REQUIRED
Algorithm string // RECOMMENDED
Created time.Time // RECOMMENDED
Expires time.Time // OPTIONAL (Not implemented: "Subsecond precision is allowed using decimal notation.")
Headers []string // OPTIONAL
Signature string // REQUIRED
}

// DigestHeader Digest header parsed into params (alg & digest)
Expand Down Expand Up @@ -355,21 +355,21 @@ func (p *Parser) setKeyValue() *ErrParser {
p.params[k] = true

if k == "keyId" {
p.headers.keyID = string(p.value)
p.headers.KeyID = string(p.value)
} else if k == "algorithm" {
p.headers.algorithm = string(p.value)
p.headers.Algorithm = string(p.value)
} else if k == "headers" {
p.headers.headers = strings.Fields(string(p.value))
p.headers.Headers = strings.Fields(string(p.value))
} else if k == "signature" {
p.headers.signature = string(p.value)
p.headers.Signature = string(p.value)
} else if k == "created" {
var err error
if p.headers.created, err = p.intToTime(p.value); err != nil {
if p.headers.Created, err = p.intToTime(p.value); err != nil {
return &ErrParser{"wrong 'created' param value", err}
}
} else if k == "expires" {
var err error
if p.headers.expires, err = p.intToTime(p.value); err != nil {
if p.headers.Expires, err = p.intToTime(p.value); err != nil {
return &ErrParser{"wrong 'expires' param value", err}
}
}
Expand Down Expand Up @@ -410,14 +410,14 @@ func (p *Parser) setDigest() *ErrParser {

// VerifySignatureFields verify required fields
func (p *Parser) VerifySignatureFields() *ErrParser {
if p.headers.keyID == "" {
if p.headers.KeyID == "" {
return &ErrParser{
"keyId is not set in header",
nil,
}
}

if p.headers.signature == "" {
if p.headers.Signature == "" {
return &ErrParser{
"signature is not set in header",
nil,
Expand Down
Loading

0 comments on commit c332876

Please sign in to comment.