oracle SSL:400 没有发送所需的证书

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36284543/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 03:12:02  来源:igfitidea点击:

SSL: 400 no required certificate was sent

javaoraclessl

提问by Alma Do

The code and inputs

代码和输入

I'm trying to establish SSL connection and I'm getting 400 No required SSL certificate was sentresponse from the server. I'm doing this in a standard way like it's described for example here; I run Java 8.

我正在尝试建立 SSL 连接,但收到400 No required SSL certificate was sent了服务器的响应。我正在以标准方式执行此操作,例如此处描述的那样;我运行 Java 8。

The sample of my code would be:

我的代码示例是:

    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;

And here is the code that I use to send GET-request:

这是我用来发送 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();
}

I enabled:

我启用:

System.setProperty("javax.net.debug", "ssl");

So to see debug messages - but there's no errors/warnings/alerts there, the only thing is in the very end:

所以要查看调试消息 - 但那里没有错误/警告/警报,唯一的事情就是最后:

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)

Which is the only thing I can treat as "abnormal" stuff (but I doubt it is).

这是我唯一可以视为“异常”的东西(但我怀疑它是)。

I tried:

我试过:

  • Different protocols disabling/enabling. For instance, forcing TLSv1/ TLSv1.1for the socket with no success. To try that I wrapped my ssl factory into another factory which disables/enables certain protocols.
  • Disabling SSLv2Hello- but it doesn't change the picture.
  • Install Oracle policiesbecause before there were notices about some skipped algorithms and this installation "solved" that but the overall result is still same.
  • Setting System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");- lame, but also didn't change a thing apart from message in the log Allow unsafe renegotiation: true(was "false" obviously)
  • Using KeyManagerFactory.getDefaultAlgorithm()as algorithmfor KeyManagerFactory.getInstance()call. That raises exception Get Key failed: Given final block not properly paddedand as far as I got the idea, it's because of wrong algorithm used (read this). My default algorithm is: SunX509
  • Adding the certificate directly to my machine with keytool -importcert -file /path/to/certificate -keystore keystore.jks -alias "Alias"and then using this in my program via System.setProperty("javax.net.ssl.trustStore","/path/to/keystore.jks");with setting password: System.setProperty("javax.net.ssl.trustStorePassword","mypassword");(I set password in keytoolafter which confirmed trusted certificate with yes); see thisand thisposts. No errors were raised with this - but issue persisted.
  • Adding the certificate to the global keystore (the one located in JAVA_PATH/jre/lib/security/cacerts) with: keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias Alias -file /path/to/certificate(see this); looks like import operation was successful but it didn't change the picture
  • 不同的协议禁用/启用。例如,强制TLSv1/TLSv1.1用于套接字没有成功。为了尝试,我将我的 ssl 工厂包装到另一个禁用/启用某些协议的工厂中。
  • 禁用SSLv2Hello- 但它不会改变图片。
  • 安装Oracle 策略是因为之前有关于一些跳过算法的通知,并且此安装“解决”了该问题,但总体结果仍然相同。
  • 设置System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");- 蹩脚,但除了日志中的消息之外也没有改变任何东西Allow unsafe renegotiation: true(显然是“假”)
  • 使用KeyManagerFactory.getDefaultAlgorithm()algorithmKeyManagerFactory.getInstance()通话。这引发了异常Get Key failed: Given final block not properly padded,据我所知,这是因为使用了错误的算法(阅读本文)。我的默认算法是: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);看到这个这个帖子。没有出现错误 - 但问题仍然存在。
  • 将证书添加到全球密钥库(一个位于JAVA_PATH/jre/lib/security/cacerts)有:keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias Alias -file /path/to/certificate(见); 看起来导入操作成功了,但它并没有改变图片

There's also notice in debug: ssl: KeyMgr: choosing key: 1 (verified: OK)- not sure if it's relevant as I'm not SSL expert.

调试中还有一个注意事项:ssl: KeyMgr: choosing key: 1 (verified: OK)- 不确定它是否相关,因为我不是 SSL 专家。

Unfortunately I can not see the server-side logs so I can't observe the full picture.

不幸的是,我看不到服务器端日志,所以我无法观察全貌。

Question

What can be the reason for this 400 error and how can I progress further (debug/try something else) ? Any tips would be much appreciated.

这个 400 错误的原因是什么,我该如何进一步(调试/尝试其他方法)?任何提示将不胜感激。

回答by Freezer

Your server is asking for a client-side certificate. You need to install a certificate (signed by a trusted authority) on your client machine, and let your program know about it.

您的服务器要求提供客户端证书。您需要在您的客户端机器上安装一个证书(由受信任的机构签署),并让您的程序知道它。

Typically, your server has a certificate (with the key purpose set to "TLS server authentication") signed by either your organization's IT security or some globally trusted CA. You should get a certificate for "TLS client authentication" from the same source.

通常,您的服务器具有由您组织的 IT 安全部门或某个全球信任的 CA 签署的证书(密钥用途设置为“TLS 服务器身份验证”)。您应该从同一来源获得用于“TLS 客户端身份验证”的证书。

If you capture the TLS handshake in Wireshark, you'll see the ServerHello message followed by a "Client Certificate Request", to which you reply with a "Client Certificate" message with length 0. Your server chooses to reject this.

如果您在 Wireshark 中捕获 TLS 握手,您将看到 ServerHello 消息后跟一个“客户端证书请求”,您用长度为 0 的“客户端证书”消息回复该消息。您的服务器选择拒绝此消息。