安卓TLS握手

3

我正在尝试理解Android与服务器之间的TLS连接。有人能帮我纠正吗?

TLS连接有两种启动方式。第一种,只有服务器有证书,客户端需要决定是否信任它。第二种,客户端和服务器都有证书。我说得对吗?

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

有人可以帮帮我吗?


虽然不完全相同,但您可以查看我的有关使用客户端证书的问题,链接在这里:https://dev59.com/LIDba4cB1Zd3GeqPK_R4 - Felix
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
5
为了通过TLS实现双重认证,您需要在服务器和客户端上都有一个密钥库。 我通常使用Portecle工具创建密钥库,这是一个基于Java的GUI工具,非常易于使用。您可以在portecle.sourceforge.net上下载它。 您需要使用该工具为服务器端创建JKS格式的密钥库,并为客户端创建BKS格式的另一个密钥库。格式不同是因为Android不支持本地使用JKS密钥库,仅支持BKS,反之亦然。 一旦您创建了两个密钥库,就需要为每个密钥库生成一对密钥(公钥和私钥)。Portecle在工具栏下的“Tools”子菜单下有一个按钮来完成此操作。常见的密钥算法和大小是RSA 2048位。之后,您需要设置一些证书参数,例如组织单位、名称、地点等。 现在您有了两个密钥库和两个密钥对。 为了让客户端解密服务器接收到的消息,必须向客户端密钥库提供服务器密钥库的公钥。只需右键单击服务器密钥库上的密钥对,然后单击“导出”选项。然后选择“证书链”,并选择文件系统上的位置以存储证书。 现在,您已经准备好将公钥导入客户端密钥库了。点击“工具”工具栏,选择“导入可信证书”,然后查找之前导出的证书文件。一些警报消息将出现,指示无法建立信任路径,请暂时不要担心。 因此,现在您具有了客户端密钥库、密钥对和服务器证书。客户端方面就足够了。 现在,需要将客户端密钥对导入服务器密钥库中。在客户端密钥库上右键单击密钥对,然后选择“导出”。在打开的弹出窗口中选择“私钥和证书”,并选择PKCS #12格式。 然后,打开服务器密钥库并使用“工具”工具栏的“导入密钥对”子菜单,然后选择在上一步中导出的密钥对。 请记住,非常重要的是将客户端密钥库保存为BKS格式,服务器密钥库保存为JKS格式。 好了,密钥库的部分已经完成,现在该编码了。 让我们从服务器代码开始。下一个片段摘自我运行的Java Spring项目。这是一个嵌入式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);
}
}

对于服务器端而言,你可以使用“setSecure(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());

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,