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 }