async _onDecrypt()

in modules/kms-keyring/src/kms_mrk_keyring.ts [260:367]


    async _onDecrypt(
      material: DecryptionMaterial<S>,
      encryptedDataKeys: EncryptedDataKey[]
    ): Promise<DecryptionMaterial<S>> {
      //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
      //# If the decryption materials (structures.md#decryption-materials)
      //# already contained a valid plaintext data key OnDecrypt MUST
      //# immediately return the unmodified decryption materials
      //# (structures.md#decryption-materials).
      if (material.hasValidKey()) return material

      const { client, keyId, grantTokens } = this

      //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
      //# The set of encrypted data keys MUST first be filtered to match this
      //# keyring's configuration.
      const decryptableEDKs = encryptedDataKeys.filter(filterEDKs(keyId))

      const cmkErrors: Catchable[] = []

      //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
      //# For each encrypted data key in the filtered set, one at a time, the
      //# OnDecrypt MUST attempt to decrypt the data key.
      for (const edk of decryptableEDKs) {
        const { providerId, encryptedDataKey } = edk
        try {
          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# When calling AWS KMS Decrypt
          //# (https://docs.aws.amazon.com/kms/latest/APIReference/
          //# API_Decrypt.html), the keyring MUST call with a request constructed
          //# as follows:
          const dataKey = await decrypt(
            //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
            //# To attempt to decrypt a particular encrypted data key
            //# (structures.md#encrypted-data-key), OnDecrypt MUST call AWS KMS
            //# Decrypt (https://docs.aws.amazon.com/kms/latest/APIReference/
            //# API_Decrypt.html) with the configured AWS KMS client.
            client,
            // For MRKs the key identifier MUST be the configured key identifer.
            { providerId, encryptedDataKey, providerInfo: this.keyId },
            material.encryptionContext,
            grantTokens
          )
          /* This should be impossible given that decrypt only returns false if the client supplier does
           * or if the providerId is not "aws-kms", which we have already filtered out
           */
          needs(dataKey, 'decrypt did not return a data key.')

          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# *  The "KeyId" field in the response MUST equal the configured AWS
          //# KMS key identifier.
          needs(
            dataKey.KeyId === this.keyId,
            '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,
          }

          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# If the response does satisfies these requirements then OnDecrypt MUST
          //# do the following with the response:
          //
          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# *  The length of the response's "Plaintext" MUST equal the key
          //# derivation input length (algorithm-suites.md#key-derivation-input-
          //# length) specified by the algorithm suite (algorithm-suites.md)
          //# included in the input decryption materials
          //# (structures.md#decryption-materials).
          //
          // setUnencryptedDataKey will throw if the plaintext does not match the algorithm suite requirements.
          material.setUnencryptedDataKey(dataKey.Plaintext, trace)
          return material
        } catch (e) {
          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# If this attempt
          //# results in an error, then these errors MUST be collected.
          //
          //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
          //# If the response does not satisfies these requirements then an error
          //# MUST be collected and the next encrypted data key in the filtered set
          //# MUST be attempted.
          cmkErrors.push({ errPlus: e })
        }
      }

      //= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-keyring.txt#2.8
      //# If OnDecrypt fails to successfully decrypt any encrypted data key
      //# (structures.md#encrypted-data-key), then it MUST yield an error that
      //# includes all the collected errors.
      needs(
        material.hasValidKey(),
        [
          `Unable to decrypt data key${
            !decryptableEDKs.length ? ': No EDKs supplied' : ''
          }.`,
          ...cmkErrors.map((e, i) => `Error #${i + 1}  \n${e.errPlus.stack}`),
        ].join('\n')
      )

      return material
    }