| package jws |
| |
| import ( |
| "bytes" |
| "encoding/base64" |
| "encoding/json" |
| "errors" |
| "math/rand" |
| "testing" |
| |
| "github.com/SermoDigital/jose/crypto" |
| ) |
| |
| type easy []byte |
| |
| func (e *easy) UnmarshalJSON(b []byte) error { |
| if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' { |
| b = b[1 : len(b)-1] |
| } |
| // json.Marshal encodes easy as it would a []byte, so in |
| // `"base64"` format. |
| dst := make([]byte, base64.StdEncoding.DecodedLen(len(b))) |
| n, err := base64.StdEncoding.Decode(dst, b) |
| if err != nil { |
| return err |
| } |
| *e = easy(dst[:n]) |
| return nil |
| } |
| |
| var _ json.Unmarshaler = (*easy)(nil) |
| |
| var easyData = easy("easy data!") |
| |
| func TestParseWithUnmarshaler(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodRS512) |
| b, err := j.Flat(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| var e easy |
| j2, err := Parse(b, &e) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| if !bytes.Equal(easyData, *j2.Payload().(*easy)) { |
| Error(t, easyData, *j2.Payload().(*easy)) |
| } |
| } |
| |
| func TestParseCompact(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodRS512) |
| b, err := j.Compact(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseCompact(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| var k easy |
| if err := k.UnmarshalJSON([]byte(j2.Payload().(string))); err != nil { |
| t.Error(err) |
| } |
| |
| if !bytes.Equal(k, easyData) { |
| Error(t, easyData, k) |
| } |
| } |
| |
| func TestParseCompactWithUnmarshaler(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodRS512) |
| b, err := j.Compact(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| var e easy |
| j2, err := ParseCompact(b, &e) |
| if err != nil { |
| t.Error(err) |
| } |
| if !bytes.Equal(easyData, *j2.Payload().(*easy)) { |
| Error(t, easyData, *j2.Payload().(*easy)) |
| } |
| } |
| |
| func TestParseGeneral(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| for i, v := range j2.(*jws).sb { |
| k := v.protected.Get("alg").(string) |
| if k != sm[i].Alg() { |
| Error(t, sm[i].Alg(), k) |
| } |
| } |
| } |
| |
| func TestVerifyMulti(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| keys := []interface{}{rsaPub, rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, nil); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestVerifyMultiOneKey(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| keys := []interface{}{rsaPub} |
| if err := j2.VerifyMulti(keys, sm, nil); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestVerifyMultiMismatchedAlgs(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| shuffle := func(a []crypto.SigningMethod) { |
| N := len(a) |
| for i := 0; i < N; i++ { |
| r := i + rand.Intn(N-i) |
| a[r], a[i] = a[i], a[r] |
| } |
| } |
| |
| shuffle(sm) |
| |
| keys := []interface{}{rsaPub, rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, nil); err == nil { |
| t.Error("Should NOT be nil") |
| } |
| } |
| |
| func TestVerifyMultiNotEnoughMethods(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| sm = sm[0 : len(sm)-1] |
| |
| keys := []interface{}{rsaPub, rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, nil); err == nil { |
| t.Error("Should NOT be nil") |
| } |
| } |
| |
| func TestVerifyMultiNotEnoughKeys(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| keys := []interface{}{rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, nil); err == nil { |
| t.Error("Should NOT be nil") |
| } |
| } |
| |
| func TestVerifyMultiSigningOpts(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| o := SigningOpts{ |
| Number: 3, |
| Indices: []int{0, 1, 2}, |
| } |
| |
| keys := []interface{}{rsaPub, rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, &o); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestVerifyMultiSigningOptsErr(t *testing.T) { |
| sm := []crypto.SigningMethod{ |
| crypto.SigningMethodRS256, |
| crypto.SigningMethodPS384, |
| crypto.SigningMethodPS512, |
| } |
| |
| j := New(easyData, sm...) |
| b, err := j.General(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseGeneral(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| o := SigningOpts{ |
| Number: 4, |
| Indices: []int{0, 1, 2, 3}, |
| } |
| |
| keys := []interface{}{rsaPub, rsaPub, rsaPub} |
| if err := j2.VerifyMulti(keys, sm, &o); err == nil { |
| t.Error("Should not be nil!") |
| } |
| } |
| |
| func TestVerify(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodPS512) |
| b, err := j.Flat(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseFlat(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| if err := j2.Verify(rsaPub, crypto.SigningMethodPS512); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestVerifyCallback(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodPS512) |
| b, err := j.Flat(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseFlat(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| cb := func(j JWS) ([]interface{}, error) { |
| return []interface{}{rsaPub}, nil |
| } |
| |
| if err := j2.VerifyCallback(cb, []crypto.SigningMethod{crypto.SigningMethodPS512}, nil); err != nil { |
| t.Error(err) |
| } |
| } |
| |
| func TestVerifyCallbackErr(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodPS512) |
| b, err := j.Flat(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseFlat(b) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| cb := func(j JWS) ([]interface{}, error) { |
| return nil, errors.New("k") |
| } |
| |
| if err := j2.VerifyCallback(cb, []crypto.SigningMethod{crypto.SigningMethodPS512}, nil); err == nil { |
| t.Error("Should not be nil!") |
| } |
| } |
| |
| func TestVerifyNoSBs(t *testing.T) { |
| j := New(easyData, crypto.SigningMethodPS512) |
| b, err := j.Flat(rsaPriv) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| j2, err := ParseFlat(b) |
| if err != nil { |
| t.Error(err) |
| } |
| j2.(*jws).sb = nil |
| if err := j2.Verify(rsaPub, crypto.SigningMethodPS512); err != ErrCannotValidate { |
| Error(t, ErrCannotValidate, err) |
| } |
| } |