Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java SunMSCAPI无法识别某些密钥库条目的私钥_Java_Security_Authentication_Ssl_Mscapi - Fatal编程技术网

Java SunMSCAPI无法识别某些密钥库条目的私钥

Java SunMSCAPI无法识别某些密钥库条目的私钥,java,security,authentication,ssl,mscapi,Java,Security,Authentication,Ssl,Mscapi,很抱歉,时间太长了。如果您熟悉用Java进行客户端身份验证,您可能可以浏览/跳到底部。我花了很长时间从不同的来源找到所有相关的信息。也许这会帮助其他人 我正在进行一项概念验证,以使用Windows密钥库从Java客户端获得客户端身份验证。我创建了一个servlet,它可以请求或要求客户端证书。它只返回一个HTML响应,其中包含证书信息,包括主题DN和序列号。我已经用浏览器(主要是Chrome和IE)做了很多实验,以验证它是否正常工作。通过使用SSL生成的证书以及使用公司内部CA颁发的证书,我成功

很抱歉,时间太长了。如果您熟悉用Java进行客户端身份验证,您可能可以浏览/跳到底部。我花了很长时间从不同的来源找到所有相关的信息。也许这会帮助其他人

我正在进行一项概念验证,以使用Windows密钥库从Java客户端获得客户端身份验证。我创建了一个servlet,它可以请求或要求客户端证书。它只返回一个HTML响应,其中包含证书信息,包括主题DN和序列号。我已经用浏览器(主要是Chrome和IE)做了很多实验,以验证它是否正常工作。通过使用SSL生成的证书以及使用公司内部CA颁发的证书,我成功地实现了客户端身份验证

我的下一步是使用Java中的MSCAPI密钥库创建一个Java客户机。我这样做的原因是,我们想要使用的证书是由我们的内部CA颁发的,并且会自动添加到Windows中的个人密钥库中,并标记为不可导出。我知道如果您是工作站的管理员,可以使用一些免费工具从密钥库中取出私钥。由于各种原因,在这种情况下,这不是一个可行的选择。以下是我最终得到的代码:

private static SSLSocketFactory getFactory() throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException 
{
  KeyStore roots = KeyStore.getInstance("Windows-ROOT", new SunMSCAPI());
  KeyStore personal = KeyStore.getInstance("Windows-MY", new SunMSCAPI());

  roots.load(null,null);
  personal.load(null,null);

  TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  tmf.init(roots);

  KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  kmf.init(personal, "".toCharArray());

  SSLContext context = SSLContext.getInstance("TLS");

  context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

  return context.getSocketFactory();
}
这是可行的,但当我连接时,Java客户端正在使用我以前生成的客户端证书进行身份验证。我看不到一个明显的方法来强制选择一个特定的密钥,所以我认为它只是选择了它遇到的主机信任的第一个密钥。然后,我删除了我从windows密钥库创建的这些证书,它将不再进行身份验证。我三次检查服务器端是否仍然可以与浏览器一起使用,并且确实可以。然后,我将这些证书读取到个人密钥库中,并从服务器端删除对我的伪CA的信任。仍然可以在浏览器中工作,而不能在客户端中工作

我在VM参数中添加了-Djavax.net.debug=ssl:handshake,并开始查看输出。我看到的一件事是,对于我添加的每个证书,都有行“为:[别名]找到密钥”,但对于通过certmgr.msc的“自注册”功能添加的证书,则没有。起初我认为这是因为它们是可导出的,但我删除了它们,并添加了一个作为不可导出的,java仍然可以使用它。我不明白为什么SunMSCAPI不会使用这些证书。我和内部CA创建的都是sha256RSA。这两个都启用了客户端身份验证。当我添加以下代码时,我看到isKeyEntry()对于我要使用的所有密钥对都是false:

Enumeration<String> aliases = personal.aliases();

while (aliases.hasMoreElements())
{
  String alias = aliases.nextElement();

  System.out.println(alias + " " + personal.isKeyEntry(alias));
}
枚举别名=personal.alias();
while(别名.hasMoreElements())
{
字符串别名=别名。nextElement();
System.out.println(别名+“”+personal.isKeyEntry(别名));
}
我发现其他人也有类似的问题,但没有明确的答案