async _onEncrypt()

in modules/kms-keyring/src/kms_keyring.ts [156:229]


    async _onEncrypt(material: EncryptionMaterial<S>) {
      /* Check for early return (Postcondition): Discovery Keyrings do not encrypt. */
      if (this.isDiscovery) return material

      const keyIds = this.keyIds.slice()
      const { clientProvider, generatorKeyId, grantTokens } = this
      if (generatorKeyId && !material.hasUnencryptedDataKey) {
        const dataKey = await generateDataKey(
          clientProvider,
          material.suite.keyLengthBytes,
          generatorKeyId,
          material.encryptionContext,
          grantTokens
        )
        /* Precondition: A generatorKeyId must generate if we do not have an unencrypted data key.
         * Client supplier is allowed to return undefined if, for example, user wants to exclude particular
         * regions. But if we are here it means that user configured keyring with a KMS key that was
         * incompatible with the client supplier in use.
         */
        if (!dataKey)
          throw new Error('Generator KMS key did not generate a data key')

        const flags =
          KeyringTraceFlag.WRAPPING_KEY_GENERATED_DATA_KEY |
          KeyringTraceFlag.WRAPPING_KEY_SIGNED_ENC_CTX |
          KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY
        const trace: KeyringTrace = {
          keyNamespace: KMS_PROVIDER_ID,
          keyName: dataKey.KeyId,
          flags,
        }

        material
          /* Postcondition: The generated unencryptedDataKey length must match the algorithm specification.
           * See cryptographic_materials as setUnencryptedDataKey will throw in this case.
           */
          .setUnencryptedDataKey(dataKey.Plaintext, trace)
          .addEncryptedDataKey(
            kmsResponseToEncryptedDataKey(dataKey),
            KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY |
              KeyringTraceFlag.WRAPPING_KEY_SIGNED_ENC_CTX
          )
      } else if (generatorKeyId) {
        keyIds.unshift(generatorKeyId)
      }

      /* Precondition: If a generator does not exist, an unencryptedDataKey *must* already exist.
       * Furthermore *only* CMK's explicitly designated as generators can generate data keys.
       * See cryptographic_materials as getUnencryptedDataKey will throw in this case.
       */
      const unencryptedDataKey = unwrapDataKey(material.getUnencryptedDataKey())

      const flags =
        KeyringTraceFlag.WRAPPING_KEY_ENCRYPTED_DATA_KEY |
        KeyringTraceFlag.WRAPPING_KEY_SIGNED_ENC_CTX
      for (const kmsKey of keyIds) {
        const kmsEDK = await encrypt(
          clientProvider,
          unencryptedDataKey,
          kmsKey,
          material.encryptionContext,
          grantTokens
        )

        /* clientProvider may not return a client, in this case there is not an EDK to add */
        if (kmsEDK)
          material.addEncryptedDataKey(
            kmsResponseToEncryptedDataKey(kmsEDK),
            flags
          )
      }

      return material
    }