当前位置: 首页 > 知识库问答 >
问题:

Android w/javax上的相互身份验证失败。网ssl。SSLHandshakeException:握手失败

赏开宇
2023-03-14

我正在尝试获得一个在android上工作的相互认证请求。我正在测试我自己的服务器,所以我有一个自签名的CA和客户端证书。

因此,我将不得不考虑不受信任的服务器证书。

以下是我正在做的:

KeyStore clientCertificate = KeyStore.getInstance("PKCS12");
InputStream client_inputStream = getResources().openRawResource(R.raw.client);
clientCertificate.load(client_inputStream, "password".toCharArray());
new SSLRequest(clientCertificate).execute();

然后使用AsyncWork来执行请求:

class SSLRequest extends AsyncTask<Void, Void, Void> {

    private Exception exception;
    private KeyStore clientCertificate;

    public SSLRequest(KeyStore clientCertificate) {
        this.clientCertificate = clientCertificate;
    }

    protected Void doInBackground(Void... params) {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
            SSLSocketFactory sf = new SSLSocketFactory(clientCertificate, null, trustStore);

            HttpParams httpParameters = new BasicHttpParams();
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schemeRegistry.register(new Scheme("https", sf, 443));
            ClientConnectionManager cm = new SingleClientConnManager(httpParameters, schemeRegistry);

            DefaultHttpClient httpClient = new DefaultHttpClient(cm, httpParameters);

            HttpGet request = new HttpGet("https://myserver.com/some.json");
            HttpResponse response = httpClient.execute(request);
            response.getEntity().consumeContent();
        } catch (Exception e) {
            this.exception = e;
        }

        return null;
    }

    protected void onPostExecute(Void params) {
        if (exception != null) {
            status.setText("Error making SSL handshake");
        } else {
            status.setText("Successful SSL handshake");
        }
    }
}

我已经在浏览器和iOS客户端上测试了这个请求,但我无法在Android上运行它。

我认为这是允许不受信任的服务器证书的正确方法:

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactory(clientCertificate, "password", trustStore);

不知道为什么我得到:

javax.net.ssl.SSLPeerUn验证异常

编辑:

我必须添加自己的SSLSocketFactory以信任自签名服务器证书:

public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(keystore, keystorePassword, truststore);

        TrustManager trustManager = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] {trustManager}, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

一旦我使用它,我会得到以下结果:

javax。网ssl。SSLHandshakeException:握手失败

编辑2:

我在Lollipop和使用apache作为我的网络服务器。我的apache Web服务器配置有:

#   SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect.  Disable SSLv2 access by default:
SSLProtocol all -SSLv2 -SSLv3

#   SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"

这可能是我的问题:在Android5.0Lollipop中,HttpClient因握手失败而失败

不太确定我需要改变什么。我已经找遍了,这似乎是推荐配置(目前)。

编辑3:

以下是完整的堆栈跟踪:

06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ javax.net.ssl.SSLHandshakeException: Handshake failed
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:390)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:75)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:88)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:175)
06-01 13:23:14.369  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:111)
06-01 13:23:14.371  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:134)
06-01 13:23:14.371  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
06-01 13:23:14.371  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
06-01 13:23:14.371  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at mil.nga.giat.handshake.HandshakeActivity$SSLRequest.doInBackground(HandshakeActivity.java:115)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at mil.nga.giat.handshake.HandshakeActivity$SSLRequest.doInBackground(HandshakeActivity.java:85)
06-01 13:23:14.372  24486-24571/mil.nga.giat.handshake W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:292)
06-01 13:23:14.373  24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-01 13:23:14.373  24486-24571/mil.nga.giat.handshake W/System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
06-01 13:23:14.373  24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-01 13:23:14.373  24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-01 13:23:14.374  24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.lang.Thread.run(Thread.java:818)
06-01 13:23:14.374  24486-24571/mil.nga.giat.handshake W/System.err﹕ Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0xa21b8800: Failure in SSL library, usually a protocol error
06-01 13:23:14.374  24486-24571/mil.nga.giat.handshake W/System.err﹕ error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1303 0xb4b57be0:0x00000003)
06-01 13:23:14.375  24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
06-01 13:23:14.375  24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318)

共有2个答案

宋高谊
2023-03-14

我正在尝试获得一个在android上工作的相互身份验证请求。。。

(注释)设备上没有安装服务器CA。不一定是这样。只有客户端证书需要在那里完成握手。这就是为什么我加载了一个空信任库来允许不可信的服务器证书。

好的,最简单的解决方案是在设备上安装CA。我知道你不想那样做,我也不真的怪你。这不是最好的解决方案,因为它会将您的CA与CA Zoo中的其他CA混合使用。

既然您是以编程方式完成这一切的,那么我相信这就是您的解决方案:直接在文件系统上使用PEM编码的CA证书来处理HTTPS请求?。客户端将使用您的CA验证服务器证书,然后继续使用客户端证书。不需要在设备上安装CA。

另一种选择是定制的TrustManager。但我更喜欢让系统执行检查,而不是覆盖行为和检查。您必须执行很多检查,而且这些检查很容易出错。对于初学者来说,您必须知道要进行哪些RFC才能确定这些检查是什么。

