我遇到了与 OpenSSL 的 CAPI 引擎的冲突问题:在正常情况下,我可以使用存储在智能卡上的私钥通过 OpenSSL 建立 SSL 连接。简化代码:
EVP_PKEY pkey = ENGINE_load_private_key(my_engine, subject_name, 0, 0);
void * pdata = my_certificate_context.pbCertEncoded;
X509 * cert = d2i_X509(0, &pdata, my_certificate_context.cbCertEncoded);
SSL_CTX_use_certificate(my_ssl_context, cert);
SSL_CTX_use_private_key(my_ssl_context, pkey);
但是,有一个问题:如果碰巧我有多个具有给定主题名称的证书,CAPI 引擎将选择其中一个证书,是否选择正确的证书取决于运气。对我来说幸运的是,它选择了错误的一个,这样就提醒了我这个问题。查看源代码,CAPI 引擎似乎支持更复杂的 key 搜索方案,因此我可以指定应该在特定证书存储中找到主题名称。因为我有正确的 PCCERT_CONTEXT,所以我可以很容易地获得证书库的名称,但我不知道如何告诉 CAPI 引擎使用该证书库。这里的文档非常粗略,我找不到一个例子。我希望它可以使用 FENGINE_ctrl_cmd_string 来完成,但我不知道该怎么做。有人可以帮我解决这个问题吗?
最佳答案
经过大量研究和测试,我可以得出结论,可以使用 ENGINE_ctrl_cmd_string 更详细地指定证书的位置:
if (!ENGINE_ctrl_cmd_string(Engine, "store_name", "MY", 0)) printf("Failed!");
if (!ENGINE_ctrl_cmd_string(Engine, "store_flags", "1", 0)) printf("Failed!");
第一行告诉 CAPI 引擎使用不同的证书存储(在本例中为“MY”,但也可以使用任何其他存储,例如“ROOT”)。第二行指示引擎使用本地计算机存储而不是当前用户存储。
但是:
1) 这两个值对于引擎都是全局的。如果需要使用具有不同设置的多个同时连接,每个连接必须有一个单独的引擎。与网络上所写的相反,使用 SSL_CTX_set_client_cert_engine 函数 可能是可能的。在这种情况下,您不需要将引擎设置为默认引擎。 (注意:如果我对两个同时连接使用两个具有不同设置的引擎,我需要对实际发生的情况进行一些测试。到目前为止,它看起来可以工作,但我不确定。)
2) 无法指定当前服务店铺等其他店铺位置。这将需要更新 CAPI 引擎。
3) 无法使用更精确的标识来指定证书,例如通过指定哈希值或序列号。
4) 无论如何指定证书是没有意义的,因为 SSL 引擎将忽略此类指定(实际上任何使用 SSL_CTX_use_certificate 和 SSL_CTX_use_PrivateKey 函数所做的事情)。相反,当执行握手时,它将打开由命令字符串指定的存储并搜索由服务器选择的 CA 签名的证书。我不确定如果找到多个这样的证书会发生什么,我怀疑会向用户显示一个对话框。无论如何,不可能通过代码选择特定的证书,除非你想修改引擎的插件。 (注意:如果您打算在服务器端使用证书,情况可能并非如此。)
5) 使用函数 SSL_CTX_use_certificate 和 SSL_CTX_use_PrivateKey 不仅毫无意义,而且实际上是危险的,因为后者将选择第一个匹配的证书(例如与存储中使用相同的主题名称)并使用它,而不管颁发 CA 或其他任何内容。
此信息对 OpenSSL 的 1.0.2 分支有效。我没有对较新或较旧的分支机构进行任何测试。
关于ssl - OpenSSL 和 CAPI - 证书冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51968387/