Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error

后端 未结 11 672
终归单人心
终归单人心 2020-11-22 10:55

I am trying to run the following code in android

URLConnection l_connection = null;
        // Create connection
        uzip=new UnZipData(mContext);
               


        
相关标签:
11条回答
  • 2020-11-22 11:35

    It was reproducible only when I use proxy on genymotion(<4.4).

    Check your proxy settings in Settings-> Wireless & Networks-> WiFi->(Long Press WiredSSID)-> Modify Network

    Select show advanced options: set Proxy settings to NONE.

    0 讨论(0)
  • 2020-11-22 11:39

    I have got this error report problem, too. My code is under below.

    public static void getShop() throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("https://10.0.2.2:8010/getShopInfo/aaa")
                            .build();
                    Response response = client.newCall(request).execute();
                    Log.d("response", response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    

    I have my Springboot as my backend and use Android OKHttp to get information. The critical mistake i made was that i use a .url("https://10.0.2.2:8010/getShopInfo/aaa") in code of Android. But the my backend is not allowed https request. After i use .url("http://10.0.2.2:8010/getShopInfo/aaa"), then my code went well. So, i want to say my mistake is not the version of emulator, it about the request protocol. I meet another problem after doing what i said, but it's another problem, and i attach the resolve method of the new problem .
    Good Luck!GUY!

    0 讨论(0)
  • 2020-11-22 11:45

    My Answer is close to the above answers but you need to write the class exactly without changing anything.

    public class TLSSocketFactory extends SSLSocketFactory {
    
    private SSLSocketFactory delegate;
    
    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        delegate = context.getSocketFactory();
    }
    
    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }
    
    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }
    
    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(delegate.createSocket());
    }
    
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
    }
    
    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(delegate.createSocket(host, port));
    }
    
    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
    }
    
    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(host, port));
    }
    
    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
    }
    
    private Socket enableTLSOnSocket(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
    

    }

    and to use it with HttpsURLConnection

    HttpsURLConnection  conn = (HttpsURLConnection) url.openConnection();
    
    int sdk = android.os.Build.VERSION.SDK_INT;
                if (sdk < Build.VERSION_CODES.LOLLIPOP) {
                    if (url.toString().startsWith("https")) {
                        try {
                            TLSSocketFactory sc = new TLSSocketFactory();
                            conn.setSSLSocketFactory(sc);
                        } catch (Exception e) {
                            String sss = e.toString();
                        }
                    }
                }
    
    0 讨论(0)
  • 2020-11-22 11:49

    Previously, I've also solved this problem with custom SSLFactory implementation, but according to OkHttp docs the solution is much easier.

    My final solution with needed TLS ciphers for 4.2+ devices looks like this:

    public UsersApi provideUsersApi() {
    
        private ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
            .supportsTlsExtensions(true)
            .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
            .cipherSuites(
                    CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                    CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                    CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                    CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                    CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
                    CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                    CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                    CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                    CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
                    CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                    CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
                    CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
            .build();
    
        OkHttpClient client = new OkHttpClient.Builder()
                .connectionSpecs(Collections.singletonList(spec))
                .build();
    
        return new Retrofit.Builder()
                .baseUrl(USERS_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build()
                .create(UsersApi.class);
    }
    

    Note that set of supported protocols depends on configured on your server.

    0 讨论(0)
  • 2020-11-22 11:51

    Also you should know that you can force TLS v1.2 for Android 4.0 devices that don't have it enabled by default:

    Put this code in onCreate() of your Application file:

    try {
            ProviderInstaller.installIfNeeded(getApplicationContext());
            SSLContext sslContext;
            sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, null, null);
            sslContext.createSSLEngine();
        } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
                | NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
    
    0 讨论(0)
  • 2020-11-22 11:51

    When I got this error, it was because the protocols (TLS versions) and/or cipher suites supported by the server were not enabled on (and possibly not even supported by) the device. For API 16-19, TLSv1.1 and TLSv1.2 are supported but not enabled by default. Once I enabled them for these versions, I still got the error because these versions don't support any of the ciphers on our instance of AWS CloudFront.

    Since it's not possible to add ciphers to Android, we had to switch our CloudFront version from TLSv1.2_2018 to TLSv1.1_2016 (which still supports TLSv1.2; it just doesn't require it), which has four of the ciphers supported by the earlier Android versions, two of which are still considered strong.

    At that point, the error disappeared and the calls went through (with TLSv1.2) because there was at least one protocol and at least one cipher that the device and server shared.

    Refer to the tables on this page to see which protocols and ciphers are supported by and enabled on which versions of Android.

    Now was Android really trying to use SSLv3 as implied by the "sslv3 alert handshake failure" part of the error message? I doubt it; I suspect this is an old cobweb in the SSL library that hasn't been cleaned out but I can't say for sure.

    In order to enable TLSv1.2 (and TLSv1.1), I was able to use a much simpler SSLSocketFactory than the ones seen elsewhere (like NoSSLv3SocketFactory). It simply makes sure that the enabled protocols include all the supported protocols and that the enabled ciphers include all the supported ciphers (the latter wasn't necessary for me but it could be for others) - see configure() at the bottom. If you'd rather enable only the latest protocols, you can replace socket.supportedProtocols with something like arrayOf("TLSv1.1", "TLSv1.2") (likewise for the ciphers):

    class TLSSocketFactory : SSLSocketFactory() {
    
        private val socketFactory: SSLSocketFactory
    
        init {
            val sslContext = SSLContext.getInstance("TLS")
            sslContext.init(null, null, null)
            socketFactory = sslContext.socketFactory
        }
    
        override fun getDefaultCipherSuites(): Array<String> {
            return socketFactory.defaultCipherSuites
        }
    
        override fun getSupportedCipherSuites(): Array<String> {
            return socketFactory.supportedCipherSuites
        }
    
        override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
            return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket)
        }
    
        override fun createSocket(host: String, port: Int): Socket {
            return configure(socketFactory.createSocket(host, port) as SSLSocket)
        }
    
        override fun createSocket(host: InetAddress, port: Int): Socket {
            return configure(socketFactory.createSocket(host, port) as SSLSocket)
        }
    
        override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
            return configure(socketFactory.createSocket(host, port, localHost, localPort) as SSLSocket)
        }
    
        override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
            return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket)
        }
    
        private fun configure(socket: SSLSocket): SSLSocket {
            socket.enabledProtocols = socket.supportedProtocols
            socket.enabledCipherSuites = socket.supportedCipherSuites
            return socket
        }
    }
    
    0 讨论(0)
提交回复
热议问题