在 android Nougat 中使用自签名证书通过 https 连接时出现 SSL 握手异常

Posted

技术标签:

【中文标题】在 android Nougat 中使用自签名证书通过 https 连接时出现 SSL 握手异常【英文标题】:SSL handshake exception while connecting over https using self signed certificate in android Nougat 【发布时间】:2017-03-30 05:04:56 【问题描述】:

在我的 android 应用程序中,我通过 https 连接。我正在使用自签名证书进行连接。 它适用于 api 级别 24 以下的设备(在 android nougat 之前)。但是在 android Nougat 上它会引发 SSL Handshake 异常:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:信任锚 找不到证书路径。

这就是我通过 https 连接的方式:-

SSLContext context = null;
    try 
    
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // Get the raw resource, which contains the keystore with
        // your trusted certificates (root and any intermediate certs)
        InputStream input = new BufferedInputStream(context.getAssets().open(pkcsFilename));
        try 
            // Initialize the keystore with the provided trusted certificates
            // Also provide the password of the keystore
            keyStore.load(input, password.toCharArray());
         finally 
            input.close();
        

        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFactory.init(keyStore, "".toCharArray());

        // Load CAs from an InputStream
        // (could be from a resource or ByteArrayInputStream or ...)
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate ca = null;
        input = new BufferedInputStream(context.getAssets().open(certificateFilename));
        try 
        
            ca = cf.generateCertificate(input);
        
        finally
        
            input.close();
        
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);
        trustStore.setCertificateEntry("server", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);

        // Create an SSLContext that uses our TrustManager
        context = SSLContext.getInstance("TLS");
        context.init(keyFactory.getKeyManagers(), tmf.getTrustManagers(), null);

        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

我尝试了以下link,但它没有帮助。

这是我的网络配置文件。我已将它添加到我的 AndroidManifest.xml 文件中。

    <?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">xyz.com</domain>
        <trust-anchors>
        <certificates src="@raw/root_ca" />
        </trust-anchors>
    </domain-config>
</network-security-config>

请帮我解决这个问题。

【问题讨论】:

【参考方案1】:

System.setProperty("javax.net.ssl.trustStore",newKeystoreFile.getAbsolutePath());

同样,尝试设置 keystorepassword 和 keypassword 属性 每次尝试使用上述属性时都重新启动服务器 https://docs.oracle.com/cd/E17802_01/webservices/webservices/reference/tutorials/wsit/doc/WSIT_Security6.html

【讨论】:

【参考方案2】:

我通过添加自定义信任管理器使其工作。初始化 SSL 上下文时context.init(keyFactory.getKeyManagers(), tmf.getTrustManagers(), null);

I modified it as :

context.init(keyFactory.getKeyManagers(), new TrustManager[]  tm , null);
TrustManager tm = new X509TrustManager() 
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException 
                

                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException 
                    for (int j=0; j<chain.length; j++)
                    
                        chain[j].checkValidity();
                        try 
                            chain[j].verify(ca.getPublicKey());
                         catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException |
                                SignatureException e) 
                            e.printStackTrace();
                            throw new CertificateException(e.getMessage());
                        
                    
                

                public X509Certificate[] getAcceptedIssuers() 
                    return null;
                
            ;

我用服务器证书验证证书。现在它的工作。

【讨论】:

以上是关于在 android Nougat 中使用自签名证书通过 https 连接时出现 SSL 握手异常的主要内容,如果未能解决你的问题,请参考以下文章

在 IBM MobileFirst android 中使用自签名证书的问题

Android使用SSL自签名证书

Android使用SSL自签名证书

Android使用SSL自签名证书

在 IBM MobileFirst Platform Android 中绕过自签名证书

Android Volley 自签名证书