验证证书链

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

本主题介绍如何在使用认证输出保护协议 (COPP) 时验证驱动程序的证书链。

图形驱动程序的证书链是 XML 文档。 证书链包含三个证书。 第一个证书称为 叶证书,是驱动程序的 COPP 证书。 下一个证书是独立硬件供应商 (IHV) 的签名证书。 最后一个证书是 Microsoft 的签名证书。 为了确保图形驱动程序是合法的 COPP 设备,应用程序必须验证这三个证书。 如果应用程序未正确验证链中的证书,恶意程序可能会阻止 COPP 正常工作。

COPP 证书链使用 UTF-8 字符集。 证书中的二进制数据(如 RSA 公钥)采用 base64 编码并按 big-endian 顺序存储。 (Big-endian 表示最重要的字节存储在具有最低地址的内存位置中。)

证书中的某些元素包含布尔值,表示存在证书的功能。 如果特征存在,则相应的子元素值设置为 1。 如果功能不存在,则证书中不存在该子元素。

XML 元素定义

下面是证书架构中元素的定义:

  • CertificateCollection。 XML 文档的根元素。 它包含 Certificate 元素,链中的每个证书对应一个元素。
  • 证书。 包含一个证书。 此元素包含 Data 和 Signature 元素。
  • 数据。 包含有关证书的信息。 具体而言,它包含证书的公钥和类型。 Data 元素包含以下子元素:
    • PublicKey。 包含证书的 RSA 公钥。 PublicKey 元素包含 KeyValue 元素,其中包含 RSAKeyValue 元素。 RSAKeyValue 元素有两个子元素,Modulus 和 Exponent,它们定义了公钥。 Modulus 和 Exponent 元素采用 base64 编码,并按 big-endian 顺序存储。
    • KeyUsage。 如果证书是驱动程序的 COPP 证书,则此元素应包含名为 EncryptKey 的子元素。 如果证书是 IHV 的签名证书或 Microsoft 的签名证书,则它应包含名为 SignCertificate 的子元素。 这两个子元素都包含布尔值。
    • SecurityLevel。 应忽略此元素。
    • ManufacturerData。 指定图形设备的制造商和型号。 此元素仅供信息使用。
    • Features。 包含指定证书用法的子元素。 唯一与 COPP 相关的是 COPPCertificate 元素。 可能存在其他子元素;如果是这样,则应忽略它们。 如果 COPPCertificate 元素存在,则证书是 COPP 证书。 此元素必须存在于有效 COPP 证书的叶节点中。 此元素包含一个布尔值。
  • 签名。 包含此证书的签名。 它包含以下子元素:
    • SignedInfo。 包含有关签名的信息。 此元素的重要子元素是 DigestValue 元素,它包含 Data 元素上的 SHA-1 哈希的 base64 编码值。 根据 CRL) (证书吊销列表检查证书时,将使用摘要值。
    • SignatureValue。 此值通过 Data 元素计算,并根据Public-Key加密标准 (PKCS) #1 (2.1 版) 中定义的 RSASSA-PSS 数字签名方案进行计算。 有关 PKCS #1 的信息,请访问 https://www.rsa.com/
    • KeyInfo。 包含链中下一个证书的 RSA 公钥。 此元素用于验证 Data 元素中的数据是否未被篡改。 此元素的格式与 PublicKey 元素相同。

证书验证

应用程序必须执行以下步骤才能正确验证证书链。 如果任何步骤失败,或者这些过程中引用的任何元素不存在,则验证将失败。

验证证书收集过程

若要验证证书链,请执行以下步骤:

  1. 验证 CertificateCollection 是格式正确的 XML。
  2. 验证 CertificateCollection 是否以 UTF-8 格式编码。
  3. 检查 CertificateCollection 元素中的 Version 属性是否为 2.0 或更高版本。
  4. 验证证书链是否正好包含三个 Certificate 元素。
  5. 循环访问证书链中的每个 Certificate 元素,并在每个元素上执行下面所述的验证证书过程。

验证证书过程

若要验证链中的证书,请执行以下步骤:

  1. 验证 Data 元素中的子元素是否没有重复。 例如,应只有一个 PublicKey 元素。
  2. 确保 Data/PublicKey/KeyValue/RSAKeyValue/Modulus 元素存在。 对于除根证书之外的所有证书,base64 解码的值的长度必须为 256 字节。 在根证书中,此元素的长度必须为 128 字节。
  3. 确保 Data/PublicKey/KeyValue/RSAKeyValue/Exponent 元素存在。 base64 解码值不能大于 4 个字节。
  4. 如果此证书是叶证书,请验证以下内容:
    • KeyUsage 元素包含值为 1 的 EncryptKey 元素。
    • Features 元素包含值为 1 的 COPPCertificate 元素。
  5. 如果此证书不是叶证书,请验证以下事项:
    • Data/PublicKey 元素的模数和指数与上一个证书的 Signature/KeyInfo 元素中的模数和指数完全匹配。
    • KeyUsage 元素包含值为 1 的 SignCertificate 元素。
  6. 使用 SHA-1 哈希算法对证书的 Data 元素中的每个字节进行哈希处理。 从 Data 标记中的<第一个字符到结束 </Data> 标记中最后一个字符的每个字节都应进行哈希>处理。 哈希值用于根据证书吊销列表 (CRL) 检查证书吊销列表,如证书吊销列表中所述
  7. 将步骤 6 中的哈希值与 Signature/SignedInfo/Reference/DigestValue 元素的 base64 解码值进行比较。 这些值必须匹配。
  8. 执行下面所述的验证签名过程。
  9. 如果此证书不是链中的最终证书,请保存 Signature/KeyInfo/KeyValue/RSAKeyValue 值以供循环的下一次迭代使用。
  10. 如果此证书是链中的最终证书,请确保 Signature/KeyInfo/KeyValue/RSAKeyValue 的值与 Microsoft 的公钥匹配。 Microsoft 公钥具有以下 base64 编码值:
    • 模:

      pjoeWLSTLDonQG8She6QhkYbYott9fPZ8tHdB128ZETcghn5KHoyin7HkJEcPJ0Eg4UdSv a0KDIYDjA3EXd69R3CN2Wp/QyOo0ZPYWYp3NXpJ700tKPgIplzo5wVd/69g7j+j8M66W7V NmDwaNs9mDc1p2+VVMsDhOsV/Au6E+E=

    • 指数: AQAB

验证签名过程

SignatureValue 元素的值根据 PKCS #1 版本 2.1 中定义的 RSASSA-PSS 数字签名方案通过 Data 元素计算, (以下称为 PKCS) 。 若要验证此签名,请执行以下步骤:

  1. 解码 Signature/KeyInfo/KeyValue/RSAKeyValue 元素中的模值和指数值。 这些值定义签名证书的 RSA 公钥。
  2. 解码 Signature/SignatureValue 元素。
  3. 计算在 PKCS 的第 8.1.2 节中定义的 RSASSA-PSS-Verify 操作。

对于 RSASSA-PSS-Verify 操作,请使用以下输入:

  • (ne) 是步骤 1 中的公钥。
  • M 是 Data 元素中的所有字节,包括包含元素的 <Data> 和 </Data> 标记。
  • S 是步骤 2 中的解码签名值。

RSASSA-PSS-Verify 操作使用第 9.1.1 节中定义的 EMSA-PSS-ENCODE 操作。 PKCS 的 。 对于此操作,COPP 使用以下选项:

  • 哈希 = SHA-1
  • hLen = 20
  • MGF (掩码生成函数) = MGF1
  • sLen = 0

掩码生成函数 MGF1 在 PKCS 的附录 B.2 中定义。 对于此函数,COPP 使用以下选项:

  • 哈希 = SHA-1
  • hLen = 20

RSASSA-PSS-Verify 操作的输出指示签名是有效还是无效。

使用认证输出保护协议 (COPP)