Android M - SSLSocket连接中的SSLHandshakeException

时间:2016-02-24 17:52:08

标签: java android ssl android-6.0-marshmallow tls1.2

我有一个相当简单的客户端(Android)/服务器应用程序,我试图添加SSL。它的工作正常至Android 4.4.4 ,但在Android M上失败SSLHandshakeException(尚未在Lollipop上测试过),服务器告诉我没有密码共同的套房

以下是基本代码(完整源代码 here)..

Server.java

public class Server {
    public static final int PORT = 4646;
    TrustManagerFactory tmf;
    KeyManagerFactory kmf;
    KeyStore publicKeyStore;
    KeyStore privateKeyStore;
    SSLServerSocket serverSocket;

    public static void main(String args[]) {
        Server server = new Server();
        server.init();
    }

    private void init() {
        InputStream privateKeyStoreIns;
        InputStream publicKeyStoreIns;

        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextInt();

        privateKeyStoreIns = Server.class.getResourceAsStream("/server.private");
        publicKeyStoreIns = Server.class.getResourceAsStream("/client.public");

        Security.addProvider(new BouncyCastleProvider());

        try {
            privateKeyStore = setupKeystore(privateKeyStoreIns, "private");
            publicKeyStore = setupKeystore(publicKeyStoreIns, "public");

            tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(publicKeyStore);

            kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(privateKeyStore, "private".toCharArray());

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(),
                    tmf.getTrustManagers(),
                    secureRandom);

            SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
            serverSocket = (SSLServerSocket) sf.createServerSocket( PORT );
            serverSocket.setNeedClientAuth(true);

            Socket socket = serverSocket.accept();

            ObjectInputStream objInputStream = new ObjectInputStream(socket.getInputStream());
            while (objInputStream.readObject() != null) {
                // do nothing
            }

            objInputStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private KeyStore setupKeystore(InputStream keyStoreInputStream, String passphrase)
            throws GeneralSecurityException, IOException {
        KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(keyStoreInputStream, passphrase.toCharArray());

        return keyStore;
    }

}

MainActivity.java

public class MainActivity extends Activity {
    private static final String TAG = MainActivity.class.getName();
    public static final int PORT = 4646;
    public static final String HOST = "192.168.1.12"; //Change to IP address of server

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        connect();
    }

    private void connect() {
        new SocketConnector(this).execute();
    }

    static class SocketConnector extends AsyncTask<Void, Void, String> {
        Activity activity;
        TrustManagerFactory tmf;
        KeyManagerFactory kmf;
        KeyStore publicKeyStore;
        KeyStore privateKeyStore;
        SSLSocket socket;

        public SocketConnector(Activity activity) {
            this.activity = activity;
        }

        @Override
        protected String doInBackground(Void... params) {
            InputStream privateKeyStoreIns;
            InputStream publicKeyStoreIns;

            SecureRandom secureRandom = new SecureRandom();
            secureRandom.nextInt();

            privateKeyStoreIns = activity.getResources().openRawResource(R.raw.client_private);
            publicKeyStoreIns = activity.getResources().openRawResource(R.raw.server_public);

            try {
                privateKeyStore = setupKeystore(privateKeyStoreIns, "private");
                publicKeyStore = setupKeystore(publicKeyStoreIns, "public");

                tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(publicKeyStore);

                kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                kmf.init(privateKeyStore, "private".toCharArray());

                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(kmf.getKeyManagers(),
                        tmf.getTrustManagers(),
                        secureRandom);

                SSLSocketFactory sf = sslContext.getSocketFactory();
                socket = (SSLSocket) sf.createSocket(HOST, PORT);
                socket.startHandshake();

            } catch (Exception e) {
                e.printStackTrace();
                return "Connection failure: " + e.getMessage();
            }

            return "Connection established!";
        }

        @Override
        protected void onPostExecute(String s) {
            TextView textView = (TextView) activity.findViewById(R.id.text_view);
            textView.setText(s);
        }

        private KeyStore setupKeystore(InputStream keyStoreInputStream, String passphrase)
                throws GeneralSecurityException, IOException {
            KeyStore keyStore = KeyStore.getInstance("BKS");
            keyStore.load(keyStoreInputStream, passphrase.toCharArray());

            return keyStore;
        }
    }
}

Android上的异常堆栈跟踪

javax.net.ssl.SSLHandshakeException: Handshake failed
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:396)
    at com.sslsocketpoc.app.MainActivity$SocketConnector.doInBackground(MainActivity.java:71)
    at com.sslsocketpoc.app.MainActivity$SocketConnector.doInBackground(MainActivity.java:31)
    at android.os.AsyncTask$2.call(AsyncTask.java:295)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x9e7a3140: Failure in SSL library, usually a protocol error
error:100c5410:SSL routines:ssl3_read_bytes:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:972 0xb4071d20:0x00000001)
error:100c009f:SSL routines:ssl3_get_server_hello:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:750 0xab25d50f:0x0000
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)

服务器端异常

javax.net.ssl.SSLHandshakeException: no cipher suites in common
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
    at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1035)

1 个答案:

答案 0 :(得分:2)

Google已在API 23(6.x)中分叉OpenSSL,现在使用BoringSSL支持no DSA(但是ECDSA),您的public client key是DSA 1024 KEY,因此您需要检查(并将您的密钥更改为supported algorithm