- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在编写一个程序,它需要与需要使用 SSL 客户端身份验证的 Web 服务器建立 HTTPS 连接。
此程序的用户将使用来自 windows 环境的证书来验证自己。
我找到了很多展示如何设置客户端身份验证的示例,如果我先将我的证书导出为 pkcs12 格式,它就可以正常工作,但我不想强制我的用户这样做。但是,当我尝试使用 MSCAPI 时,它总是会出现异常:
javax.net.ssl.SSLHandshakeException: Error signing certificate verify
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverHelloDone(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read1(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at com.example.Win2.main(Win2.java:62)
Caused by: java.security.SignatureException: Bad Key.
at sun.security.mscapi.RSASignature.signHash(Native Method)
at sun.security.mscapi.RSASignature.engineSign(RSASignature.java:390)
at java.security.Signature$Delegate.engineSign(Unknown Source)
at java.security.Signature.sign(Unknown Source)
at sun.security.ssl.RSASignature.engineSign(Unknown Source)
at java.security.Signature$Delegate.engineSign(Unknown Source)
at java.security.Signature.sign(Unknown Source)
at sun.security.ssl.HandshakeMessage$CertificateVerify.<init>(Unknown Source)
... 16 more
我真的无法从那个异常中判断出 key 可能有什么问题。
我做了一个小测试程序来重现我遇到的问题:
String passwd = .....";
URL url = new URL("https://.........");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, passwd.toCharArray());
keyManagerFactory.init(keyStore, passwd.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, null);
SSLSocketFactory socketFactory = context.getSocketFactory();
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(socketFactory);
这里的 API 显然有一些我不理解的地方。它怎么知道我想使用 keystore 中的哪个 key ?我原以为 Windows 会提示我,就像它对其他需要身份验证的应用程序所做的那样,但我怀疑它只是选择它找到的第一个应用程序。
我是否需要实现自己的 key 管理器,以便它可以选择要使用的 key ?
如果我遍历 keystore ,我可以看到其中的 key ,并且可以通过调用 getKey 来提取 key 。使事情复杂化的是,商店中有多个具有相同别名(但有效性不同)的 key 。其他(非 Java)应用程序,例如。 Chrome,似乎能够以某种方式确定使用哪些键。
编辑:我忘了说,我使用的是 Java 1.7。
最佳答案
负责选择将使用 keystore 中的哪个 key 的是 KeyManager 对象。您可以获得调用 keyManagerFactory.getKeyManagers() 的那些对象的 vector 。
图书馆通常会获得他们在商店中找到的第一个 key 条目(可能与本例中提供的服务器证书兼容)。 MS-CAPI API 也不异常(exception)。
要在 keystore 中选择要使用的 key ,您应该做 3 件事:
实现接口(interface)X509KeyManager
制作方法chooseClientAlias上述接口(interface)返回所需的别名您的 key
将对象设置为您的 SSLContext。
提醒您,您的 keystore 必须包含从您的个人证书开始到根授权机构的所有证书链。您应该使用 certmgr.msc 程序导入证书和/或检查所有证书是否都存在于文件夹Personal(您的证书)、中间证书颁发机构(您链中的任何中间 CA)和受信任的根证书颁发机构。
设置您的信任 keystore 也很重要 - 它存储您信任的根证书,该存储将用于验证服务器证书。如果是 MS-CAPI,您可以使用 KeyStore.getInstance("Windows-ROOT") 命令获取它(Trusted Root Certification Authorities 文件夹中的证书)。
修改您的代码以完成此操作:
URL url = new URL("https://.........");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null);
keyManagerFactory.init(keyStore);
/* You must also set your trust store */
KeyStore ts = KeyStore.getInstance("Windows-ROOT");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
/* Here you can implement a way to set your key alias
** You can run through all key entries and implement a way
** to prompt the user to choose one - for simplicity I just set a
** name*/
String alias = "user1_alias";
/* Get your current KeyManager from the factory */
final X509KeyManager okm = (X509KeyManager)keyManagerFactory.getKeyManagers()[0];
/* Implement the Interface X509KeyManager */
X509KeyManager km = new X509KeyManager() {
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
/* Implement your own logic to choose the alias
according to the validity if the case,
or use the entry id or any other way, you can get
those values outside this class*/
return alias;
}
public X509Certificate[] getCertificateChain(String alias) {
return okm.getCertificateChain(alias);
}
/* Implement the other methods of the interface using the okm object */
};
SSLContext context = SSLContext.getInstance("TLS");
/* set the keymanager in the SSLContext */
context.init(new KeyManager[]{km}, tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory socketFactory = context.getSocketFactory();
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(socketFactory);
关于java - 如何使用 MSCAPI 提供程序进行客户端 SSL 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20321984/
我正在使用SQL Server 2008 R2,并且想创建一个触发器。 对于每个添加(仅添加),将像这样更新一列: ABC-CurrentYear-AutoIncrementCode 例子: ABC-
是否可以在显示最终一致性的数据存储中创建/存储用户帐户? 似乎不可能在没有一堆架构复杂性的情况下管理帐户创建,以避免可能发生具有相同 UID(例如电子邮件地址)的两个帐户的情况? 最终一致性存储的用户
您好, 我有一个带有 Identity 的 .NetCore MVC APP并使用 this指导我能够创建自定义用户验证器。 public class UserDomainValidator : IU
这与以下问题相同:HiLo or identity? 我们以本站的数据库为例。 假设该站点具有以下表格: 帖子。 投票。 注释。 使用它的最佳策略是什么: 身份 - 这是更常见的。 或者 HiLo -
我想将 Blazor Server 与 ASP.NET Identity 一起使用。但我需要使用 PostgreSQL 作为用户/角色存储,因为它在 AWS 中。 它不使用 EF,这是我需要的。 我创
我正在开发一个 .NET 应用程序,它可以使用 Graph API 代表用户发送电子邮件。 提示用户对应用程序进行授权;然后使用获取的访问 token 来调用 Graph API。刷新 token 用
我使用 ASP.NET 身份和 ClaimsIdentity 来验证我的用户。当用户通过身份验证时,属性 User.Identity 包含一个 ClaimsIdentity 实例。 但是,在登录请求期
所以我在两台机器上都安装了 CYGWIN。 如果我这样做,它会起作用: ssh -i desktop_rsa root@remoteserver 这需要我输入密码 ssh root@remoteser
我尝试在 mac osx 上的终端中通过 telnet 连接到 TOR 并请求新身份,但它不起作用,我总是收到此错误消息: Trying 127.0.0.1... telnet: connect to
我正在开发一个 .NET 应用程序,它可以使用 Graph API 代表用户发送电子邮件。 提示用户对应用程序进行授权;然后使用获取的访问 token 来调用 Graph API。刷新 token 用
我正在开发一项服务,客户可以在其中注册他们的 webhook URL,我将发送有关已注册 URL 的更新。为了安全起见,我想让客户端(接收方)识别是我(服务器)向他们发送请求。 Facebook和 G
在 Haskell 中,有没有办法测试两个 IORef 是否相同?我正在寻找这样的东西: IORef a -> IORef a -> IO Bool 例如,如果您想可视化由 IORef 组成的图形,这
我是 .NET、MVC 和身份框架的新手。我注意到身份框架允许通过注释保护单个 Controller 操作。 [Authorize] public ActionResult Edit(int? Id)
我有一列具有身份的列,其计数为19546542,我想在删除所有数据后将其重置。我需要类似ms sql中的'dbcc checkident'这样的内容,但在Oracle中 最佳答案 在Oracle 12
这是我用来创建 session 以发送电子邮件的代码: props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enabl
我想了解 [AllowAnonymous] 标签的工作原理。 我有以下方法 [HttpGet] public ActionResult Add() { return View(); } 当我没
在使用沙盒测试环境时,PayPal 身份 token 对某些人显示而不对其他人显示的原因是否有任何原因。 我在英国使用 API,终生无法生成或找到 token 。 我已经遵循协议(protocol)并
我对非常简单的事情有一些疑问:IDENTITY。我尝试在 phpMyAdmin 中创建表: CREATE TABLE IF NOT EXISTS typEventu ( typEventu
习语 #1 和 #5 是 FinnAPL Idiom Library两者具有相同的名称:“Progressive index of (without replacement)”: ((⍴X)⍴⍋⍋X⍳
当我第一次在 TFS 中设置时,我的公司拼错了我的用户名。此后他们将其更改为正确的拼写,但该更改显然未反射(reflect)在 TFS 中。当我尝试 checkin 更改时,出现此错误: 有没有一种方
我是一名优秀的程序员,十分优秀!