Microsoft MSCAPI-CSP 和 CNG 兼容性

Microsoft MSCAPI-CSP and CNG compatibility

我们之前开发了一个 RSA MSCAPI CSP 用于经典 Windows 加密 API 并且多年来一直运行良好。不幸的是,在 AES 加密的情况下,较新版本的 Outlook 拒绝使用此 CSP。它仍然支持 3DES 但不支持 AES。这很奇怪,因为它实际上不是处理对称解密的 CSP,但显然 Microsoft 不想支持 MS-CAPI 的 AES 案例。对于 AES 支持,RSA 密钥需要采用更新的提供程序类型,即符合 CNG 框架的密钥存储提供程序。 好的,但问题是:我如何确保软件依赖于 MS-CAPI 接口的客户端的向后兼容性?
根据我的理解(可能是错误的),证书存储对于 MSCAPI 和 CNG 是相同的。区别在于如何引用私钥。该证书有一个属性 "CERT_KEY_PROV_INFO_PROP_ID",其中包含许多字段,包括提供者名称、容器名称和提供者类型。如果提供商类型为“0”(这在旧 API 中不是合法值),则表明指定的提供商实际上是新的 CNG 提供商之一。

旧应用程序将使用 CERT_KEY_PROV_INFO_PROP_ID 中的值来使用遗留函数(即 CryptAcquireContext())获取加密上下文。但是,在 CNG 提供程序(即提供程序类型 = 0)的情况下,此函数失败 - 此处似乎程序将不得不使用新的 CNG 函数,即 NCryptOpenStorageProvider、NCryptOpenKey 等再次传入来自 CERT_KEY_PROV_INFO_PROP_ID 的值.因此,如果这个 understanding/testing 是正确的,则意味着不可能迁移到 CNG 提供商,并且从遗留应用程序的角度来看仍然有相同的 certificates/keys 工作。我没能在文档中找到明确说明,但似乎每个应用程序都需要查看 CERT_KEY_PROV_INFO_PROP_ID 内容,并有一个开关:如果它是 provider type = 0,这是一个键入 CNG 提供程序,以便程序使用新的 CNG 功能。另一方面,如果提供者类型 > 0,则程序应使用遗留功能。但是,当然,遗留程序不会有这种逻辑,因此在 CNG 提供程序中的密钥的情况下会失败。这意味着不可能同时满足新程序和遗留程序的需求,因为您必须在 CERT_KEY_PROV_INFO_PROP_ID 中添加对遗留提供程序或新提供程序的引用,但您不能同时拥有两者。而且 Outlook 只需要对新提供程序的引用,而旧程序只能与旧提供程序一起使用。

但是真的可以这样吗,还是我漏了什么或者理解有误?微软似乎有多种方法来帮助程序具有某种类型的互操作性(例如,旧程序可以使用旧的 API 来使用新的 KSP)。

据我所知,没有任何解决方案可以完全按照所述解决问题。但是新的 CNG API 提供了一个函数 NCryptTranslateHandle(),程序可以使用该函数将旧式引用从 CERT_KEY_PROV_INFO_PROP_ID 转换为相应 KSP 的句柄。当 KSP 自行注册时,它可以指定一个或多个 "aliases",即它作为别名的经典 MS-CAPI 提供程序的名称。如果一个程序然后从经典的 MS-CAPI CSP 的句柄上调用 NCryptTranslateHandle() 句柄,Windows 将查看是否有已安装的 KSP 已将自己注册为该 CSP 的别名.如果是这样,该句柄将被翻译成相应 CSP 的句柄。然后程序可以继续并在该句柄上使用新的 CNG 函数,这将调用新的提供程序。

那么要做什么:1) 保持证书中的 CERT_KEY_PROV_INFO_PROP_ID 引用现在是什么(即指向旧 CSP),2) 注册一个以旧 CSP 作为别名的 KSP 提供商(不现在我面前有SDK,但它是您可以提供的注册参数之一。如果找不到,请告诉我!)。

对此有点不满意的是,这一切都取决于调用 NCryptTranslateHandle() 句柄的调用程序。一个旧的遗留程序——在 CNG 出现之前编写的——显然不会调用这个函数,因为这个函数在开发时并不存在。但是 Microsoft Outlook(至少是较新的功能)——这是一个非常常见的用例——确实知道调用此功能。因此,如果您提供我在前面段落中描述的双 CSP+KSP 解决方案,它会很好地工作:由于使用了翻译功能,Outlook 最终将通过 KSP API 调用您的解决方案。

实施解决方案时,您应该先编写一个程序对其进行测试,然后再使用 Outlook 进行测试。让程序以老式的方式获取密钥的句柄,然后使用翻译函数并查看您是否获取了句柄,然后在生成的句柄上使用 KSP 函数。