github.com/trustbloc/kms-go@v1.1.2/doc/jose/jws_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package jose
     8  
     9  import (
    10  	"encoding/base64"
    11  	"errors"
    12  	"fmt"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestHeaders_GetKeyID(t *testing.T) {
    20  	kid, ok := Headers{"kid": "key id"}.KeyID()
    21  	require.True(t, ok)
    22  	require.Equal(t, "key id", kid)
    23  
    24  	kid, ok = Headers{"kid": 777}.KeyID()
    25  	require.False(t, ok)
    26  	require.Empty(t, kid)
    27  
    28  	kid, ok = Headers{}.KeyID()
    29  	require.False(t, ok)
    30  	require.Empty(t, kid)
    31  }
    32  
    33  func TestHeaders_GetAlgorithm(t *testing.T) {
    34  	kid, ok := Headers{"alg": "EdDSA"}.Algorithm()
    35  	require.True(t, ok)
    36  	require.Equal(t, "EdDSA", kid)
    37  
    38  	kid, ok = Headers{"alg": 777}.Algorithm()
    39  	require.False(t, ok)
    40  	require.Empty(t, kid)
    41  
    42  	kid, ok = Headers{}.Algorithm()
    43  	require.False(t, ok)
    44  	require.Empty(t, kid)
    45  }
    46  
    47  func TestNewCompositeAlgSignatureVerifier(t *testing.T) {
    48  	verifier := NewCompositeAlgSigVerifier(AlgSignatureVerifier{
    49  		Alg: "EdDSA",
    50  		Verifier: SignatureVerifierFunc(
    51  			func(joseHeaders Headers, payload, signingInput, signature []byte) error {
    52  				return errors.New("signature is invalid")
    53  			},
    54  		),
    55  	})
    56  
    57  	err := verifier.Verify(Headers{"alg": "EdDSA"}, nil, nil, nil)
    58  	require.Error(t, err)
    59  	require.EqualError(t, err, "signature is invalid")
    60  
    61  	// alg is not defined
    62  	err = verifier.Verify(Headers{}, nil, nil, nil)
    63  	require.Error(t, err)
    64  	require.EqualError(t, err, "'alg' JOSE header is not present")
    65  
    66  	// not supported alg
    67  	err = verifier.Verify(Headers{"alg": "RS256"}, nil, nil, nil)
    68  	require.Error(t, err)
    69  	require.EqualError(t, err, "no verifier found for RS256 algorithm")
    70  }
    71  
    72  func TestDefaultSigningInputVerifier_Verify(t *testing.T) {
    73  	verifier := DefaultSigningInputVerifier(func(joseHeaders Headers, payload, signingInput, signature []byte) error {
    74  		return errors.New("signature is invalid")
    75  	})
    76  
    77  	err := verifier.Verify(Headers{"alg": "EdDSA"}, nil, nil, nil)
    78  	require.Error(t, err)
    79  	require.EqualError(t, err, "signature is invalid")
    80  
    81  	// fail in signingInput()
    82  	err = verifier.Verify(Headers{HeaderB64Payload: "invalid value"}, nil, nil, nil)
    83  	require.Error(t, err)
    84  	require.EqualError(t, err, "invalid b64 header")
    85  }
    86  
    87  func TestJSONWebSignature_SerializeCompact(t *testing.T) {
    88  	headers := Headers{"alg": "EdSDA", "typ": "JWT"}
    89  	payload := []byte("payload")
    90  
    91  	jws, err := NewJWS(headers, nil, payload,
    92  		&testSigner{
    93  			headers:   Headers{"alg": "dummy"},
    94  			signature: []byte("signature"),
    95  		})
    96  	require.NoError(t, err)
    97  
    98  	jwsCompact, err := jws.SerializeCompact(false)
    99  	require.NoError(t, err)
   100  	require.NotEmpty(t, jwsCompact)
   101  
   102  	// b64=false
   103  	jws, err = NewJWS(headers, nil, payload,
   104  		&testSigner{
   105  			headers:   Headers{"alg": "dummy", "b64": false},
   106  			signature: []byte("signature"),
   107  		})
   108  	require.NoError(t, err)
   109  
   110  	jwsCompact, err = jws.SerializeCompact(false)
   111  	require.NoError(t, err)
   112  	require.NotEmpty(t, jwsCompact)
   113  
   114  	// signer error
   115  	jws, err = NewJWS(headers, nil, payload,
   116  		&testSigner{
   117  			headers: Headers{"alg": "dummy"},
   118  			err:     errors.New("signer error"),
   119  		})
   120  	require.Error(t, err)
   121  	require.Contains(t, err.Error(), "sign JWS verification data")
   122  	require.Nil(t, jws)
   123  
   124  	// no alg defined
   125  	jws, err = NewJWS(Headers{}, nil, payload,
   126  		&testSigner{
   127  			headers: Headers{},
   128  		})
   129  	require.Error(t, err)
   130  	require.Contains(t, err.Error(), "alg JWS header is not defined")
   131  	require.Nil(t, jws)
   132  
   133  	// jose headers marshalling error
   134  	jws, err = NewJWS(Headers{}, nil, payload,
   135  		&testSigner{
   136  			headers: getUnmarshallableMap(),
   137  		})
   138  	require.Error(t, err)
   139  	require.Contains(t, err.Error(), "serialize JWS headers")
   140  	require.Nil(t, jws)
   141  
   142  	// invalid b64
   143  	jws, err = NewJWS(Headers{}, nil, payload,
   144  		&testSigner{
   145  			headers:   Headers{"alg": "dummy", "b64": "invalid"},
   146  			signature: []byte("signature"),
   147  		})
   148  	require.Error(t, err)
   149  	require.Contains(t, err.Error(), "invalid b64 header")
   150  	require.Nil(t, jws)
   151  }
   152  
   153  func TestJSONWebSignature_Signature(t *testing.T) {
   154  	jws := &JSONWebSignature{
   155  		signature: []byte("signature"),
   156  	}
   157  	require.NotEmpty(t, jws.Signature())
   158  
   159  	jws.signature = nil
   160  	require.Empty(t, jws.Signature())
   161  }
   162  
   163  func TestParseJWS(t *testing.T) {
   164  	corruptedBased64 := "XXXXXaGVsbG8="
   165  
   166  	jws, err := NewJWS(Headers{"alg": "EdSDA", "typ": "JWT"}, nil, []byte("payload"),
   167  		&testSigner{
   168  			headers:   Headers{"alg": "dummy"},
   169  			signature: []byte("signature"),
   170  		})
   171  	require.NoError(t, err)
   172  
   173  	jwsCompact, err := jws.SerializeCompact(false)
   174  	require.NoError(t, err)
   175  	require.NotEmpty(t, jwsCompact)
   176  
   177  	validJWSParts := strings.Split(jwsCompact, ".")
   178  
   179  	parsedJWS, err := ParseJWS(jwsCompact, &testVerifier{})
   180  	require.NoError(t, err)
   181  	require.NotNil(t, parsedJWS)
   182  	require.Equal(t, jws, parsedJWS)
   183  
   184  	jwsDetached := fmt.Sprintf("%s.%s.%s", validJWSParts[0], "", validJWSParts[2])
   185  
   186  	detachedPayload, err := base64.RawURLEncoding.DecodeString(validJWSParts[1])
   187  	require.NoError(t, err)
   188  
   189  	parsedJWS, err = ParseJWS(jwsDetached, &testVerifier{}, WithJWSDetachedPayload(detachedPayload))
   190  	require.NoError(t, err)
   191  	require.NotNil(t, parsedJWS)
   192  	require.Equal(t, jws, parsedJWS)
   193  
   194  	// Parse not compact JWS format
   195  	parsedJWS, err = ParseJWS(`{"some": "JSON"}`, &testVerifier{})
   196  	require.Error(t, err)
   197  	require.EqualError(t, err, "JWS JSON serialization is not supported")
   198  	require.Nil(t, parsedJWS)
   199  
   200  	// Parse invalid compact JWS format
   201  	parsedJWS, err = ParseJWS("two_parts.only", &testVerifier{})
   202  	require.Error(t, err)
   203  	require.EqualError(t, err, "invalid JWS compact format")
   204  	require.Nil(t, parsedJWS)
   205  
   206  	// invalid headers
   207  	jwsWithInvalidHeaders := fmt.Sprintf("%s.%s.%s", "invalid", validJWSParts[1], validJWSParts[2])
   208  	parsedJWS, err = ParseJWS(jwsWithInvalidHeaders, &testVerifier{})
   209  	require.Error(t, err)
   210  	require.Contains(t, err.Error(), "unmarshal JSON headers")
   211  	require.Nil(t, parsedJWS)
   212  
   213  	jwsWithInvalidHeaders = fmt.Sprintf("%s.%s.%s", corruptedBased64, validJWSParts[1], validJWSParts[2])
   214  	parsedJWS, err = ParseJWS(jwsWithInvalidHeaders, &testVerifier{})
   215  	require.Error(t, err)
   216  	require.Contains(t, err.Error(), "decode base64 header")
   217  	require.Nil(t, parsedJWS)
   218  
   219  	emptyHeaders := base64.RawURLEncoding.EncodeToString([]byte("{}"))
   220  
   221  	jwsWithInvalidHeaders = fmt.Sprintf("%s.%s.%s", emptyHeaders, validJWSParts[1], validJWSParts[2])
   222  	parsedJWS, err = ParseJWS(jwsWithInvalidHeaders, &testVerifier{})
   223  	require.Error(t, err)
   224  	require.Contains(t, err.Error(), "alg JWS header is not defined")
   225  	require.Nil(t, parsedJWS)
   226  
   227  	// invalid payload
   228  	jwsWithInvalidPayload := fmt.Sprintf("%s.%s.%s", validJWSParts[0], corruptedBased64, validJWSParts[2])
   229  	parsedJWS, err = ParseJWS(jwsWithInvalidPayload, &testVerifier{})
   230  	require.Error(t, err)
   231  	require.Contains(t, err.Error(), "decode base64 payload")
   232  	require.Nil(t, parsedJWS)
   233  
   234  	// invalid signature
   235  	jwsWithInvalidSignature := fmt.Sprintf("%s.%s.%s", validJWSParts[0], validJWSParts[1], corruptedBased64)
   236  	parsedJWS, err = ParseJWS(jwsWithInvalidSignature, &testVerifier{})
   237  	require.Error(t, err)
   238  	require.Contains(t, err.Error(), "decode base64 signature")
   239  	require.Nil(t, parsedJWS)
   240  
   241  	// verifier error
   242  	parsedJWS, err = ParseJWS(jwsCompact, &testVerifier{err: errors.New("bad signature")})
   243  	require.Error(t, err)
   244  	require.EqualError(t, err, "bad signature")
   245  	require.Nil(t, parsedJWS)
   246  }
   247  
   248  func TestIsCompactJWS(t *testing.T) {
   249  	require.True(t, IsCompactJWS("a.b.c"))
   250  	require.False(t, IsCompactJWS("a.b"))
   251  	require.False(t, IsCompactJWS(`{"some": "JSON"}`))
   252  	require.False(t, IsCompactJWS(""))
   253  }
   254  
   255  type testSigner struct {
   256  	headers   Headers
   257  	signature []byte
   258  	err       error
   259  }
   260  
   261  func (s testSigner) Sign(_ []byte) ([]byte, error) {
   262  	return s.signature, s.err
   263  }
   264  
   265  func (s testSigner) Headers() Headers {
   266  	return s.headers
   267  }
   268  
   269  type testVerifier struct {
   270  	err error
   271  }
   272  
   273  func (v testVerifier) Verify(_ Headers, _, _, _ []byte) error {
   274  	return v.err
   275  }
   276  
   277  func getUnmarshallableMap() map[string]interface{} {
   278  	return map[string]interface{}{"alg": "JWS", "error": map[chan int]interface{}{make(chan int): 6}}
   279  }