Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 68 additions & 3 deletions algorithm.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
package httpsignatures

import (
"crypto"
"crypto/hmac"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"hash"
)

var (
AlgorithmHmacSha256 = &Algorithm{"hmac-sha256", sha256.New}
AlgorithmHmacSha1 = &Algorithm{"hmac-sha1", sha1.New}
AlgorithmHmacSha256 = &Algorithm{"hmac-sha256", sha256.New, hmacSign}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this could use a goimports run over it https://godoc.org/golang.org/x/tools/cmd/goimports

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran goimports and go fmt again.

AlgorithmHmacSha1 = &Algorithm{"hmac-sha1", sha1.New, hmacSign}
AlgorithmRsaSha1 = &Algorithm{"rsa-sha1", sha1.New, rsaSha1Sign}
AlgorithmRsaSha256 = &Algorithm{"rsa-sha256", sha256.New, rsaSha256Sign}

ErrorUnknownAlgorithm = errors.New("Unknown Algorithm")
)

type Algorithm struct {
name string
hash func() hash.Hash
sign func(hashFunc func() hash.Hash, key string, signingString string) ([]byte, error)
}

func algorithmFromString(name string) (*Algorithm, error) {
Expand All @@ -25,7 +35,62 @@ func algorithmFromString(name string) (*Algorithm, error) {
return AlgorithmHmacSha1, nil
case AlgorithmHmacSha256.name:
return AlgorithmHmacSha256, nil
case AlgorithmRsaSha1.name:
return AlgorithmRsaSha1, nil
case AlgorithmRsaSha256.name:
return AlgorithmRsaSha256, nil
}

return nil, ErrorUnknownAlgorithm
}

func hmacSign(hashFunc func() hash.Hash, key string, signingString string) ([]byte, error) {
hash := hmac.New(hashFunc, []byte(key))
hash.Write([]byte(signingString))
return hash.Sum(nil), nil
}

func rsaSha1Sign(hashFunc func() hash.Hash, key string, signingString string) ([]byte, error) {
return rsaSign(hashFunc, key, signingString, crypto.SHA1)
}

func rsaSha256Sign(hashFunc func() hash.Hash, key string, signingString string) ([]byte, error) {
return rsaSign(hashFunc, key, signingString, crypto.SHA256)
}

func rsaSign(hashFunc func() hash.Hash, key string, signingString string, hashType crypto.Hash) ([]byte, error) {
private_key, err := parsePrivateKey([]byte(key[:]))
if err != nil {
return nil, err
}
hash := hashFunc()
hash.Write([]byte(signingString))
d := hash.Sum(nil)
singed_hash, err := rsa.SignPKCS1v15(rand.Reader, private_key, hashType, d)
if err != nil {
return nil, err
}
return singed_hash, nil
}

func parsePrivateKey(pemBytes []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("ssh: no key found")
}
switch block.Type {
case "RSA PRIVATE KEY":
rsa, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsa, nil
case "PRIVATE KEY":
rsaz, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return rsaz.(*rsa.PrivateKey), nil
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
}
11 changes: 5 additions & 6 deletions signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package httpsignatures

import (
"crypto/hmac"
"encoding/base64"
"errors"
"fmt"
Expand Down Expand Up @@ -107,16 +106,16 @@ func (s Signature) String() string {
}

func (s Signature) calculateSignature(key string, r *http.Request) (string, error) {
hash := hmac.New(s.Algorithm.hash, []byte(key))

signingString, err := s.Headers.signingString(r)
if err != nil {
return "", err
}

hash.Write([]byte(signingString))

return base64.StdEncoding.EncodeToString(hash.Sum(nil)), nil
signature, err := s.Algorithm.sign(s.Algorithm.hash, key, signingString)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), nil
}

