如何使用 Java 从 Windows (MSCAPI) 上的智能卡获取用户身份?

Posted

技术标签:

【中文标题】如何使用 Java 从 Windows (MSCAPI) 上的智能卡获取用户身份?【英文标题】:How to obtain a user's identity from a smartcard on Windows (MSCAPI) with Java? 【发布时间】:2013-03-05 10:05:50 【问题描述】:

我想使用 Sun 的 MSCAPIProvider 从 Windows 上的 Java 胖客户端的智能卡 (PKI) 获取用户的身份。目标是:

    用户打开应用 提示卡 提示输入 PIN 码 我得到了 Java 中的 X509Certicate 授予访问权限等

我根据this*** 问题示例找到了我商店中的所有证书,我可以使用 Microsoft 智能卡提供程序 PIN 提示符对一些字节进行签名。

这是我的代码:

Provider provider = Security.getProvider("SunMSCAPI");
KeyStore store = KeyStore.getInstance("Windows-MY", provider);
store.load(null, null);

System.out.println(store);
Enumeration<?> aliases = store.aliases();
while(aliases.hasMoreElements()) 
    String alias = aliases.nextElement().toString();
    Certificate[] signerKey = (Certificate[]) store.getCertificateChain(alias);
    Object entry = store.getKey(alias, null);
    System.out.println(alias + " " + Arrays.toString(signerKey));
    System.out.println(entry);


Signature sig = Signature.getInstance("SHA1withRSA",provider);
PrivateKey key = (PrivateKey) store.getKey("Michael-O", null);

sig.initSign(key);
sig.update("Test".getBytes());
System.out.println(Arrays.toString(sig.sign()));

现在我面临两个问题:

    我不知道他的别名可能是什么(chicken-egg-problem) 如何使用 X509Cert 强制 PIN 授权,从而通过 HTTPS 建立 SSL 上下文?

缺少哪些位?

【问题讨论】:

您是否尝试过从商店请求所有密钥来过滤掉别名?您是否尝试过添加CallbackHandler? 1. PrivateKey entry = (PrivateKey) store.getKey(alias, null); 在一个循环中。使用卡,钥匙不打印。当我把卡放进去时,钥匙就列出来了。下次运行时移除卡让我要求它。任何时候都不会要求我输入我的 PIN 码。 2. 当我 1. 不知道别名,2. 想要使用 MS 智能卡提供程序而不是自定义对话框时,CallbackHandler 将如何帮助我? 您可以使用aliases()isKeyEntry() 从KeyStore 请求所有密钥别名,也许这将有助于检索密钥?至于CallbackHandler,是否得到PIN提示可能取决于智能卡附带的软件的实现。我没有看到您要使用提供商的密钥提示的任何要求(我个人不希望在应用程序之外出现 PIN 提示 - 我想知道我使用密钥的目的,但这是个人喜好)。跨度> 但这真的是一个通过枚举交互的解决方案吗? 嗯,从逻辑上讲,如果您无法注册某种类型的侦听器来获得回叫,那么您可以做的就是轮询(如果轮询结果不准确,则检索更多信息)够了)。 【参考方案1】:

对于 Windows 情况,通常智能卡供应商提供两个驱动程序。

使用 PKCS11 协议访问和使用智能卡签名。 另一个使用 Windows 加密服务提供程序(又名 CSP)访问和签名

当您使用SunMSCAPI 提供程序时,您可以访问本地用户windows 密钥库以及是否安装了一些CSP 智能卡驱动程序;您还可以通过它查看智能卡证书(但您无法知道本地和智能卡证书之间的区别,因为 Windows 密钥库充当接口)。

如果您尝试通过 sunMSCAPI 访问智能卡的公共证书,则您访问的是公共密钥,因此无需引入 PIN。但是,如果您尝试执行签名,则 Windows 密钥库会将操作委托给智能卡 CSP,这将提示您输入 PIN

现在尝试回答您的两个具体问题:

    我不知道他的别名可能是什么(chicken-egg-problem)

一个选项可以是在弹出窗口中打印所有证书(例如主题或序列号)的信息(保持别名和您显示的描述之间的关系),让用户选择要使用的证书,然后在内部选择您可以使用别名来引用所选证书;这就像任何https 身份验证在需要客户端身份验证时起作用;浏览器向您显示可能的证书进行身份验证。

https 中,您可以在服务器中创建一些过滤器以仅显示符合某些条件的证书(例如,您可以从某些条件过滤证书;例如为特定 CA 颁发的证书),但最终用户必须选择所需的进行身份验证。

您还可以执行某种过滤器,例如从密钥库获取证书属性或证书链,并仅显示您认为符合要求的那些...但最后,如果您在过滤器之后有多个ve 让用户决定要选择哪一个。

    如何使用 X509Cert 强制 PIN 授权 通过 HTTPS 建立 SSL 上下文?

如果您通过 sunMSCAPI 提供商将私钥访问操作委托给智能卡CSP,我认为您可以不关心 PIN em>,让 CSP 为您处理。

如果由于某种原因您需要保留 PIN,那么一个可能的选择是使用不同的提供商 (SunPKCS11) 直接实例化智能卡(而不是通过 CSP)并使用CallbackHandler(正如@Maarten Bodewes 在cmets 中建议的那样)来处理它。但是恕我直言,如果在这种情况下所有客户端都在 Windows 上,我建议您使用 sunMSCAPI,以避免来自某些不同智能卡的不同 PKCS11 驱动程序实现出现问题。

【讨论】:

以上是关于如何使用 Java 从 Windows (MSCAPI) 上的智能卡获取用户身份?的主要内容,如果未能解决你的问题,请参考以下文章