github.com/trustbloc/kms-go@v1.1.2/doc/jose/encrypt_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 "bytes" 11 "crypto/elliptic" 12 "encoding/base64" 13 "encoding/json" 14 "fmt" 15 "testing" 16 17 "github.com/google/tink/go/aead" 18 "github.com/google/tink/go/keyset" 19 "github.com/stretchr/testify/require" 20 21 "github.com/trustbloc/kms-go/crypto/tinkcrypto" 22 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/ecdh" 23 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/keyio" 24 25 cryptoapi "github.com/trustbloc/kms-go/spi/crypto" 26 ) 27 28 func TestFailConvertRecKeyToMarshalledJWK(t *testing.T) { 29 t.Run("test convertRecEPKToMarshalledJWK using EPK with bad curve", func(t *testing.T) { 30 recKey := &cryptoapi.RecipientWrappedKey{ 31 EPK: cryptoapi.PublicKey{ 32 Curve: "badCurveName", 33 Type: "EC", 34 }, 35 } 36 37 _, err := convertRecEPKToMarshalledJWK(&recKey.EPK) 38 require.EqualError(t, err, "unsupported curve") 39 }) 40 41 t.Run("test convertRecEPKToMarshalledJWK and buildRecipientHeaders using EPK with bad key type", func(t *testing.T) { 42 recKey := &cryptoapi.RecipientWrappedKey{ 43 EPK: cryptoapi.PublicKey{ 44 Curve: "P-256", 45 }, 46 } 47 48 _, err := convertRecEPKToMarshalledJWK(&recKey.EPK) 49 require.EqualError(t, err, "invalid key type") 50 51 _, err = buildRecipientHeaders(recKey, false) 52 require.EqualError(t, err, "failed to convert recipient key to marshalled JWK: invalid key type") 53 }) 54 } 55 56 func TestBuildRecsWithEPKMissingKeyTypeFailure(t *testing.T) { 57 recKey := &cryptoapi.RecipientWrappedKey{ 58 EPK: cryptoapi.PublicKey{ 59 Curve: "P-256", 60 }, 61 } 62 63 c, err := tinkcrypto.New() 64 require.NoError(t, err) 65 66 recipients, recsKH := createRecipients(t, 2) 67 68 enc, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 69 "0", recsKH["0"], recipients, c) 70 require.NoError(t, err) 71 72 _, _, err = enc.buildRecs([]*cryptoapi.RecipientWrappedKey{recKey}, true) 73 require.EqualError(t, err, "failed to convert recipient key to marshalled JWK: invalid key type") 74 } 75 76 func TestBadSenderKeyType(t *testing.T) { 77 c, err := tinkcrypto.New() 78 require.NoError(t, err) 79 80 // create a keyset.Handle that fails JWE/ECDH primitive execution (must come from an ECDH key template). 81 aeadKT := aead.AES256GCMKeyTemplate() 82 aeadKH, err := keyset.NewHandle(aeadKT) 83 require.NoError(t, err) 84 85 recipients, _ := createRecipients(t, 2) 86 87 // create jweEncrypter manually with a bad sender type 88 jweEncrypter := JWEEncrypt{ 89 skid: "123", 90 senderKH: aeadKH, 91 recipientsKeys: recipients, 92 crypto: c, 93 encAlg: A256GCM, 94 } 95 96 _, err = jweEncrypter.Encrypt([]byte{}) 97 require.EqualError(t, err, "jweencryptWithSender: failed to wrap cek: wrapCEKForRecipientsWithTagAndEPK: "+ 98 "wrapKey: 1 failed: wrapKey: deriveKEKAndWrap: error ECDH-1PU kek derivation: derive1PUKEK: EC key derivation "+ 99 "error derive1PUWithECKey: failed to retrieve sender key: ksToPrivateECDSAKey: failed to extract sender key: "+ 100 "extractPrivKey: can't extract unsupported private key 'type.googleapis.com/google.crypto.tink.AesGcmKey'") 101 } 102 103 func TestMergeSingleRecipientsHeadersFailureWithUnsetCurve(t *testing.T) { 104 aad := map[string]string{"enc": "test"} 105 106 mAAD, err := json.Marshal(aad) 107 require.NoError(t, err) 108 109 wk := &cryptoapi.RecipientWrappedKey{ 110 EPK: cryptoapi.PublicKey{Type: "EC"}, 111 } 112 113 // fail with aad not base64URL encoded 114 _, err = mergeSingleRecipientHeaders(wk, []byte("aad not base64URL encoded"), json.Marshal) 115 require.EqualError(t, err, "illegal base64 data at input byte 3") 116 117 badAAD := base64.RawURLEncoding.EncodeToString([]byte("aad not a json format")) 118 119 // fail with aad not being a marshalled json 120 _, err = mergeSingleRecipientHeaders(wk, []byte(badAAD), json.Marshal) 121 require.EqualError(t, err, "invalid character 'a' looking for beginning of value") 122 123 // fail with epk curve not set 124 _, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), json.Marshal) 125 require.EqualError(t, err, "unsupported curve") 126 127 // set epk curve for subsequent tests 128 wk.EPK.Curve = elliptic.P256().Params().Name 129 130 fm := &failingMarshaller{ 131 numTimesMarshalCalledBeforeReturnErr: 0, 132 } 133 134 // fail KID marshalling 135 _, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal) 136 require.EqualError(t, err, errFailingMarshal.Error()) 137 138 fm = &failingMarshaller{ 139 numTimesMarshalCalledBeforeReturnErr: 1, 140 } 141 142 // fail Alg marshalling 143 _, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal) 144 require.EqualError(t, err, errFailingMarshal.Error()) 145 146 fm = &failingMarshaller{ 147 numTimesMarshalCalledBeforeReturnErr: 1, 148 } 149 150 // fail EPK marshalling 151 _, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal) 152 require.EqualError(t, err, errFailingMarshal.Error()) 153 } 154 155 func TestEmptyComputeAuthData(t *testing.T) { 156 protecteHeaders := new(map[string]interface{}) 157 aad := []byte("") 158 _, err := computeAuthData(*protecteHeaders, "", aad) 159 require.NoError(t, err, "computeAuthData with empty protectedHeaders and empty aad should not fail") 160 } 161 162 // createRecipients and return their public key and keyset.Handle. 163 func createRecipients(t *testing.T, numberOfEntities int) ([]*cryptoapi.PublicKey, map[string]*keyset.Handle) { 164 t.Helper() 165 166 r := make([]*cryptoapi.PublicKey, 0) 167 rKH := make(map[string]*keyset.Handle) 168 169 for i := 0; i < numberOfEntities; i++ { 170 mrKey, kh := createAndMarshalEntityKey(t) 171 ecPubKey := new(cryptoapi.PublicKey) 172 err := json.Unmarshal(mrKey, ecPubKey) 173 require.NoError(t, err) 174 175 ecPubKey.KID = fmt.Sprint(i) 176 177 r = append(r, ecPubKey) 178 rKH[fmt.Sprint(i)] = kh 179 } 180 181 return r, rKH 182 } 183 184 // createAndMarshalEntityKey creates a new recipient keyset.Handle, extracts public key, marshals it and returns 185 // both marshalled public key and original recipient keyset.Handle. 186 func createAndMarshalEntityKey(t *testing.T) ([]byte, *keyset.Handle) { 187 t.Helper() 188 189 tmpl := ecdh.NISTP256ECDHKWKeyTemplate() 190 191 kh, err := keyset.NewHandle(tmpl) 192 require.NoError(t, err) 193 194 pubKH, err := kh.Public() 195 require.NoError(t, err) 196 197 buf := new(bytes.Buffer) 198 pubKeyWriter := keyio.NewWriter(buf) 199 require.NotEmpty(t, pubKeyWriter) 200 201 err = pubKH.WriteWithNoSecrets(pubKeyWriter) 202 require.NoError(t, err) 203 204 return buf.Bytes(), kh 205 } 206 207 const ( 208 testEncType = "application/test-encrypted+json" 209 testPayloadType = "application/test-content+json" 210 ) 211 212 func TestFailJWEEncrypt(t *testing.T) { 213 c, err := tinkcrypto.New() 214 require.NoError(t, err) 215 216 recipients, recsKH := createRecipients(t, 2) 217 218 enc, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 219 "0", recsKH["0"], recipients, c) 220 require.NoError(t, err) 221 222 enc.encAlg = "Undefined" 223 224 _, err = enc.Encrypt([]byte("test")) 225 require.EqualError(t, err, "jweencrypt: failed to get encryption primitive: getECDHEncPrimitive: encAlg"+ 226 " not supported: 'Undefined'") 227 } 228 229 func TestFailJWEDecrypt(t *testing.T) { 230 c, err := tinkcrypto.New() 231 require.NoError(t, err) 232 233 recipients, _ := createRecipients(t, 2) 234 235 // encrypt using local jose package 236 jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 237 "", nil, recipients, c) 238 require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys") 239 240 pt := []byte("some msg") 241 jwe, err := jweEncrypter.Encrypt(pt) 242 require.NoError(t, err) 243 require.Equal(t, len(recipients), len(jwe.Recipients)) 244 245 dec := NewJWEDecrypt(nil, c, nil) 246 require.NotEmpty(t, dec) 247 248 jwe.ProtectedHeaders[HeaderEncryption] = "Undefined" 249 250 _, err = dec.decryptJWE(jwe, []byte("")) 251 require.EqualError(t, err, "jwedecrypt: failed to get decryption primitive: invalid content encAlg: 'Undefined'") 252 253 delete(jwe.ProtectedHeaders, HeaderEncryption) 254 255 _, err = dec.decryptJWE(jwe, []byte("")) 256 require.EqualError(t, err, "jwedecrypt: JWE 'enc' protected header is missing") 257 } 258 259 func TestBuildAPUAPVFailures(t *testing.T) { 260 c, err := tinkcrypto.New() 261 require.NoError(t, err) 262 263 recipients, _ := createRecipients(t, 3) 264 265 // encrypt using local jose package 266 jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 267 "", nil, recipients, c) 268 require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys") 269 270 t.Run("call encryptWithSender and buildAPUAPV with JWEEncrypter having empty skid", func(t *testing.T) { 271 _, err = jweEncrypter.encryptWithSender(nil, nil, nil, nil, nil) 272 require.EqualError(t, err, "jweencryptWithSender: cannot create APU/APV with empty sender skid") 273 274 _, _, err = jweEncrypter.buildAPUAPV() 275 require.EqualError(t, err, "cannot create APU/APV with empty sender skid") 276 }) 277 278 t.Run("call buildAPUAPV with JWEEncrypter having empty recipients", func(t *testing.T) { 279 jweEncrypter.skid = "skid" 280 jweEncrypter.recipientsKeys = nil 281 282 _, _, err = jweEncrypter.buildAPUAPV() 283 require.EqualError(t, err, "cannot create APU/APV with empty recipient keys") 284 }) 285 } 286 287 func TestGenerateEPKAndUpdateAuthDataFor1PUFailure(t *testing.T) { 288 c, err := tinkcrypto.New() 289 require.NoError(t, err) 290 291 recipients, _ := createRecipients(t, 5) 292 293 recipients[0].Type = "invalidType" 294 295 // encrypt using local jose package 296 jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 297 "", nil, recipients, c) 298 require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys") 299 300 epk, authData, authJSON, err := jweEncrypter.generateEPKAndUpdateAuthDataFor1PU(nil, nil, nil, nil) 301 require.EqualError(t, err, "generateEPKAndUpdateAuthDataFor1PU: newEPK: invalid key type 'invalidType'") 302 require.Empty(t, epk) 303 require.Empty(t, authData) 304 require.Empty(t, authJSON) 305 306 recipients[0].Type = "EC" 307 recipients[0].Curve = "invalid" 308 309 _, _, err = jweEncrypter.newEPK([]byte("")) 310 require.EqualError(t, err, "newEPK: ecEPKAndAlg: getCurve: unsupported curve") 311 } 312 313 func TestBuildCommonAuthDataFailure(t *testing.T) { 314 c, err := tinkcrypto.New() 315 require.NoError(t, err) 316 317 recipients, _ := createRecipients(t, 5) 318 319 recipients[0].Type = "invalid" 320 321 // encrypt using local jose package 322 jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType, 323 "", nil, recipients, c) 324 require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys") 325 326 t.Run("buildCommonAuthData with authData having invalid b64 format", func(t *testing.T) { 327 epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "==Badb64Str$$#^", 328 nil, nil, nil, nil) 329 require.EqualError(t, err, "buildCommonAuthData: authdata decode: illegal base64 data at input byte 0") 330 require.Empty(t, epk) 331 require.Empty(t, authData) 332 require.Empty(t, authJSON) 333 }) 334 335 t.Run("buildCommonAuthData with authData having invalid json format", func(t *testing.T) { 336 epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "badjsonunmarshal", 337 nil, nil, nil, nil) 338 require.EqualError(t, err, "buildCommonAuthData: authData unmarshall: invalid character 'm' looking "+ 339 "for beginning of value") 340 require.Empty(t, epk) 341 require.Empty(t, authData) 342 require.Empty(t, authJSON) 343 }) 344 345 t.Run("buildCommonAuthData with epk having invalid public key type", func(t *testing.T) { 346 epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "eyJ0ZXN0IjoidGVzdCJ9", 347 nil, nil, nil, &cryptoapi.PrivateKey{ 348 PublicKey: cryptoapi.PublicKey{Type: "invalid"}, 349 D: nil, 350 }) 351 require.EqualError(t, err, "buildCommonAuthData: epk marshall: invalid key type") 352 require.Empty(t, epk) 353 require.Empty(t, authData) 354 require.Empty(t, authJSON) 355 }) 356 } 357 358 func TestDecodeAPUAPVFailure(t *testing.T) { 359 t.Run("decodeAPUAPV with recipient APU header as invalid b64 []byte", func(t *testing.T) { 360 _, _, err := decodeAPUAPV(&RecipientHeaders{APU: "=Badb64Str$$#^"}) 361 require.EqualError(t, err, "illegal base64 data at input byte 0") 362 }) 363 364 t.Run("decodeAPUAPV with recipient APV header as invalid b64 []byte", func(t *testing.T) { 365 _, _, err := decodeAPUAPV(&RecipientHeaders{APV: "=Badb64Str$$#^"}) 366 require.EqualError(t, err, "illegal base64 data at input byte 0") 367 }) 368 } 369 370 func TestJWKMarshalEPKFailure(t *testing.T) { 371 t.Run("jwkMarshalEPK with protectedHeadersJSON having 'epk' with invalid json format", func(t *testing.T) { 372 err := jwkMarshalEPK(map[string]json.RawMessage{HeaderEPK: []byte("badjsonunmarshal")}) 373 require.EqualError(t, err, "unable to read JWK: invalid character 'b' looking for beginning of value") 374 }) 375 }