我将使用自定义的TrustManager进行公钥锁定。有很多这样的例子;例如,请参见OWASP站点上的证书和公钥固定。您可以使用钉住并放弃支票,因为您不需要授予信任。您可以使用公钥X与预期的服务器通信;或者你不知道——第三方怎么说也不重要(比如CA)。

还要注意Java和Android的SSLFactory有一些问题,比如getInstance(“TLS”)也会返回SSLv3;TLS 1.1和1.2将被禁用。要解决此问题,请参阅为SSL套接字启用哪些密码套件?。

与您的编辑相关:

SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256
    EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL
    !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"

这通常很好:

HIGH:!aNULL:!kRSA:!MD5:!RC4:!SRP:!PSK

HIGH将为您提供所有强大功能(大约112位及以上的安全性)。

!aNULL删除匿名协议,并!kRSA删除密钥传输(但不是RSA签名),因此剩下整数和椭圆曲线Diffie-Hellman。您可以在下面看到使用Au=RSA进行RSA签名的示例。

HIGH也会给你带来一些虚弱/受伤的积垢,比如MD5RC4,所以你可以明确地移除它们。您还可以删除不需要的密码套件,如SRPPSK

您可以使用openssl密码-v'HIGH:!阿努尔:!克尔萨:!MD5:!RC4:!SRP:!PSK'

$ openssl ciphers -v 'HIGH:!aNULL:!kRSA:!MD5:!RC4:!SRP:!PSK'
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
...

顺便说一下,这是你的绳子。总而言之,我觉得它看起来不错。RC4将从某些浏览器中为您提供过时的加密警告。把它扔了吧,因为分组密码中的填充预言是固定的(再次…)。

$ openssl ciphers -v 'EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384: \
EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS'
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
ECDHE-RSA-RC4-SHA       SSLv3 Kx=ECDH     Au=RSA  Enc=RC4(128)  Mac=SHA1
ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
ECDHE-RSA-AES128-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA1
ECDHE-ECDSA-AES128-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA1
ECDHE-ECDSA-RC4-SHA     SSLv3 Kx=ECDH     Au=ECDSA Enc=RC4(128)  Mac=SHA1
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA256
DHE-RSA-AES256-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA1
DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH       Au=RSA  Enc=Camellia(256) Mac=SHA1
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA256
DHE-RSA-AES128-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA1
DHE-RSA-SEED-SHA        SSLv3 Kx=DH       Au=RSA  Enc=SEED(128) Mac=SHA1
DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH       Au=RSA  Enc=Camellia(128) Mac=SHA1
ECDH-RSA-RC4-SHA        SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128)  Mac=SHA1
ECDH-ECDSA-RC4-SHA      SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128)  Mac=SHA1
RC4-SHA                 SSLv3 Kx=RSA      Au=RSA  Enc=RC4(128)  Mac=SHA1
沈伟
2023-03-14

我从未将客户端证书放入KeyManager:

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
    kmf.init(keystore, "password".toCharArray());
    sslContext.init(kmf.getKeyManagers(), new TrustManager[]{tm}, null);
 类似资料:
  • 我必须在kafka中使用SSL添加加密和身份验证。 这就是我所做的: > < li> 为每个经纪人kafka生成证书: keytools-keystoreserver.keystore.jks别名localhost有效性 创建CA。生成的CA是一个公钥-私钥对,是用于签署其他证书的证书。CA负责签署证书。 使用生成的 CA 对所有代理证书进行签名 从密钥库导出证书: < code > keytoo

  • 我正在尝试使用Spring RestTemplate调用POST Rest调用: 这个https://server.com有证书:webapi。tartu-x86。p12我将证书导入C:\Java_8\jre\lib\security\cacerts usinf keytool 运行代码后,我出现以下错误: 我使用的是Java1.8.091 有人能帮忙吗?

  • 我正在编写一个JMeter测试计划,以连接到SSL端口(Tomcat Connector)。在JDK8(1.8.0_51)上使用三个JMeter SSL客户端实现(HttpClient4、HttpClient3.1、Java)中的任何一个连接到SSL端口时,我会收到一个SSLHandshakeExc0019(handshake_failure)。如果我使用JDK7(1.7。0_75)-一切都像预期

  • 我得到这个错误,而试图在linux上执行和旧的MapleStory服务器,我已经尝试了相同的文件在窗口和工作没有问题。我尝试了多个Java版本没有成功。

  • 我正在开发一个应用程序,(强大的)用户必须为其设置自己的服务器(即nginx)来运行后端应用程序。需要在应用程序中配置相应的域,这样它才能连接。我主要在我自己的手机(索尼z3c)上进行测试,并开始为5.1开发。后来我收到了6.0版本的更新,但在模拟器中仍然保持了5.1版本。不久之前,我开始使用7.0镜像的AVD,但令我吃惊的是,它不会连接到我的服务器,告诉我ssl握手失败。我的nginx配置相当严

  • http://bigparty.cz/photos/headlinefoto/13.jpg (我可以附加一个带有整个错误的日志-UIL自动将错误放入日志)