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 <jbd@google.com>
Run-TryBot: David Symonds <dsymonds@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
This commit is contained in:
David Symonds 2015-11-06 11:23:41 +11:00
parent 038cb4adce
commit e347d2238c
1 changed files with 18 additions and 7 deletions

View File

@ -119,8 +119,11 @@ func Decode(payload string) (*ClaimSet, error) {
return c, err return c, err
} }
// Encode encodes a signed JWS with provided header and claim set. // Signer returns a signature for the given data.
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) { 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() head, err := header.encode()
if err != nil { if err != nil {
return "", err return "", err
@ -130,14 +133,22 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err
return "", err return "", err
} }
ss := fmt.Sprintf("%s.%s", head, cs) ss := fmt.Sprintf("%s.%s", head, cs)
h := sha256.New() sig, err := sg([]byte(ss))
h.Write([]byte(ss))
b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
if err != nil { if err != nil {
return "", err return "", err
} }
sig := base64Encode(b) return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil
return fmt.Sprintf("%s.%s", ss, 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 // base64Encode returns and Base64url encoded version of the input string with any