// Sign this signature using the given key
Expand Down
27 changes: 27 additions & 0 deletions signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,33 @@ const (
TEST_KEY = "SomethingRandom"
TEST_DATE = "Thu, 05 Jan 2012 21:31:40 GMT"
TEST_KEY_ID = "Test"
RSA_TEST_KEY = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAptqthxnWUoN6J/9RhspO9uKmsYUTT150rGyLln/Keq0E4vam
7Pj3B6Xh3reGbyjSz0NQkfLftalRKqNse0TH5TLGMYXz5mtxm+jZkuTqE73wgRDF
3jW0gCoFGy0qKXckunvKOpwkNVDuMZZ1DLgLbUGi1XTVpH8r4hHWsVfrupzJnfo4
ptAGEPlH9VRoYZd5sNg3OIxQaUYtNZr3dpywzwXwPF1VvWCw1K9cENZhkFS5CW/l
PuZXCFOPDgO1hTJMLWE+aZ7TElYOH/i+1/4igBdPn0G0awBR+OoGF0wN4JpUXDSQ
D9F6nyFRDKaxx5aFYdme+QrzQTyYNPQ18hjf2wIDAQABAoIBABcw68+MWsqrNY5b
oWQ/uEv+YrbnzTBJ66OPjrNDXcxBQh2dtMPZMtSgTM2c6pWGsg5Wx9sRS+C/AOYR
QuG7RKFptjxp5uWO54KJEbymDpbh3ozB3Q6unkD2FjGZzHNo+PTmgcw1qZ6zeffw
dqJm7keoSM6sZ4lul5XbbuDFXKFaMMbz1VRVVdFnAvmKQZfwd6/noeKiuyMyG3g8
v7VikhsEA3pX7uOVDs2vbj5Pq5lDYZ22k0FD0BS6uPUyzrhDyn+nF2I2GWS8PePX
xRsrw05BgGLi5mcI4XPpxLY53T4yc1RYBKvmtGJsZ26/QeOo/ER7ogd8hV/EwjuM
S30PNbECgYEA/kQklql7ri7+qG6HZ07avD2DTQqC9LIOXc6WsoBIRV13geKL/H9a
uXSrxlLbkWYqt8yd2zzVvo+0mbm+Nixe2huPmawbQjsQoLA0hSC7+g8djboDz91Q
SHsHTDYzNUw6SDqRsypQpUJIOQvvwxodcPlW8RaHW4JAafXPMygkTjkCgYEAp/3x
9ClD+4MTinYLVdRfY4j9r4TjkI2sXf4nfD06fnQcSVsZWD6AqGjqmjfJA+f6w+lu
KHo1NJonlLzac4qOScGCTgCrSbbSPUq8IgaZk4ufqnIek6TH/wPEaY7ZLVb59Wam
Z0+yrpqDqVMf2uUJyiTlFdajfqtHx9Oo5vvnnrMCgYAqd7Msvs37f7nk4+EVriP2
gMenXHQW7o5buJ+O3MI1Y7EMLox29cZvZz8xdrFZjZjg7foHnheNJm9hpZZRcgO9
phDL9+TtoPPcAtIi0h7TWybyfvkYBLzd/j5vyjWvVzX8zlt7czvY/kMV1BqNmZUF
Q3/z8HFXJWAg0n9y6ed2cQKBgQCROs/+heI4wIOXMx/vjo78jMTMBXV6VZBLHdpi
5Mf55EVEAZaynC476Z/PvSRx1Q4ManSKV8RBend3daDhPEpwZvNQnfF2469zv3VP
cSc5z/4zqz7V4yHnTAl0PENyl/u19I0tSVAu9HOYYb1rTpCdCjJmI83qRwbiMRCW
x/XgUwKBgBd+kQkrjhhn/vbhG1EtHgAgszyuMCl+nXlvWGrIP24nSfDxH8UBjhhg
LvbPDIsyREqu3KgddzwdUgCu1PX7adl3mEJXfg62QhqU707+eo6OAGkyUJWDofyi
46RZixuecH3thF1BnNNdYi0QI0UTLkZgpKWGE9mXTp4xxzHg0sfs
-----END RSA PRIVATE KEY-----`
)

func TestCreateSignatureFromAuthorizationHeader(t *testing.T) {
Expand Down
10 changes: 9 additions & 1 deletion signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ var (
// DefaultSha256Signer will sign requests with the url and date using the SHA256 algorithm.
// Users are encouraged to create their own signer with the headers they require.
DefaultSha256Signer = NewSigner(AlgorithmHmacSha256, RequestTarget, "date")

// DefaultSha1Signer will sign requests with the url and date using the SHA1 algorithm.
// Users are encouraged to create their own signer with the headers they require.
DefaultRsaSha1Signer = NewSigner(AlgorithmRsaSha1, RequestTarget, "date")

// DefaultRsaSha256Signer will sign requests with the url and date using the SHA256 algorithm.
// Users are encouraged to create their own signer with the headers they require.
DefaultRsaSha256Signer = NewSigner(AlgorithmRsaSha256, RequestTarget, "date")
)

func NewSigner(algorithm *Algorithm, headers ...string) *Signer {
Expand Down Expand Up @@ -61,7 +69,7 @@ func (s Signer) AuthRequest(id, key string, r *http.Request) error {

func (s Signer) buildSignature(id, key string, r *http.Request) (*Signature, error) {
if r.Header.Get("date") == "" {
r.Header.Set("date", time.Now().Format(time.RFC1123))
r.Header.Set("date", time.Now().UTC().Format(time.RFC1123))
}

sig := &Signature{
Expand Down
50 changes: 48 additions & 2 deletions signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestSignSha1(t *testing.T) {
func TestSignHmacSha1(t *testing.T) {
r := &http.Request{
Header: http.Header{
"Date": []string{"Thu, 05 Jan 2012 21:31:40 GMT"},
Expand All @@ -30,7 +30,7 @@ func TestSignSha1(t *testing.T) {
)
}

func TestSignSha256(t *testing.T) {
func TestSignHmacSha256(t *testing.T) {
r := &http.Request{
Header: http.Header{
"Date": []string{"Thu, 05 Jan 2012 21:31:40 GMT"},
Expand All @@ -53,6 +53,52 @@ func TestSignSha256(t *testing.T) {
)
}

func TestSignRsaSha1(t *testing.T) {
r := &http.Request{
Header: http.Header{
"Date": []string{"Thu, 05 Jan 2012 21:31:40 GMT"},
},
}

err := DefaultRsaSha1Signer.SignRequest(TEST_KEY_ID, RSA_TEST_KEY, r)
assert.Nil(t, err)

s, err := FromRequest(r)
assert.Nil(t, err)

assert.Equal(t, TEST_KEY_ID, s.KeyID)
assert.Equal(t, DefaultRsaSha1Signer.algorithm, s.Algorithm)
assert.Equal(t, DefaultRsaSha1Signer.headers, s.Headers)

assert.Equal(t,
"GvZYUHYZQJ3aYh9FulOG2TQj10ix3wWZ08bXbIxkPXrxDkW55b7yZSbY38HxzLMA9+Nso4xuduQi0eJSDZxadCOs8GHEV/hXyVVX1xUF4Yw8tiWYeu8bRkdWworRP5/L+Xl3g7AFwfKPRWWe6MlY7Vqi8oxt2q2rd3Z+35q4LWDgcvblu0Q5mv8IbtfTP0Z4ncwnQRWRGoe8nVP1v66Thook68eNHszmPRINgTrSDwQbl5jQWvkQv0vznBlj9yxGa3XVO+CoL5r896YrMTrE8JRhj7NHZ1vqOZUIRIK6xgfzjWz0geTUrXS/WIT3hvHLPBMzE8TGaZtlVGycMzD/9g==",
s.Signature,
)
}

func TestSignRsaSha256(t *testing.T) {
r := &http.Request{
Header: http.Header{
"Date": []string{"Thu, 05 Jan 2012 21:31:40 GMT"},
},
}

err := DefaultRsaSha256Signer.SignRequest(TEST_KEY_ID, RSA_TEST_KEY, r)
assert.Nil(t, err)

s, err := FromRequest(r)
assert.Nil(t, err)

assert.Equal(t, TEST_KEY_ID, s.KeyID)
assert.Equal(t, DefaultRsaSha256Signer.algorithm, s.Algorithm)
assert.Equal(t, DefaultRsaSha256Signer.headers, s.Headers)

assert.Equal(t,
"eVyldHIP+4DotKk28VzSXv7q9ZK0HHcTorxHr0aBsyKYElOUMbISOLbaEOJrOsycH7d7NYr3J985ugGOx5mDzamDy3LyjpCK63tZkawqxdEJA2YZE4Ccu1zX8mlutHCMId6/hM8t4tW86La0lxPo6v7Q9mxwkbZn22lVy4qfjOVEiUrSN6phFIWhwi5/3AhhiMtqnD0Lm3iQDB1YKKBCUPmdrC8PTZGTIha3c7NRRnyVxqOUt16EzHDA8QEZ7TmxnIfv3+v5/sC4mCgW8cW/lo3uiBlCF8mtV6MW7H1NIiGcLrHmCA4PaxoSCLHAZRqKlzvA7/TbffG9T8/JOR3hVg==",
s.Signature,
)
}

func TestSignWithMissingDateHeader(t *testing.T) {
r := &http.Request{Header: http.Header{}}

Expand Down