| /*- |
| * Copyright 2018 Square Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package jose |
| |
| import ( |
| "fmt" |
| "testing" |
| ) |
| |
| type signWrapper struct { |
| pk *JSONWebKey |
| wrapped payloadSigner |
| algs []SignatureAlgorithm |
| } |
| |
| var _ = OpaqueSigner(&signWrapper{}) |
| |
| func (sw *signWrapper) Algs() []SignatureAlgorithm { |
| return sw.algs |
| } |
| |
| func (sw *signWrapper) Public() *JSONWebKey { |
| return sw.pk |
| } |
| |
| func (sw *signWrapper) SignPayload(payload []byte, alg SignatureAlgorithm) ([]byte, error) { |
| sig, err := sw.wrapped.signPayload(payload, alg) |
| if err != nil { |
| return nil, err |
| } |
| return sig.Signature, nil |
| } |
| |
| type verifyWrapper struct { |
| wrapped []payloadVerifier |
| } |
| |
| var _ = OpaqueVerifier(&verifyWrapper{}) |
| |
| func (vw *verifyWrapper) VerifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error { |
| if len(vw.wrapped) == 0 { |
| return fmt.Errorf("error: verifier had no keys") |
| } |
| var err error |
| for _, v := range vw.wrapped { |
| err = v.verifyPayload(payload, signature, alg) |
| if err == nil { |
| return nil |
| } |
| } |
| return err |
| } |
| |
| func TestRoundtripsJWSOpaque(t *testing.T) { |
| sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA} |
| |
| serializers := []func(*JSONWebSignature) (string, error){ |
| func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() }, |
| func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil }, |
| } |
| |
| corrupter := func(obj *JSONWebSignature) {} |
| |
| for _, alg := range sigAlgs { |
| signingKey, verificationKey := GenerateSigningTestKey(alg) |
| |
| for i, serializer := range serializers { |
| sw := makeOpaqueSigner(t, signingKey, alg) |
| vw := makeOpaqueVerifier(t, []interface{}{verificationKey}, alg) |
| |
| err := RoundtripJWS(alg, serializer, corrupter, sw, verificationKey, "test_nonce") |
| if err != nil { |
| t.Error(err, alg, i) |
| } |
| |
| err = RoundtripJWS(alg, serializer, corrupter, signingKey, vw, "test_nonce") |
| if err != nil { |
| t.Error(err, alg, i) |
| } |
| |
| err = RoundtripJWS(alg, serializer, corrupter, sw, vw, "test_nonce") |
| if err != nil { |
| t.Error(err, alg, i) |
| } |
| } |
| } |
| } |
| |
| func makeOpaqueSigner(t *testing.T, signingKey interface{}, alg SignatureAlgorithm) *signWrapper { |
| ri, err := makeJWSRecipient(alg, signingKey) |
| if err != nil { |
| t.Fatal(err) |
| } |
| return &signWrapper{ |
| wrapped: ri.signer, |
| algs: []SignatureAlgorithm{alg}, |
| pk: &JSONWebKey{Key: ri.publicKey()}, |
| } |
| } |
| |
| func makeOpaqueVerifier(t *testing.T, verificationKey []interface{}, alg SignatureAlgorithm) *verifyWrapper { |
| var verifiers []payloadVerifier |
| for _, vk := range verificationKey { |
| verifier, err := newVerifier(vk) |
| if err != nil { |
| t.Fatal(err) |
| } |
| verifiers = append(verifiers, verifier) |
| } |
| return &verifyWrapper{wrapped: verifiers} |
| } |
| |
| func TestOpaqueSignerKeyRotation(t *testing.T) { |
| |
| sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA} |
| |
| serializers := []func(*JSONWebSignature) (string, error){ |
| func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() }, |
| func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil }, |
| } |
| |
| for _, alg := range sigAlgs { |
| for i, serializer := range serializers { |
| sk1, pk1 := GenerateSigningTestKey(alg) |
| sk2, pk2 := GenerateSigningTestKey(alg) |
| |
| sw := makeOpaqueSigner(t, sk1, alg) |
| sw.pk.KeyID = "first" |
| vw := makeOpaqueVerifier(t, []interface{}{pk1, pk2}, alg) |
| |
| signer, err := NewSigner( |
| SigningKey{Algorithm: alg, Key: sw}, |
| &SignerOptions{NonceSource: staticNonceSource("test_nonce")}, |
| ) |
| if err != nil { |
| t.Fatal(err, alg, i) |
| } |
| |
| jws1, err := signer.Sign([]byte("foo bar baz")) |
| if err != nil { |
| t.Fatal(err, alg, i) |
| } |
| jws1 = rtSerialize(t, serializer, jws1, vw) |
| if kid := jws1.Signatures[0].Protected.KeyID; kid != "first" { |
| t.Errorf("expected kid %q but got %q", "first", kid) |
| } |
| |
| swNext := makeOpaqueSigner(t, sk2, alg) |
| swNext.pk.KeyID = "next" |
| sw.wrapped = swNext.wrapped |
| sw.pk = swNext.pk |
| |
| jws2, err := signer.Sign([]byte("foo bar baz next")) |
| if err != nil { |
| t.Error(err, alg, i) |
| } |
| jws2 = rtSerialize(t, serializer, jws2, vw) |
| if kid := jws2.Signatures[0].Protected.KeyID; kid != "next" { |
| t.Errorf("expected kid %q but got %q", "next", kid) |
| } |
| } |
| } |
| } |
| |
| func rtSerialize(t *testing.T, serializer func(*JSONWebSignature) (string, error), sig *JSONWebSignature, vk interface{}) *JSONWebSignature { |
| b, err := serializer(sig) |
| if err != nil { |
| t.Fatal(err) |
| } |
| sig, err = ParseSigned(b) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if _, err := sig.Verify(vk); err != nil { |
| t.Fatal(err) |
| } |
| return sig |
| } |