async _onDecrypt()

in modules/kms-keyring/src/kms_keyring.ts [231:310]


    async _onDecrypt(
      material: DecryptionMaterial<S>,
      encryptedDataKeys: EncryptedDataKey[]
    ) {
      const keyIds = this.keyIds.slice()
      const { clientProvider, generatorKeyId, grantTokens } = this
      if (generatorKeyId) keyIds.unshift(generatorKeyId)

      /* If there are no key IDs in the list, keyring is in "discovery" mode and will attempt KMS calls with
       * every ARN it comes across in the message. If there are key IDs in the list, it will cross check the
       * ARN it reads with that list before attempting KMS calls. Note that if caller provided key IDs in
       * anything other than a CMK ARN format, the Encryption SDK will not attempt to decrypt those data keys, because
       * the EDK data format always specifies the CMK with the full (non-alias) ARN.
       */
      const decryptableEDKs = encryptedDataKeys.filter(filterEDKs(keyIds, this))

      const cmkErrors: Catchable[] = []

      for (const edk of decryptableEDKs) {
        let dataKey: RequiredDecryptResponse | false = false
        try {
          dataKey = await decrypt(
            clientProvider,
            edk,
            material.encryptionContext,
            grantTokens
          )
        } catch (e) {
          /* Failures onDecrypt should not short-circuit the process
           * If the caller does not have access they may have access
           * through another Keyring.
           */
          cmkErrors.push({ errPlus: e })
        }

        /* Check for early return (Postcondition): clientProvider may not return a client. */
        if (!dataKey) continue

        /* Postcondition: The KeyId from KMS must match the encoded KeyID. */
        needs(
          dataKey.KeyId === edk.providerInfo,
          'KMS Decryption key does not match the requested key id.'
        )

        const flags =
          KeyringTraceFlag.WRAPPING_KEY_DECRYPTED_DATA_KEY |
          KeyringTraceFlag.WRAPPING_KEY_VERIFIED_ENC_CTX
        const trace: KeyringTrace = {
          keyNamespace: KMS_PROVIDER_ID,
          keyName: dataKey.KeyId,
          flags,
        }

        /* Postcondition: The decrypted unencryptedDataKey length must match the algorithm specification.
         * See cryptographic_materials as setUnencryptedDataKey will throw in this case.
         */
        material.setUnencryptedDataKey(dataKey.Plaintext, trace)
        return material
      }

      /* Postcondition: A CMK must provide a valid data key or KMS must not have raised any errors.
       * If I have a data key,
       * decrypt errors can be ignored.
       * However, if I was unable to decrypt a data key AND I have errors,
       * these errors should bubble up.
       * Otherwise, the only error customers will see is that
       * the material does not have an unencrypted data key.
       * So I return a concatenated Error message
       */
      needs(
        material.hasValidKey() ||
          (!material.hasValidKey() && !cmkErrors.length),
        cmkErrors.reduce(
          (m, e, i) => `${m} Error #${i + 1} \n ${e.errPlus.stack} \n`,
          'Unable to decrypt data key and one or more KMS CMKs had an error. \n '
        )
      )

      return material
    }