mirror of
https://github.com/Luzifer/nginx-sso.git
synced 2024-12-20 21:01:17 +00:00
192 lines
5.1 KiB
Go
192 lines
5.1 KiB
Go
/*-
|
|
* 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
|
|
}
|