forked from Mirrors/oauth2
jws: add RS256 Verification for JWS
Provides helper method for verifying a signed JWT against a provided public key. Change-Id: I498ecfce07862c372fd5f81c1fcdc09692ed0f5c Reviewed-on: https://go-review.googlesource.com/21762 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
f6a14f0423
commit
14446d3f8b
21
jws/jws.go
21
jws/jws.go
|
@ -145,12 +145,31 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
|
||||||
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
|
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
|
||||||
sg := func(data []byte) (sig []byte, err error) {
|
sg := func(data []byte) (sig []byte, err error) {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(data))
|
h.Write(data)
|
||||||
return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
||||||
}
|
}
|
||||||
return EncodeWithSigner(header, c, sg)
|
return EncodeWithSigner(header, c, sg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify tests whether the provided JWT token's signature was produced by the private key
|
||||||
|
// associated with the supplied public key.
|
||||||
|
func Verify(token string, key *rsa.PublicKey) error {
|
||||||
|
parts := strings.Split(token, ".")
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return errors.New("jws: invalid token received, token must have 3 parts")
|
||||||
|
}
|
||||||
|
|
||||||
|
signedContent := parts[0] + "." + parts[1]
|
||||||
|
signatureString, err := base64Decode(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(signedContent))
|
||||||
|
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
|
||||||
|
}
|
||||||
|
|
||||||
// base64Encode returns and Base64url encoded version of the input string with any
|
// base64Encode returns and Base64url encoded version of the input string with any
|
||||||
// trailing "=" stripped.
|
// trailing "=" stripped.
|
||||||
func base64Encode(b []byte) string {
|
func base64Encode(b []byte) string {
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package jws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignAndVerify(t *testing.T) {
|
||||||
|
header := &Header{
|
||||||
|
Algorithm: "RS256",
|
||||||
|
Typ: "JWT",
|
||||||
|
}
|
||||||
|
payload := &ClaimSet{
|
||||||
|
Iss: "http://google.com/",
|
||||||
|
Aud: "",
|
||||||
|
Exp: 3610,
|
||||||
|
Iat: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := Encode(header, payload, privateKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Verify(token, &privateKey.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyFailsOnMalformedClaim(t *testing.T) {
|
||||||
|
err := Verify("abc.def", nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Improperly formed JWT should fail.")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue