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

发布于 2024-11-03 12:45:39 字数 4701 浏览 0 评论 0原文

我一直在尝试让客户端通过 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);
        }
    }
}

I have been trying to get a client to communicate with a server securely through SSL. I created my own self-signed certificates and it seems like that the client can connect to the server using the certificates, but the client never seems to be getting the response from the server. I tried printing the content-length which returns -1 and the actual content seems to be an empty string, although a simple HTML 'hello world' is expected.

What am I doing wrong?

Server:

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();
      }
   }

}

Client:

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());
        }
    }   

Custom HTTP client:

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);
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深白境迁sunset 2024-11-10 12:45:39

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

You might want to change the server code to read the request from the client before sending the response. It could be that the client is blocking (and then timing out?) waiting for the server to read the request.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文