代码和输入
我正在尝试建立 SSL 连接,但我得到了400 No required SSL certificate was sent
来自服务器的响应。我正在以标准方式执行此操作,例如所描述的here https://stackoverflow.com/a/24007536;我运行 Java 8。
我的代码示例是:
OkHttpClient client = new OkHttpClient();
KeyStore keyStoreClient = getClientKeyStore();
KeyStore keyStoreServer = getServerKeyStore();
String algorithm = ALGO_DEFAULT;//this is defined as "PKIX"
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
keyManagerFactory.init(keyStoreClient, PASSWORD_SERVER.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
trustManagerFactory.init(keyStoreServer);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
client.setSslSocketFactory(sslContext.getSocketFactory());
client.setConnectTimeout(32, TimeUnit.SECONDS); // connect timeout
client.setReadTimeout(32, TimeUnit.SECONDS); // socket timeout
return client;
这是我用来发送 GET 请求的代码:
public String get(String url) throws IOException
{
String callUrl = URL_LIVE.concat(url);
Request request = new Request.Builder()
.url(callUrl)
.build();
Response response = this.client.newCall(request).execute();
return response.body().string();
}
我启用了:
System.setProperty("javax.net.debug", "ssl");
因此,要查看调试消息 - 但那里没有错误/警告/警报,唯一的事情是最后:
main, called close()
main, called closeInternal(true)
main, SEND TLSv1.2 ALERT: warning, description = close_notify
main, WRITE: TLSv1.2 Alert, length = 26
main, called closeSocket(true)
这是我唯一可以视为“异常”的东西(但我怀疑它是)。
I tried:
- 禁用/启用不同的协议。例如,强迫
TLSv1
/ TLSv1.1
对于套接字没有成功。为了尝试,我将我的 ssl 工厂包装到另一个工厂中,该工厂禁用/启用某些协议。
- 禁用
SSLv2Hello
- 但这并没有改变图片。
- Install 甲骨文政策 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html因为之前有关于一些跳过算法的通知,并且此安装“解决”了该问题,但总体结果仍然相同。
- Setting
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
- 蹩脚,但除了日志中的消息之外也没有改变任何东西Allow unsafe renegotiation: true
(显然是“假”)
- Using
KeyManagerFactory.getDefaultAlgorithm()
as algorithm
for KeyManagerFactory.getInstance()
称呼。这引发了异常Get Key failed: Given final block not properly padded
据我所知,这是因为使用了错误的算法(阅读this https://stackoverflow.com/a/8053459/2637490)。我的默认算法是:SunX509
- 将证书直接添加到我的机器上
keytool -importcert -file /path/to/certificate -keystore keystore.jks -alias "Alias"
然后在我的程序中使用它System.setProperty("javax.net.ssl.trustStore","/path/to/keystore.jks");
设置密码:System.setProperty("javax.net.ssl.trustStorePassword","mypassword");
(我设置密码keytool
之后确认可信证书yes
); see this https://stackoverflow.com/a/4326346/2637490 and this https://stackoverflow.com/a/5871352/2637490帖子。没有出现任何错误 - 但问题仍然存在。
- 将证书添加到全局密钥库(位于
JAVA_PATH/jre/lib/security/cacerts
) with: keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias Alias -file /path/to/certificate
(see this https://stackoverflow.com/a/27928213/2637490);看起来导入操作成功,但图片没有改变
调试中还注意到:ssl: KeyMgr: choosing key: 1 (verified: OK)
- 不确定它是否相关,因为我不是 SSL 专家。
不幸的是我看不到服务器端日志,所以我无法观察全貌。
Question
出现此 400 错误的原因是什么?我该如何进一步进行(调试/尝试其他方法)?任何提示将不胜感激。