Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android TLS握手_Android_Ssl - Fatal编程技术网

Android TLS握手

Android TLS握手,android,ssl,Android,Ssl,我试图了解Android和服务器的TLS连接。有人能纠正我吗 有两种启动TLS连接的方法。首先,只有服务器有证书,客户端决定是否信任它。其次,客户端和服务器都有证书。我说得对吗 如何在Android设备上为TLS连接生成自定义唯一证书并将其用于连接到服务器?我只发现了第一种联系的实现 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); KeyStore trust

我试图了解Android和服务器的TLS连接。有人能纠正我吗

有两种启动TLS连接的方法。首先,只有服务器有证书,客户端决定是否信任它。其次,客户端和服务器都有证书。我说得对吗

如何在Android设备上为TLS连接生成自定义唯一证书并将其用于连接到服务器?我只发现了第一种联系的实现

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

            //load keystore stream
            byte[] keystoreData = readInputStream(getAssets().open("client.keystore"));

            //load keystore
            ByteArrayInputStream bais = new ByteArrayInputStream(keystoreData);
            keyStore.load(bais, KEYSTORE_PASSWORD.toCharArray());
            //load truststore
            bais = new ByteArrayInputStream(keystoreData);
            trustStore.load(bais, KEYSTORE_PASSWORD.toCharArray());
            //load trustmanager
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            //init keymanager
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray());
            //create ssl context
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            List<String> allowedHostnames = new ArrayList<String>();
            allowedHostnames.add("pinterest.com");
            allowedHostnames.add("192.168.1.43");
            allowedHostnames.add("10.0.2.2");
            return allowedHostnames.indexOf(hostname) != -1;
        }
    };

                    //open https connection
                    URL url = new URL("https://" + SERVER_URL + ":" + SERVER_PORT + "/api/v1/publication/getDescriptor/" + publicationId);
                    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
                    urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
                    urlConnection.setHostnameVerifier(HOSTNAME_VERIFIER);

                    //read server response
                    byte[] serverResult = readInputStream(urlConnection.getInputStream());

有人能帮我吗?

要通过TLS实现双向身份验证,您需要在服务器端和客户端都有一个密钥库

我通常使用Portecle工具来创建密钥存储库,这是一个非常容易使用的基于java的gui工具。您可以在portecle.sourceforge.net上下载它

您需要使用该工具为服务器端创建一个JKS格式的密钥库,为客户端创建另一个BKS格式的密钥库。这种格式是不同的,因为Android不支持本机使用JKS密钥库,只支持BKS和viceversa

一旦创建了两个密钥库,就需要为它们中的每一个生成公钥和私钥对。Portecle在工具栏上的“工具”子菜单下有一个按钮来执行此操作。常见的密钥算法和大小是RSA 2048位。之后,您需要为证书设置一些参数,如组织unti、名称、位置等

现在您有两个密钥库和两个密钥对

要允许客户端解密服务器接收的消息,必须向客户端密钥库提供服务器密钥库的公钥。要做到这一点,只需右键单击服务器密钥库上的密钥对,然后单击“导出”选项。然后选择“证书链”,并在文件系统上选择存储证书的位置

现在,您已经准备好将公钥导入客户机密钥库。要执行此操作,请单击“工具”工具栏并选择“导入受信任证书”,然后查找上一步导出的证书文件。将出现一些警告消息,指示您无法建立信任路径,暂时不要担心

现在,您有了带有密钥对的客户机密钥库和服务器证书。这在客户端已经足够了

现在,有必要将客户机密钥对导入服务器密钥库。在客户端密钥库上,右键单击密钥对并选择“导出”。在打开的弹出窗口中选择“私钥和证书”,然后选择PKCS 12格式

然后,打开服务器密钥库并使用“工具”工具栏的“导入密钥对”子菜单,然后选择上一步导出的密钥对

请记住,以BKS格式保存客户机密钥库和以JKS格式保存服务器密钥库非常重要

好了,这就是密钥库的全部内容,现在是编写代码的时候了

让我们从服务器代码开始。下一个片段是从我正在运行的JavaSpring项目中提取的。它是一个嵌入式tomcat,所以配置是纯java的,很容易找到如何在传统的tomcat配置上配置ssl连接器,所以我只放嵌入式版本

private Connector createSslConnector() {

//print the client keystore
printClientKeystore();

Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {

    //read the keystore from the jar
    //and write it to a tmp file
    Resource keystoreResource = context.getResource("classpath:config/server.keystore");
    byte[] keystoreData = readKeystore(keystoreResource.getInputStream());
    File tmpKeystoreFile = File.createTempFile("keystore", "");
    writeKeystore(tmpKeystoreFile, keystoreData);

    //keystore information
    final String keystoreFile = tmpKeystoreFile.getAbsolutePath();
    final String keystorePass = "yourKeystorePass";
    final String keystoreType = "pkcs12";
    final String keystoreProvider = "SunJSSE";
    final String keystoreAlias = "comics_tomcat";

    connector.setScheme("https");
    connector.setAttribute("clientAuth", "true");
    connector.setPort(HTTPS_PORT);
    connector.setSecure(true);
    protocol.setSSLEnabled(true);

    //keystore
    protocol.setKeystoreFile(keystoreFile);
    protocol.setKeystorePass(keystorePass);
    protocol.setKeystoreType(keystoreType);
    protocol.setProperty("keystoreProvider", keystoreProvider);
    protocol.setKeyAlias(keystoreAlias);

    //truststore
    protocol.setTruststoreFile(keystoreFile);
    protocol.setTruststorePass(keystorePass);

    protocol.setPort(HTTPS_PORT);

    return connector;
}
catch (IOException e) {
    LOGGER.error(e.getMessage(), e);
    throw new IllegalStateException("cant access keystore: [" + "keystore"
            + "] or truststore: [" + "keystore" + "]", e);
}
}
这就是服务器端的全部内容,通过使用“setSecuretrue”方法,您有一个安全标志为true的ssl连接器。这允许您要求使用私钥/公钥身份验证进行用户身份验证

下面的代码是针对客户端的,它使用相同的密钥库加载密钥库和信任库,配置主机名验证器以允许连接到特定域,然后打开连接

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

            //load keystore stream
            byte[] keystoreData = readInputStream(getAssets().open("client.keystore"));

            //load keystore
            ByteArrayInputStream bais = new ByteArrayInputStream(keystoreData);
            keyStore.load(bais, KEYSTORE_PASSWORD.toCharArray());
            //load truststore
            bais = new ByteArrayInputStream(keystoreData);
            trustStore.load(bais, KEYSTORE_PASSWORD.toCharArray());
            //load trustmanager
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            //init keymanager
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray());
            //create ssl context
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            List<String> allowedHostnames = new ArrayList<String>();
            allowedHostnames.add("pinterest.com");
            allowedHostnames.add("192.168.1.43");
            allowedHostnames.add("10.0.2.2");
            return allowedHostnames.indexOf(hostname) != -1;
        }
    };

                    //open https connection
                    URL url = new URL("https://" + SERVER_URL + ":" + SERVER_PORT + "/api/v1/publication/getDescriptor/" + publicationId);
                    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
                    urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
                    urlConnection.setHostnameVerifier(HOSTNAME_VERIFIER);

                    //read server response
                    byte[] serverResult = readInputStream(urlConnection.getInputStream());

如果你有任何问题,请告诉我

虽然不是完全重复,但您可以在此处查看我关于使用客户端证书的问题: