jwt: began basic JWT.
crypto: moved SigningMethod into crypto
diff --git a/jws/ecdsa.go b/crypto/ecdsa.go
similarity index 99%
rename from jws/ecdsa.go
rename to crypto/ecdsa.go
index ce46b47..c518c9d 100644
--- a/jws/ecdsa.go
+++ b/crypto/ecdsa.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto"
diff --git a/jws/ecdsa_test.go b/crypto/ecdsa_test.go
similarity index 99%
rename from jws/ecdsa_test.go
rename to crypto/ecdsa_test.go
index 30a0f60..e557d1a 100644
--- a/jws/ecdsa_test.go
+++ b/crypto/ecdsa_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
// import (
// "crypto/ecdsa"
diff --git a/jws/ecdsa_utils.go b/crypto/ecdsa_utils.go
similarity index 98%
rename from jws/ecdsa_utils.go
rename to crypto/ecdsa_utils.go
index e08a346..4bd75d2 100644
--- a/jws/ecdsa_utils.go
+++ b/crypto/ecdsa_utils.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto/ecdsa"
diff --git a/crypto/errors.go b/crypto/errors.go
new file mode 100644
index 0000000..34fbd25
--- /dev/null
+++ b/crypto/errors.go
@@ -0,0 +1,9 @@
+package crypto
+
+import "errors"
+
+var (
+ // ErrInvalidKey means the key argument passed to SigningMethod.Verify
+ // was not the correct type.
+ ErrInvalidKey = errors.New("key is invalid")
+)
diff --git a/jws/hmac.go b/crypto/hmac.go
similarity index 98%
rename from jws/hmac.go
rename to crypto/hmac.go
index 1d25d72..a9afb1f 100644
--- a/jws/hmac.go
+++ b/crypto/hmac.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto"
diff --git a/jws/hmac_test.go b/crypto/hmac_test.go
similarity index 99%
rename from jws/hmac_test.go
rename to crypto/hmac_test.go
index 86b357e..ff46861 100644
--- a/jws/hmac_test.go
+++ b/crypto/hmac_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
// import (
// "github.com/dgrijalva/jwt-go"
diff --git a/jws/none.go b/crypto/none.go
similarity index 93%
rename from jws/none.go
rename to crypto/none.go
index 5d0a4bf..2b27af4 100644
--- a/jws/none.go
+++ b/crypto/none.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto"
@@ -7,10 +7,7 @@
"io"
)
-func init() {
- crypto.RegisterHash(crypto.Hash(0), h)
- RegisterSigningMethod(Unsecured)
-}
+func init() { crypto.RegisterHash(crypto.Hash(0), h) }
// h is passed to crypto.RegisterHash.
func h() hash.Hash { return &f{Writer: nil} }
diff --git a/jws/rsa.go b/crypto/rsa.go
similarity index 98%
rename from jws/rsa.go
rename to crypto/rsa.go
index 9174478..80596df 100644
--- a/jws/rsa.go
+++ b/crypto/rsa.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto"
diff --git a/jws/rsa_pss.go b/crypto/rsa_pss.go
similarity index 98%
rename from jws/rsa_pss.go
rename to crypto/rsa_pss.go
index 81330b8..3847ae2 100644
--- a/jws/rsa_pss.go
+++ b/crypto/rsa_pss.go
@@ -1,6 +1,6 @@
// +build go1.4
-package jws
+package crypto
import (
"crypto"
diff --git a/jws/rsa_pss_test.go b/crypto/rsa_pss_test.go
similarity index 99%
rename from jws/rsa_pss_test.go
rename to crypto/rsa_pss_test.go
index c45ecf7..c88f949 100644
--- a/jws/rsa_pss_test.go
+++ b/crypto/rsa_pss_test.go
@@ -1,6 +1,6 @@
// +build go1.4
-package jws_test
+package crypto_test
// import (
// "crypto/rsa"
diff --git a/jws/rsa_test.go b/crypto/rsa_test.go
similarity index 99%
rename from jws/rsa_test.go
rename to crypto/rsa_test.go
index 7eb9753..c594605 100644
--- a/jws/rsa_test.go
+++ b/crypto/rsa_test.go
@@ -1,4 +1,4 @@
-package jws_test
+package crypto_test
// import (
// "github.com/dgrijalva/jwt-go"
diff --git a/jws/rsa_utils.go b/crypto/rsa_utils.go
similarity index 98%
rename from jws/rsa_utils.go
rename to crypto/rsa_utils.go
index d8a1a75..350c394 100644
--- a/jws/rsa_utils.go
+++ b/crypto/rsa_utils.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"crypto/rsa"
diff --git a/jws/signature.go b/crypto/signature.go
similarity index 97%
rename from jws/signature.go
rename to crypto/signature.go
index 6fbdc78..37571f9 100644
--- a/jws/signature.go
+++ b/crypto/signature.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"encoding/json"
diff --git a/jws/signature_test.go b/crypto/signature_test.go
similarity index 95%
rename from jws/signature_test.go
rename to crypto/signature_test.go
index 74714be..7601065 100644
--- a/jws/signature_test.go
+++ b/crypto/signature_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
import (
"bytes"
diff --git a/crypto/signing_method.go b/crypto/signing_method.go
new file mode 100644
index 0000000..998ac59
--- /dev/null
+++ b/crypto/signing_method.go
@@ -0,0 +1,24 @@
+package crypto
+
+// SigningMethod is an interface that provides a way to sign JWS tokens.
+import "crypto"
+
+type SigningMethod interface {
+ // Alg describes the signing algorithm, and is used to uniquely
+ // describe the specific crypto.SigningMethod.
+ Alg() string
+
+ // Verify accepts the raw content, the signature, and the key used
+ // to sign the raw content, and returns any errors found while validating
+ // the signature and content.
+ Verify(raw []byte, sig Signature, key interface{}) error
+
+ // Sign returns a Signature for the raw bytes, as well as any errors
+ // that occurred during the signing.
+ Sign(raw []byte, key interface{}) (Signature, error)
+
+ // Used to cause quick panics when a crypto.SigningMethod whose form of hashing
+ // isn't linked in the binary when you register a crypto.SigningMethod.
+ // To spoof this, see "crypto.SigningMethodNone".
+ Hasher() crypto.Hash
+}
diff --git a/crypto/stubs_test.go b/crypto/stubs_test.go
new file mode 100644
index 0000000..96ec4fd
--- /dev/null
+++ b/crypto/stubs_test.go
@@ -0,0 +1,22 @@
+package crypto
+
+import (
+ "fmt"
+ "testing"
+)
+
+func Error(t *testing.T, want, got interface{}) {
+ format := "\nWanted: %s\nGot: %s"
+
+ switch want.(type) {
+ case []byte, string, nil:
+ default:
+ format = fmt.Sprintf(format, "%v", "%v")
+ }
+
+ t.Errorf(format, want, got)
+}
+
+func ErrorTypes(t *testing.T, want, got interface{}) {
+ t.Errorf("\nWanted: %T\nGot: %T", want, got)
+}
diff --git a/jws/errors.go b/jws/errors.go
index 2d48368..6f6de54 100644
--- a/jws/errors.go
+++ b/jws/errors.go
@@ -3,9 +3,6 @@
import "errors"
var (
- // ErrInvalidKey means the key argument passed to SigningMethod.Verify
- // was not the correct type.
- ErrInvalidKey = errors.New("key is invalid")
// ErrNotEnoughMethods is returned if New was called _or_ the Flat/Compact
// methods were called with 0 SigningMethods.
@@ -49,4 +46,10 @@
// reasons. For example, if there aren't any signatures/payloads/headers
// to actually validate.
ErrCannotValidate = errors.New("cannot validate")
+
+ // ErrIsNotJWT means the given JWS is not a JWT.
+ ErrIsNotJWT = errors.New("JWS is not a JWT")
+
+ // ErrHoldsJWE means the given JWS holds a JWE inside its payload.
+ ErrHoldsJWE = errors.New("JWS holds JWE")
)
diff --git a/jws/jws.go b/jws/jws.go
index 4147d37..2a65f25 100644
--- a/jws/jws.go
+++ b/jws/jws.go
@@ -6,6 +6,7 @@
"sort"
"github.com/SermoDigital/jose"
+ "github.com/SermoDigital/jose/crypto"
)
// JWS represents a specific JWS.
@@ -15,8 +16,13 @@
clean bool
sb []sigHead
+
+ isJWT bool
}
+// Payload returns the JWS' payload.
+func (j *JWS) Payload() interface{} { return j.payload.v }
+
// sigHead represents the 'signatures' member of the JWS' "general"
// serialization form per
// https://tools.ietf.org/html/rfc7515#section-7.2.1
@@ -24,15 +30,15 @@
// It's embedded inside the "flat" structure in order to properly
// create the "flat" JWS.
type sigHead struct {
- Protected rawBase64 `json:"protected,omitempty"`
- Unprotected rawBase64 `json:"header,omitempty"`
- Signature Signature `json:"signature"`
+ Protected rawBase64 `json:"protected,omitempty"`
+ Unprotected rawBase64 `json:"header,omitempty"`
+ Signature crypto.Signature `json:"signature"`
- protected jose.Protected `json:"-"`
- unprotected jose.Header `json:"-"`
- clean bool `json:"-"`
+ protected jose.Protected
+ unprotected jose.Header
+ clean bool
- method SigningMethod
+ method crypto.SigningMethod
}
func (s *sigHead) unmarshal() error {
@@ -45,8 +51,8 @@
return nil
}
-// New creates a new JWS with the provided SigningMethods.
-func New(content interface{}, methods ...SigningMethod) *JWS {
+// New creates a new JWS with the provided crypto.SigningMethods.
+func New(content interface{}, methods ...crypto.SigningMethod) *JWS {
sb := make([]sigHead, len(methods))
for i := range methods {
sb[i] = sigHead{
@@ -218,6 +224,10 @@
// For information on the json.Unmarshaler parameter, see Parse.
func ParseCompact(encoded []byte, u ...json.Unmarshaler) (*JWS, error) {
+ // This section loosely follows
+ // https://tools.ietf.org/html/rfc7519#section-7.2
+ // because it's used to parse _both_ JWS and JWTs.
+
parts := bytes.Split(encoded, []byte{'.'})
if len(parts) != 3 {
return nil, ErrNotCompact
@@ -252,6 +262,11 @@
return nil, err
}
+ // https://tools.ietf.org/html/rfc7519#section-7.2.8
+ cty, ok := p.Get("cty").(string)
+ if ok && cty == "JWT" {
+ return &j, ErrHoldsJWE
+ }
return &j, nil
}
@@ -279,6 +294,8 @@
return nil
}
+// Any means any of the JWS signatures need to validate.
+// Refer to ValidateMulti for more information.
const Any int = -1
// ValidateMulti validates the current JWS as-is. Since it's meant to be
@@ -286,14 +303,16 @@
// internal parsing like the Sign, Flat, Compact, or General methods do.
// idx represents which signatures need to validate
// in order for the JWS to be considered valid.
-// Use the constant `Any` (-1) if _any_ should validate the JWS. Otherwise,
+// Use the constant `Any` (-1) if *any* should validate the JWS. Otherwise,
// use the indexes of the signatures that need to validate in order
// for the JWS to be considered valid.
-// Note: if idx is omitted it defaults to requiring _all_
-// signatures validate, and the JWS spec required _at least_ one
-// signature to validate in order for the JWS to be considered
-// valid.
-func (j *JWS) ValidateMulti(keys []interface{}, methods []SigningMethod, idx ...int) error {
+//
+// Notes:
+// 1.) If idx is omitted it defaults to requiring *all*
+// signatures validate
+// 2.) The JWS spec requires *at least* one
+// signature to validate in order for the JWS to be considered valid.
+func (j *JWS) ValidateMulti(keys []interface{}, methods []crypto.SigningMethod, idx ...int) error {
if len(j.sb) != len(methods) {
return ErrNotEnoughMethods
@@ -333,14 +352,17 @@
// Validate validates the current JWS as-is. Refer to ValidateMulti
// for more information.
-func (j *JWS) Validate(key interface{}, method SigningMethod) error {
+func (j *JWS) Validate(key interface{}, method crypto.SigningMethod) error {
if len(j.sb) < 1 {
return ErrCannotValidate
}
+ if j.isJWT {
+ return j.validateJWT(key, method)
+ }
return j.sb[0].validate(j.plcache, key, method)
}
-func (s *sigHead) validate(pl []byte, key interface{}, method SigningMethod) error {
+func (s *sigHead) validate(pl []byte, key interface{}, method crypto.SigningMethod) error {
if s.method != method {
return ErrMismatchedAlgorithms
}
diff --git a/jws/jws_serialize.go b/jws/jws_serialize.go
index 46ecd38..33369dd 100644
--- a/jws/jws_serialize.go
+++ b/jws/jws_serialize.go
@@ -27,8 +27,8 @@
// https://tools.ietf.org/html/rfc7515#section-7.2.1
//
// If only one key is passed it's used for all the provided
-// SigningMethods. Otherwise, len(keys) must equal the number
-// of SigningMethods added.
+// crypto.SigningMethods. Otherwise, len(keys) must equal the number
+// of crypto.SigningMethods added.
func (j *JWS) General(keys ...interface{}) ([]byte, error) {
if err := j.sign(keys...); err != nil {
return nil, err
diff --git a/jws/jws_serialize_test.go b/jws/jws_serialize_test.go
index 124a3b4..6472fe3 100644
--- a/jws/jws_serialize_test.go
+++ b/jws/jws_serialize_test.go
@@ -6,6 +6,7 @@
"testing"
"github.com/SermoDigital/jose"
+ "github.com/SermoDigital/jose/crypto"
)
var dataRaw = struct {
@@ -44,7 +45,7 @@
}
func TestGeneralIntegrity(t *testing.T) {
- j := New(dataRaw, SigningMethodRS512)
+ j := New(dataRaw, crypto.SigningMethodRS512)
b, err := j.General(rsaPriv)
if err != nil {
t.Error(err)
@@ -70,7 +71,7 @@
}
func TestFlatIntegrity(t *testing.T) {
- j := New(dataRaw, SigningMethodRS512)
+ j := New(dataRaw, crypto.SigningMethodRS512)
b, err := j.Flat(rsaPriv)
if err != nil {
t.Error(err)
@@ -96,7 +97,7 @@
}
func TestCompactIntegrity(t *testing.T) {
- j := New(dataRaw, SigningMethodRS512)
+ j := New(dataRaw, crypto.SigningMethodRS512)
b, err := j.Compact(rsaPriv)
if err != nil {
t.Error(err)
diff --git a/jws/jws_test.go b/jws/jws_test.go
index ebd7cf0..6c8355f 100644
--- a/jws/jws_test.go
+++ b/jws/jws_test.go
@@ -5,6 +5,8 @@
"encoding/base64"
"encoding/json"
"testing"
+
+ "github.com/SermoDigital/jose/crypto"
)
type easy []byte
@@ -29,7 +31,7 @@
var easyData = easy("easy data!")
func TestParseWithUnmarshaler(t *testing.T) {
- j := New(easyData, SigningMethodRS512)
+ j := New(easyData, crypto.SigningMethodRS512)
b, err := j.Flat(rsaPriv)
if err != nil {
t.Error(err)
@@ -47,7 +49,7 @@
}
func TestParseCompact(t *testing.T) {
- j := New(easyData, SigningMethodRS512)
+ j := New(easyData, crypto.SigningMethodRS512)
b, err := j.Compact(rsaPriv)
if err != nil {
t.Error(err)
@@ -69,7 +71,7 @@
}
func TestParseGeneral(t *testing.T) {
- sm := []SigningMethod{SigningMethodRS512, SigningMethodPS384, SigningMethodPS256}
+ sm := []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS384, crypto.SigningMethodPS256}
j := New(easyData, sm...)
b, err := j.General(rsaPriv)
if err != nil {
@@ -90,7 +92,7 @@
}
func TestValidateMulti(t *testing.T) {
- sm := []SigningMethod{SigningMethodRS512, SigningMethodPS384, SigningMethodPS256}
+ sm := []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS384, crypto.SigningMethodPS256}
j := New(easyData, sm...)
b, err := j.General(rsaPriv)
if err != nil {
@@ -109,7 +111,7 @@
}
func TestValidateMultiMismatchedAlgs(t *testing.T) {
- sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+ sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
j := New(easyData, sm...)
b, err := j.General(rsaPriv)
if err != nil {
@@ -122,7 +124,7 @@
}
// Shuffle it.
- sm = []SigningMethod{SigningMethodRS512, SigningMethodPS256, SigningMethodPS384}
+ sm = []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS256, crypto.SigningMethodPS384}
keys := []interface{}{rsaPub, rsaPub, rsaPub}
if err := j2.ValidateMulti(keys, sm, Any); err == nil {
@@ -131,7 +133,7 @@
}
func TestValidateMultiNotEnoughMethods(t *testing.T) {
- sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+ sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
j := New(easyData, sm...)
b, err := j.General(rsaPriv)
if err != nil {
@@ -152,7 +154,7 @@
}
func TestValidateMultiNotEnoughKeys(t *testing.T) {
- sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+ sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
j := New(easyData, sm...)
b, err := j.General(rsaPriv)
if err != nil {
@@ -171,7 +173,7 @@
}
func TestValidate(t *testing.T) {
- j := New(easyData, SigningMethodPS512)
+ j := New(easyData, crypto.SigningMethodPS512)
b, err := j.Flat(rsaPriv)
if err != nil {
t.Error(err)
@@ -182,7 +184,7 @@
t.Error(err)
}
- if err := j2.Validate(rsaPub, SigningMethodPS512); err != nil {
+ if err := j2.Validate(rsaPub, crypto.SigningMethodPS512); err != nil {
t.Error(err)
}
}
diff --git a/jws/jwt.go b/jws/jwt.go
new file mode 100644
index 0000000..ce2e985
--- /dev/null
+++ b/jws/jwt.go
@@ -0,0 +1,48 @@
+package jws
+
+import (
+ "github.com/SermoDigital/jose/crypto"
+ "github.com/SermoDigital/jose/jwt"
+)
+
+// Claims represents a set of JOSE Claims.
+type Claims jwt.Claims
+
+// NewJWT creates a new JWT with the given claims.
+func NewJWT(claims Claims, method crypto.SigningMethod) jwt.JWT {
+ j := New(claims, method)
+ j.isJWT = true
+ return j
+}
+
+// Serialize helps implements jwt.JWT.
+func (j *JWS) Serialize(key interface{}) ([]byte, error) {
+ if j.isJWT {
+ return j.Compact(key)
+ }
+ return nil, ErrIsNotJWT
+}
+
+// Claims helps implements jwt.JWT.
+func (j *JWS) Claims() jwt.Claims {
+ if j.isJWT {
+ if c, ok := j.payload.v.(Claims); ok {
+ return jwt.Claims(c)
+ }
+ }
+ return nil
+}
+
+// ParseJWT parses a serialized JWT into a physical JWT.
+func ParseJWT(encoded []byte) (JWT, error) {
+ return ParseCompact(encoded)
+}
+
+// IsJWT returns true if the JWS is a JWT.
+func (j *JWS) IsJWT() bool { return j.isJWT }
+
+func (j *JWS) validateJWT(key interface{}, m crypto.SigningMethod) error {
+ return nil
+}
+
+var _ jwt.JWT = (*JWS)(nil)
diff --git a/jws/signing_methods.go b/jws/signing_methods.go
index bc21d69..1b6665f 100644
--- a/jws/signing_methods.go
+++ b/jws/signing_methods.go
@@ -1,56 +1,38 @@
package jws
import (
- "crypto"
"sync"
+
+ "github.com/SermoDigital/jose/crypto"
)
var (
mu = &sync.RWMutex{}
- signingMethods = map[string]SigningMethod{
- SigningMethodES256.Alg(): SigningMethodES256,
- SigningMethodES384.Alg(): SigningMethodES384,
- SigningMethodES512.Alg(): SigningMethodES512,
+ signingMethods = map[string]crypto.SigningMethod{
+ crypto.SigningMethodES256.Alg(): crypto.SigningMethodES256,
+ crypto.SigningMethodES384.Alg(): crypto.SigningMethodES384,
+ crypto.SigningMethodES512.Alg(): crypto.SigningMethodES512,
- SigningMethodPS256.Alg(): SigningMethodPS256,
- SigningMethodPS384.Alg(): SigningMethodPS384,
- SigningMethodPS512.Alg(): SigningMethodPS512,
+ crypto.SigningMethodPS256.Alg(): crypto.SigningMethodPS256,
+ crypto.SigningMethodPS384.Alg(): crypto.SigningMethodPS384,
+ crypto.SigningMethodPS512.Alg(): crypto.SigningMethodPS512,
- SigningMethodRS256.Alg(): SigningMethodRS256,
- SigningMethodRS384.Alg(): SigningMethodRS384,
- SigningMethodRS512.Alg(): SigningMethodRS512,
+ crypto.SigningMethodRS256.Alg(): crypto.SigningMethodRS256,
+ crypto.SigningMethodRS384.Alg(): crypto.SigningMethodRS384,
+ crypto.SigningMethodRS512.Alg(): crypto.SigningMethodRS512,
- SigningMethodHS256.Alg(): SigningMethodHS256,
- SigningMethodHS384.Alg(): SigningMethodHS384,
- SigningMethodHS512.Alg(): SigningMethodHS512,
+ crypto.SigningMethodHS256.Alg(): crypto.SigningMethodHS256,
+ crypto.SigningMethodHS384.Alg(): crypto.SigningMethodHS384,
+ crypto.SigningMethodHS512.Alg(): crypto.SigningMethodHS512,
+
+ crypto.Unsecured.Alg(): crypto.Unsecured,
}
)
-// SigningMethod is an interface that provides a way to sign JWS tokens.
-type SigningMethod interface {
- // Alg describes the signing algorithm, and is used to uniquely
- // describe the specific SigningMethod.
- Alg() string
-
- // Verify accepts the raw content, the signature, and the key used
- // to sign the raw content, and returns any errors found while validating
- // the signature and content.
- Verify(raw []byte, sig Signature, key interface{}) error
-
- // Sign returns a Signature for the raw bytes, as well as any errors
- // that occurred during the signing.
- Sign(raw []byte, key interface{}) (Signature, error)
-
- // Used to cause quick panics when a SigningMethod whose form of hashing
- // isn't linked in the binary when you register a SigningMethod.
- // To spoof this, see "SigningMethodNone".
- Hasher() crypto.Hash
-}
-
-// RegisterSigningMethod registers the SigningMethod in the global map.
+// RegisterSigningMethod registers the crypto.SigningMethod in the global map.
// This is typically done inside the caller's init function.
-func RegisterSigningMethod(sm SigningMethod) {
+func RegisterSigningMethod(sm crypto.SigningMethod) {
if GetSigningMethod(sm.Alg()) != nil {
panic("jose/jws: cannot duplicate signing methods")
}
@@ -64,15 +46,15 @@
mu.Unlock()
}
-// RemoveSigningMethod removes the SigningMethod from the global map.
-func RemoveSigningMethod(sm SigningMethod) {
+// RemoveSigningMethod removes the crypto.SigningMethod from the global map.
+func RemoveSigningMethod(sm crypto.SigningMethod) {
mu.Lock()
delete(signingMethods, sm.Alg())
mu.Unlock()
}
-// GetSigningMethod retrieves a SigningMethod from the global map.
-func GetSigningMethod(alg string) SigningMethod {
+// GetSigningMethod retrieves a crypto.SigningMethod from the global map.
+func GetSigningMethod(alg string) crypto.SigningMethod {
mu.RLock()
defer mu.RUnlock()
return signingMethods[alg]
diff --git a/jws/signing_methods_test.go b/jws/signing_methods_test.go
index 59d52c2..017d482 100644
--- a/jws/signing_methods_test.go
+++ b/jws/signing_methods_test.go
@@ -5,6 +5,8 @@
"hash"
"io"
"testing"
+
+ c "github.com/SermoDigital/jose/crypto"
)
func init() { crypto.RegisterHash(crypto.Hash(0), HH) }
@@ -29,11 +31,11 @@
Hash crypto.Hash
}
-func (m *TestSigningMethod) Verify(_ []byte, _ Signature, _ interface{}) error {
+func (m *TestSigningMethod) Verify(_ []byte, _ c.Signature, _ interface{}) error {
return nil
}
-func (m *TestSigningMethod) Sign(_ []byte, _ interface{}) (Signature, error) {
+func (m *TestSigningMethod) Sign(_ []byte, _ interface{}) (c.Signature, error) {
return nil, nil
}
diff --git a/jws/stubs_test.go b/jws/stubs_test.go
index 0b9e9b2..513c6ef 100644
--- a/jws/stubs_test.go
+++ b/jws/stubs_test.go
@@ -9,6 +9,8 @@
"io/ioutil"
"path/filepath"
"testing"
+
+ "github.com/SermoDigital/jose/crypto"
)
func Error(t *testing.T, want, got interface{}) {
@@ -66,7 +68,7 @@
if err != nil {
panic(err)
}
- ec256Priv, err = ParseECPrivateKeyFromPEM(ecData)
+ ec256Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
if err != nil {
panic(err)
}
@@ -74,7 +76,7 @@
if err != nil {
panic(err)
}
- ec256Pub, err = ParseECPublicKeyFromPEM(ecData)
+ ec256Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
if err != nil {
panic(err)
}
@@ -82,7 +84,7 @@
if err != nil {
panic(err)
}
- ec384Priv, err = ParseECPrivateKeyFromPEM(ecData)
+ ec384Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
if err != nil {
panic(err)
}
@@ -90,7 +92,7 @@
if err != nil {
panic(err)
}
- ec384Pub, err = ParseECPublicKeyFromPEM(ecData)
+ ec384Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
if err != nil {
panic(err)
}
@@ -98,7 +100,7 @@
if err != nil {
panic(err)
}
- ec512Priv, err = ParseECPrivateKeyFromPEM(ecData)
+ ec512Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
if err != nil {
panic(err)
}
@@ -106,7 +108,7 @@
if err != nil {
panic(err)
}
- ec512Pub, err = ParseECPublicKeyFromPEM(ecData)
+ ec512Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
if err != nil {
panic(err)
}
diff --git a/jwt/claims.go b/jwt/claims.go
new file mode 100644
index 0000000..46076d9
--- /dev/null
+++ b/jwt/claims.go
@@ -0,0 +1,76 @@
+package jwt
+
+import (
+ "encoding/json"
+
+ "github.com/SermoDigital/jose"
+)
+
+// Claims implements a JOSE Claim set with the addition of some helper
+// methods, similar to net/url.Values.
+type Claims map[string]interface{}
+
+// Get retrieves the value corresponding with key from the Claims.
+func (c Claims) Get(key string) interface{} {
+ if c == nil {
+ return nil
+ }
+ return c[key]
+}
+
+// Set sets Claims[key] = val. It'll overwrite without warning.
+func (c Claims) Set(key string, val interface{}) {
+ c[key] = val
+}
+
+// Del removes the value that corresponds with key from the Claims.
+func (c Claims) Del(key string) {
+ delete(c, key)
+}
+
+// Has returns true if a value for the given key exists inside the Claims.
+func (c Claims) Has(key string) bool {
+ _, ok := c[key]
+ return ok
+}
+
+// MarshalJSON implements json.Marshaler for Claims.
+func (c Claims) MarshalJSON() ([]byte, error) {
+ if c == nil || len(c) == 0 {
+ return nil, nil
+ }
+ b, err := json.Marshal(map[string]interface{}(c))
+ if err != nil {
+ return nil, err
+ }
+ return jose.EncodeEscape(b), nil
+}
+
+// Base64 implements the Encoder interface.
+func (c Claims) Base64() ([]byte, error) {
+ return c.MarshalJSON()
+}
+
+// UnmarshalJSON implements json.Unmarshaler for Claims.
+func (c *Claims) UnmarshalJSON(b []byte) error {
+ if b == nil {
+ return nil
+ }
+
+ b, err := jose.DecodeEscaped(b)
+ if err != nil {
+ return err
+ }
+
+ // Since json.Unmarshal calls UnmarshalJSON,
+ // calling json.Unmarshal on *p would be infinitely recursive
+ // A temp variable is needed because &map[string]interface{}(*p) is
+ // invalid Go.
+
+ tmp := map[string]interface{}(*c)
+ if err = json.Unmarshal(b, &tmp); err != nil {
+ return err
+ }
+ *c = Claims(tmp)
+ return nil
+}
diff --git a/jwt/claims_test.go b/jwt/claims_test.go
new file mode 100644
index 0000000..e22cb07
--- /dev/null
+++ b/jwt/claims_test.go
@@ -0,0 +1 @@
+package jwt
diff --git a/jwt/jwt.go b/jwt/jwt.go
new file mode 100644
index 0000000..bd09ec0
--- /dev/null
+++ b/jwt/jwt.go
@@ -0,0 +1,16 @@
+package jwt
+
+import "github.com/SermoDigital/jose/crypto"
+
+type JWT interface {
+ // Claims returns the set of Claims.
+ Claims() Claims
+
+ // Validate returns an error describing any issues found while
+ // validating the JWT.
+ Validate(key interface{}, method crypto.SigningMethod) error
+
+ // Serialize serializes the JWT into its on-the-wire
+ // representation.
+ Serialize(key interface{}) ([]byte, error)
+}