java - Android:使用 SSL 交换消息时出现问题

标签 java android ssl client

我一直在尝试让客户端通过 SSL 安全地与服务器通信。我创建了自己的自签名证书,客户端似乎可以使用证书连接到服务器,但客户端似乎从未从服务器获得响应。我尝试打印返回 -1 的内容长度,但实际内容似乎是一个空字符串,尽管需要一个简单的 HTML“hello world”。

我做错了什么?

服务器:

public class SSLServer {
   public static void main(String[] args) {
      String ksName = "key.jks";
      char ksPass[] = "password".toCharArray();
      char ctPass[] = "password".toCharArray();
      try {
         KeyStore ks = KeyStore.getInstance("JKS");
         ks.load(new FileInputStream(ksName), ksPass);
         KeyManagerFactory kmf = 
         KeyManagerFactory.getInstance("SunX509");

         kmf.init(ks, ctPass);
         SSLContext sc = SSLContext.getInstance("TLS");
         sc.init(kmf.getKeyManagers(), null, null);
         SSLServerSocketFactory ssf = sc.getServerSocketFactory();
         SSLServerSocket s 
            = (SSLServerSocket) ssf.createServerSocket(8888);
         System.out.println("Server started:");
         // Listening to the port
         SSLSocket c = (SSLSocket) s.accept();
         BufferedWriter w = new BufferedWriter(
            new OutputStreamWriter(c.getOutputStream()));

         w.write("HTTP/1.0 200 OK");
         w.write("Content-Type: text/html");
         w.write("<html><body>Hello world!</body></html>");
         w.flush();
         w.close();
         c.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

}

客户:

public class TestSSLActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Instantiate the custom HttpClient
        DefaultHttpClient client = new MyHttpClient(getApplicationContext());
        HttpGet get = new HttpGet("https://192.168.15.195:8888");
        // Execute the GET call and obtain the response
        HttpResponse getResponse;
        try {
            getResponse = client.execute(get);
            HttpEntity responseEntity = getResponse.getEntity();
            Log.i("Connection",responseEntity.getContentLength()+"");
            BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent(), "UTF-8"));
            StringBuilder builder = new StringBuilder();

            for (String line = null; (line = reader.readLine()) != null;) {
                builder.append(line).append("\n");
            } 
            Log.i("Connection","build: "+builder.toString());


        } catch (Exception e) {
            Log.i("Connection",e.getMessage());
        }
    }   

自定义 HTTP 客户端:

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Register for port 443 our SSLSocketFactory with our keystore
        // to the ConnectionManager
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = context.getResources().openRawResource(R.raw.key);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "password".toCharArray());
            } finally {
                in.close();
            }
            // Pass the keystore to the SSLSocketFactory. The factory is responsible
            // for the verification of the server certificate.
            SSLSocketFactory sf = new SSLSocketFactory(trusted);
            // Hostname verification from certificate
            // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
            sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

最佳答案

您可能希望更改服务器代码以在发送响应之前从客户端读取请求。可能是客户端阻塞(然后超时?)等待服务器读取请求。

关于java - Android:使用 SSL 交换消息时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5780480/

相关文章:

java - 使用 PDFbox 从 PDF 文件中删除图像

java - 如何捕获 SocketTimeoutException

android - 为什么在添加依赖项后从导入行重定向时 http.dart 文件显示为空,而且 http.get(url) 方法未完成

c++ - 以编程方式获取颁发者证书 C++

iis - 如何仅从特定 CA 请求客户端证书

java - 为不同的键存储相同的值。 [Java]

java - 关系图的自动布局

android - Red5Pro调试Android Studio异常

android - 如何为我的移动应用程序选择平台以及如何将其发展为多个平台?

android - 如何检查和设置适用于 iOS 和 Android 的 Amazon Web Services SDK 以使用 HTTPS (SSL)?