in modules/kms-keyring/src/kms_mrk_discovery_keyring.ts [178:307]
async _onDecrypt(
material: DecryptionMaterial<S>,
encryptedDataKeys: EncryptedDataKey[]
): Promise<DecryptionMaterial<S>> {
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-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
// See the constructor, this is to support both AWS SDK v2 and v3.
needs(
typeof this.clientRegion === 'string' ||
/* Precondition: AWS SDK V3 region promise MUST have resolved to a string.
* In the constructor the region promise resolves
* to the same value that is then set.
*/
// @ts-ignore
typeof (await this.clientRegion) == 'string',
'clientRegion MUST be a string.'
)
const { client, grantTokens, clientRegion } = this
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-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(this))
const cmkErrors: Catchable[] = []
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-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) {
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
//# Otherwise it MUST
//# be the provider info.
let keyId = edk.providerInfo
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
//# * "KeyId": If the provider info's resource type is "key" and its
//# resource is a multi-Region key then a new ARN MUST be created
//# where the region part MUST equal the AWS KMS client region and
//# every other part MUST equal the provider info.
const keyArn = parseAwsKmsKeyArn(edk.providerInfo)
needs(keyArn, 'Unexpected EDK ProviderInfo for AWS KMS EDK')
if (isMultiRegionAwsKmsArn(keyArn)) {
keyId = constructArnInOtherRegion(keyArn, clientRegion)
}
let dataKey: RequiredDecryptResponse | false = false
try {
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-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:
dataKey = await decrypt(
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-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,
{
providerId: edk.providerId,
providerInfo: keyId,
encryptedDataKey: edk.encryptedDataKey,
},
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
*/
if (!dataKey) continue
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
//# * The "KeyId" field in the response MUST equal the requested "KeyId"
needs(
dataKey.KeyId === 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-region-discovery-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).
//
//= compliance/framework/aws-kms/aws-kms-mrk-aware-symmetric-region-discovery-keyring.txt#2.8
//# Since the response does satisfies these requirements then OnDecrypt
//# MUST do the following with the response:
//
// 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-region-discovery-keyring.txt#2.8
//# If the response does not satisfies these requirements then an error
//# is 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-region-discovery-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 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
}