转发 DRM 内容 ID

DRMK 系统驱动程序取消锁定包含受保护内容的音频播放流。 DRMK 实现一个 KS 筛选器,该筛选器采用一个输入流,其中包含已争用数据、取消占用数据,并将未压缩的流馈送到由一些数量的内核驻留模块组成的数据路径中。 这些模块可以是 KS 筛选器或其他类型的驱动程序。 数据路径通常以音频呈现设备结尾,将数字内容转换为可以通过扬声器播放的模拟信号。

在允许未压缩的内容进入数据路径之前,DRMK 会验证数据路径是否安全。 为此,DRMK 对数据路径中的每个模块进行身份验证,从数据路径的上游端的模块开始,并将下游移动到数据路径的另一端。 下图说明了此过程。

diagram illustrating a secure data path.

在上图中,实心箭头表示数据路径,虚线箭头表示验证数据路径是否安全所需的通信。 只有在 DRMK 完成对该路径中的所有模块进行身份验证后,未处理的数据才会进入该路径。

DRMK 对每个模块进行身份验证后,该模块会向 DRMK 提供有关数据路径中下一个模块的信息,以便也可以对其进行身份验证。 在对每个模块进行身份验证时,它接收标识流的 DRM 内容 ID。

从安全数据路径的上游端开始,DRMK 会将内容 ID 转发到模块 A,后者又将内容 ID 转发到模块 B。此过程一直持续到内容 ID 转发到模块 Z(安全数据路径中的最后一个模块)。

下图显示了数据路径中的一对相邻模块。

diagram illustrating forwarding a content id.

上游端的模块调用以下 DRM 函数之一,为 DRMK 提供有关下游模块的信息,并将内容 ID 转发到该模块:

DrmForwardContentToDeviceObject

DrmForwardContentToInterface

DrmAddContentHandlers

其中每个“转发”函数都为 DRMK 提供 DRM 内容 ID,用于标识受保护流,以及 DRMK 需要对下游模块进行身份验证的信息。 要调用的这三个函数中的哪一个取决于两个相邻模块在管理受保护内容的传输时相互通信的接口类型:

  1. 如果上游模块调用 IoCallDriver 与下游模块通信,则下游模块是 WDM 驱动程序的一部分。 在这种情况下,上游模块调用 DrmForwardContentToDeviceObject ,为 DRMK 提供表示下游模块的设备对象。 DRMK 使用设备对象对下游模块进行身份验证。

  2. 如果两个模块通过下游模块实现的 COM 接口进行通信,上游模块将调用 DrmForwardContentToInterface。 此调用为 DRMK 提供了指向下游模块的 COM 接口的指针。 DRMK 只调用此接口中的 IUnknown 方法,并且对其他方法没有假设,尽管这两个模块本身必须就这些方法执行的操作达成一致。 DRMK 验证接口中每个方法的入口点是否属于经过身份验证的模块。 如果入口点分布在多个模块之间,DRMK 会验证所有这些模块。

  3. 如果两个模块既不使用 COM 接口也不使用 IoCallDriver 函数进行通信,上游模块会调用 DrmAddContentHandlers ,以便为 DRMK 提供在下游模块中实现的“内容处理程序”的入口点列表。 DRMK 不调用内容处理程序,也不会对它们执行的函数做出任何假设。 但是,DRMK 确实对入口点所在的模块 (或模块) 进行身份验证。

进行身份验证后,下游模块需要以下信息:

  • 标识包含受保护内容的流的 DRM 内容 ID。 该模块要求此 ID 通知 DRMK 任何模块(进一步下游),该模块计划向其发送受保护内容。

  • 与受保护内容关联的 DRM 内容权限。 模块需要内容权限才能强制实施适当的安全级别。

这三个转发函数中的每一个都以略有不同的方式向模块提供此信息:

  1. DrmForwardContentToDeviceObject 函数将KSPROPERTY_DRMAUDIOSTREAM_CONTENTID set-property 请求发送到下游模块的设备对象。 此请求会将流的内容 ID 和内容权限转发到下游模块。

  2. DrmForwardContentToInterface 函数查询下游模块的 COM 接口以获取 IDrmAudioStream 接口。 如果查询成功,函数将调用 IDrmAudioStream::SetContentId 方法,将内容 ID 和内容权限转发到下游模块。

  3. 对于 DrmAddContentHandlers 函数,调用方 (上游模块) 负责将流的内容 ID 和内容权限转发到下游模块。 DrmAddContentHandlers 返回成功代码指示下游模块已经过身份验证后,上游模块通过调用其内容处理程序之一将内容 ID 和内容权限传递给下游模块。

如果上游模块是 WaveCyclic 或 WavePci 微型端口驱动程序,则可以通过以下方法之一间接调用相应的 DRM 函数:

IDrmPort2::ForwardContentToDeviceObject

IDrmPort::ForwardContentToInterface

IDrmPort2::AddContentHandlers

有关详细信息,请参阅 DRM 函数

为简单起见,前面的讨论假设数据路径中的每个模块都接受来自单个源的流,并将该流转发到最多一个下游模块。 事实上,模块可以将流转发到两个或多个下游模块,但它必须首先通过调用三个转发函数之一对每个下游模块进行身份验证。 同样,模块可以混合多个输入流,但它必须尊重输入流的内容权限,方法是向混合输出流提供适当的保护级别。 有关详细信息,请参阅内容 ID 和内容权限DrmCreateContentMixed 函数的讨论。

典型的安全数据路径由 KMixer 系统驱动程序 组成,后跟表示音频呈现设备的波形筛选器。 该筛选器作为 WaveCyclic 或 WavePci 微型端口驱动程序实现,并结合相应的端口驱动程序。 若要验证数据路径是否安全,DRMK 会将内容 ID 转发到 KMixer,后者又会将内容 ID 转发到筛选器。 实现泛型筛选器功能的端口驱动程序接收内容 ID,并将其转发到微型端口驱动程序。 具体而言,端口驱动程序调用 DrmForwardContentToInterface 函数,将内容 ID 转发到微型端口驱动程序实例化为表示音频呈现设备上的波形输出引脚的流对象。 此调用的参数值之一是指向流对象的 IMiniportWaveCyclicStreamIMiniportWavePciStream 接口的指针。 通过此接口,函数将查询流对象以获取其 IDrmAudioStream 接口,并调用该接口的 SetContentId 方法。

有关详细信息,请参阅 Sysvad 示例驱动程序中 SetContentId 方法的实现,该驱动程序在 示例音频驱动程序中进行了讨论。