From e347d2238c75fcce9f32e1dff7708f86e4fe2228 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Fri, 6 Nov 2015 11:23:41 +1100 Subject: [PATCH] jws: add EncodeWithSigner function. This permits controlling the mechanism for signing the token; for instance, one can use EncodeWithSigner in an App Engine app to use the App Identity API to perform the signing (you don't have direct access to the private key there). An alternate would be to replace Encode with EncodeWithSigner, and add a little wrapper type that turns a *rsa.PrivateKey into a Signer. That's probably what I'd do if this were being written from scratch, but I wasn't keen on breaking existing code. Change-Id: Id48f5dfa15c179832e613268d4a4098b96648f9a Reviewed-on: https://go-review.googlesource.com/16711 Reviewed-by: Burcu Dogan Run-TryBot: David Symonds Reviewed-by: Andrew Gerrand --- jws/jws.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/jws/jws.go b/jws/jws.go index 6b86a3e..e300001 100644 --- a/jws/jws.go +++ b/jws/jws.go @@ -119,8 +119,11 @@ func Decode(payload string) (*ClaimSet, error) { return c, err } -// Encode encodes a signed JWS with provided header and claim set. -func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) { +// Signer returns a signature for the given data. +type Signer func(data []byte) (sig []byte, err error) + +// EncodeWithSigner encodes a header and claim set with the provided signer. +func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) { head, err := header.encode() if err != nil { return "", err @@ -130,14 +133,22 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err return "", err } ss := fmt.Sprintf("%s.%s", head, cs) - h := sha256.New() - h.Write([]byte(ss)) - b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil)) + sig, err := sg([]byte(ss)) if err != nil { return "", err } - sig := base64Encode(b) - return fmt.Sprintf("%s.%s", ss, sig), nil + return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil +} + +// Encode encodes a signed JWS with provided header and claim set. +// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key. +func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) { + sg := func(data []byte) (sig []byte, err error) { + h := sha256.New() + h.Write([]byte(data)) + return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil)) + } + return EncodeWithSigner(header, c, sg) } // base64Encode returns and Base64url encoded version of the input string with any