安全密钥注入

安全密钥注入支持通过不受信任的客户端将敏感材料从服务器应用程序加密传输到智能卡。 若要使安全密钥注入正常工作,必须执行以下步骤:

  1. 建立加密密钥:

    1. 在服务器与客户端上的智能卡之间使用共享对称密钥。
    2. 在服务器上生成临时对称会话密钥并将其导入智能卡。 会话密钥必须由公钥加密,该公钥具有在智能卡 上生成的相应私钥。
    3. 从共享对称密钥派生会话密钥。 有关详细信息,请参阅 CardGetSharedKeyHandle
    4. 使用 DH 密钥派生。
  2. 服务器上的数据加密:

    1. 数据可以是身份验证数据,例如 PIN。
    2. 数据可以是 RSA/ECC 等非对称密钥对。
  3. 解密客户端上的智能卡中的数据。

下图显示了一个服务器应用程序,该应用程序生成一个密钥,然后跨信任边界安全地将密钥传输到客户端。 收到密钥后,客户端将其导入智能卡。 最后一步是将密钥导入 CA 进行存档。 服务器应用程序和智能卡之间应存在加密通道,客户端应用程序/微型驱动程序应无法访问加密的数据。

概述使用智能卡进行安全密钥注入期间服务器-客户端交互。

若要加密步骤 2 中的密钥,服务器和智能卡需要共享对称密钥。

为了适应在执行安全密钥注入时使用专有格式的现有卡,可以在服务器端加载微型驱动程序,而无需存在卡。 微型驱动程序格式化消息,最后对其进行加密,从而允许在客户端上运行的同一微型驱动程序解密消息。

下图概述了使用微型驱动程序进行服务器/客户端密钥存档。

使用微型驱动程序存档服务器/客户端密钥的概述。

卡键句柄

处理对称密钥时,应使用CARD_KEY_HANDLE来传递密钥句柄。

typedef ULONG_PTR  CARD_KEY_HANDLE;

无卡模式

为了便于使用安装在不受信任的客户端上的同一微型驱动程序来格式化和加密数据的服务器应用程序,可以在不需要存在卡的模式下调用 CardAcquireContext。 通过在 CardAcquireContextdwFlags 参数中设置以下标志来启用此模式。

#define CARD_SECURE_KEY_INJECTION_NO_CARD_MODE  0x1

此设置指示 CardAcquireContext 不要期望任何卡出现在读取器中。 这意味着 不会填充CARD_DATA 中的 ATR 字段,并且 hSCardhSCardCtx 设置为零。

设置此标志后,微型驱动程序只能接受以下函数调用:

安全密钥注入的用例方案

在此示例方案中,客户端应用程序请求从代表智能卡所有者在服务器上运行的 CA 应用程序颁发证书。 CA 还需要密钥存档。 有关使用非对称密钥对建立临时对称会话密钥的指导,请参阅安全密钥注入部分中的脚注。

用户密钥在服务器端生成、存档,然后使用安全密钥注入功能注入到用户的智能卡。 下图演示了该过程。

密钥生成和插入过程。

此方案基于导入使用非对称密钥加密的对称会话密钥,然后使用此对称密钥进行后续密钥包装。

以下步骤描述了上图中所示的过程:

  1. 客户端应用程序从服务器上运行的 CA 应用程序请求新证书。

  2. 当它收到客户端的请求时,服务器应用程序会检测到证书模板已配置为进行密钥恢复。 因此,服务器应用程序启动安全密钥注入协议。

  3. 客户端应用程序为CP_KEY_IMPORT_SUPPORT调用 CardGetProperty 来发现以下内容:

    • 卡是否支持安全密钥注入。
    • 支持哪种对称密钥导入方法。
    • 支持哪些算法。
  4. 微型驱动程序向客户端应用程序指示它通过非对称机制 (CARD_KEY_IMPORT_ASYMMETRIC_KEYEST) 支持密钥注入。

  5. 客户端应用程序查看智能卡的容器映射文件,以查看是否有任何容器对密钥导入有用。 如果未找到任何密钥,客户端应用程序将调用 CardCreateContainer 来生成新的密钥对。

  6. 微型驱动程序指示智能卡创建密钥对。

  7. 创建密钥后,智能卡将密钥返回给微型驱动程序。

  8. 微型驱动程序向客户端应用程序返回指示,指示密钥已生成。

  9. 客户端应用程序现在调用 CardGetContainerInfo 来导出在步骤 6 中创建的密钥对的公钥。

  10. 卡微型驱动程序指示卡返回公钥。

  11. 卡从卡中提取公钥 (K1) ,并将其返回到微型驱动程序。

  12. 微型驱动程序将 K1 返回到客户端应用程序。

  13. 客户端应用程序调用 CardGetProperty 来枚举卡支持的对称算法,并枚举可与 K1 一起使用的填充方案。

  14. 微型驱动程序返回支持的算法和填充模式。

  15. 客户端应用程序将 K1 发送回服务器应用程序,以及描述卡支持的对称密钥算法和填充模式的信息。

  16. 通过使用卡支持的算法之一,服务器应用程序 (S1) 生成对称密钥。 对称密钥 S1 使用 K1 进行加密,并返回到客户端应用程序。 服务器应用程序还返回有关加密算法和用于加密 S1 的填充类型的信息。

  17. 客户端应用程序使用加密密钥数据 BLOB 以及对 K1 的引用以及用于解密 BLOB 的任何填充信息调用 CardImportSessionKey

    有关关键数据 BLOB 的详细信息,请参阅 BCRYPT_KEY_DATA_BLOB_HEADER

  18. 微型驱动程序将加密的 BLOB 数据传递给智能卡进行解密。

  19. 解密对称密钥后,智能卡会将对对称密钥的引用返回到微型驱动程序。

  20. 微型驱动程序将对称密钥的密钥句柄返回到客户端应用程序。

  21. 客户端应用程序向服务器应用程序发送已导入对称密钥的确认。

  22. 服务器应用程序通过调用 MDImportSessionKey 将 S1 导入服务器端微型驱动程序。

  23. 服务器端微型驱动程序返回成功,指示 S1 已成功导入。

  24. 服务器应用程序 (K2) 生成非对称密钥对。 K2 通过调用 MDEncryptData 发送到服务器端微型驱动程序。 服务器应用程序生成 IV 和链接模式,并通过调用 CardSetKeyProperty 将此信息设置为服务器端微型驱动程序。

  25. 服务器端微型驱动程序使用 S1 加密 K2,并将加密的 K2 返回到服务器应用程序。

  26. 服务器应用程序将 encryptedK2 以及与加密相关的任何信息发送到客户端应用程序。 这包括 IV 和链接模式信息。

  27. 客户端应用程序调用 CardSetKeyProperty 来指示微型驱动程序与 S1 一起使用的 IV 和链接模式。 然后,客户端应用程序使用以下数据调用 CardProcessEncryptedData

    • 包含 K2 的加密密钥数据 BLOB。
    • 对 S1 的密钥引用,以便卡可以解密数据并创建密钥。
  28. 微型驱动程序执行准备新密钥容器的必要步骤,并将加密密钥数据 BLOB 提供给智能卡。

  29. 智能卡使用 S1 解密 K2,并为 K2 生成新的密钥容器。 卡返回成功,指示密钥已导入。

  30. 微型驱动程序从 CardProcessEncryptedData 返回成功。

  31. 客户端应用程序返回成功,并且该过程已完成。