java - Android 服务器应用程序 : SSLHandshakeException (unable to find valid certification path to requested target)

标签 java android ssl ssl-certificate sslhandshakeexception

我正在开发一个 Android 应用程序,需要使用我自己的 SSL 证书提供一个 SSL 保护的 TCP 服务器。 我有以下文件:

  • 服务器.crt
  • server.key(私有(private))
  • 我的ca.crt

1)证书创建:
如本 SO 中所述,我使用命令行工具“keytool”从 mycert.pem 创建 BKS-keystore。将它放在我的应用程序的/res/raw 文件夹中,但我不确定如何处理私钥,我不需要它来创建证书,对吗?

2) 服务器代码:

String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
KeyStore.load(context.getResouces().openRawResource(R.raw.mykeystore), "mypass".toCharArray();

String keyalg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyalg);
kmf.init(keyStore, "mypass".toCharArray());


SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
SSLServerSocket serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(3333);

SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();

//not shown: create BufferedReader from sslSocket.getInputStream(), while-loop for incoming messages

3)客户端代码:
我写了一个包含这段代码的虚拟 Java 客户端:

SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.168.2.101", 3333);
sslsocket.startHandshake();

然后通过调用运行它:

java -Djavax.net.ssl.trustStore=keystore -Djavax.net.ssl.trustStorePassword=password client passing the same keystore I've created for my server.

当调用 startHandshake() 时,客户端抛出 SSLHandshakeException,提示“PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径”。

对于客户端和服务器,我使用仅包含 server.crt 文件的相同 keystore 。这可能是问题的根源吗?我是否必须使用私钥 (server.key) 和/或 ca-cert 才能完成这项工作?还有其他建议吗?

非常感谢任何帮助。提前致谢。

最佳答案

我想我已经明白了。这很麻烦,所以如果有人遇到同样的问题,这就是完成后的结果。 我创建了一个新的 pkcs12 keystore ,通过调用添加 server.crt、server.key 和 ca.crt:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out server.p12 -name server -CAfile cacert.pem -caname root

Android 只接受 BKS 文件,所以我需要转换它。使用工具 portecle 的直接转换不起作用,因为 pkcs12 到 bks 需要 bouncy caSTLe 1.5,但 android 仅支持 bouncy caSTLe 1.46。所以我下载了两个版本的充气城堡。首先,我添加了 1.5 版并将 pkcs12 转换为 JRE 文件(该文件有 SO 答案)。

然后我将 1.5 版替换为 1.46 版,并再次使用 portecle 将 JRE 转换为 BKS。

之后你只需要将keystore添加到Android的/res/raw目录下,如上代码所示使用即可。

希望这对某人有帮助。

关于java - Android 服务器应用程序 : SSLHandshakeException (unable to find valid certification path to requested target),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25094186/

相关文章:

java - 400(错误请求)错误 - 使用 JQuery AJAX 的 Spring-boot 文件上传

java - 我怎样才能得到位的位置

c# - Unity Google VR - 从安卓设备获取旋转、偏航和俯仰值

iOS 添加受信任的根证书 - 公共(public)还是私有(private)?

ssl - Rundeck gmail smtp设置

java - 从线程获取InputObjectStream

java - 将元素添加到 List<Map.Entry<Integer,Integer>>

java - window.clearFlags(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) 无法从 fragment 内部工作

android - 开始 Activity 时延迟

ssl - simplehtmldom - SSL 操作失败,代码为 1。OpenSSL 错误消息