0
我正试图编写一个通过安全连接(SSL/TLS)与java PC服务器通信的android应用程序,我已经阅读了几本教程并遵循了它们以下内容代码在个人计算机上使用时可以工作,但是当我使用Android(3.2)设备上的客户端代码时,它将停止在SSL或TLS握手中。 以下是客户端通讯代码:如何在Android客户端和自定义java服务器之间使用SSL套接字
public class ClientCommunicationManager implements Runnable{
/**
* Application context
*/
private Context context;
/**
* Host string
*/
private String host;
/**
* port number
*/
private int port;
/**
* Report Recieved Listeners vector
*/
private Vector<ReportRecievedListener> rrListeners;
/**
* Connection to the client
*/
private DataInputStream din;
/**
* Connection to the client
*/
private DataOutputStream dout;
/**
* KeyStore for storing our public/private key pair
*/
private KeyStore clientKeyStore;
/**
* KeyStore for storing the server's public key
*/
private KeyStore serverKeyStore;
/**
* Used to generate a SocketFactory
*/
private SSLContext sslContext;
/**
* A list of visible postings
*/
private Set postings = new HashSet();
/**
* Passphrase for accessing our authentication keystore
*/
static private final String passphrase = "a1n2d3r4o5i6d";
/**
* A source of secure random numbers
*/
static private SecureRandom secureRandom;
public ClientCommunicationManager(String host, int port,Context context) {
this.context = context;
this.host = host;
this.port = port;
rrListeners = new Vector<ReportRecievedListener>();
secureRandom = new SecureRandom();
secureRandom.nextInt();
}
public void registerRRListener(ReportRecievedListener listener){
rrListeners.add(listener);
}
private void setupServerKeystore() throws GeneralSecurityException, IOException {
serverKeyStore = KeyStore.getInstance("BKS");
serverKeyStore.load(context.getResources().openRawResource(R.raw.serverbks),
"public".toCharArray());
}
private void setupClientKeyStore() throws GeneralSecurityException, IOException {
clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(context.getResources().openRawResource(R.raw.clientbks),
passphrase.toCharArray());
}
private void setupSSLContext() throws GeneralSecurityException, IOException {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(serverKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientKeyStore, passphrase.toCharArray());
sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(),
tmf.getTrustManagers(),
secureRandom);
}
public void connect() {
new Thread(new Runnable() {
public void run() {
try {
setupServerKeystore();
setupClientKeyStore();
setupSSLContext();
} catch (GeneralSecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
SSLSocketFactory sf = sslContext.getSocketFactory();
SSLSocket socket= null;
InputStream in = null;
OutputStream out = null;
try {
socket = (SSLSocket)sf.createSocket(host, port);
socket.setUseClientMode(true);
socket.startHandshake();
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
din = new DataInputStream(in);
dout = new DataOutputStream(out);
if(socket!=null)
new Thread(this).start();
}
}).start();
}
public void run() {
boolean isConnected = true;
try {
while (isConnected) {
String msg = din.readUTF();
if(msg.equals("END"))
isConnected = false;
else
fireReportRecievedEvent(new ReportRecievedEvent(msg));
}
} catch(IOException ie) {
ie.printStackTrace();
}
}
private void fireReportRecievedEvent(ReportRecievedEvent event){
for(ReportRecievedListener listener : rrListeners){
listener.onReportRecieved(event);
}
}
}
以下是服务器代码:
public class CommunicationManager implements Runnable{
private int port = Constants.SERVER_PORT;
private HashSet<ConnectionProcessor> connections = new HashSet<ConnectionProcessor>();
private KeyStore clientKeyStore;
private KeyStore serverKeyStore;
private SSLContext sslContext;
static private SecureRandom secureRandom;
private boolean running;
private SSLServerSocket ss=null;
private static CommunicationManager instance=null;
private CommunicationManager(){
}
public static CommunicationManager getInstance(){
if(instance == null){
instance = new CommunicationManager();
}
return instance;
}
public int getSecureRandom(){
SecureRandom securerandom = new SecureRandom();
return securerandom.nextInt();
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public void startServer(){
if(!isRunning()){
setRunning(true);
new Thread(this).start();
}
}
public void stopServer(){
setRunning(false);
for(ConnectionProcessor cp : connections){
cp.close();
}
try {
if(ss!=null)
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void setupClientKeyStore() throws GeneralSecurityException, IOException {
clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("resources/client.public"),
"public".toCharArray());
}
private void setupServerKeystore() throws GeneralSecurityException, IOException {
serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("resources/server.private"),
Constants.SERVER_KEYSTORE_PWD.toCharArray());
}
private void setupSSLContext() throws GeneralSecurityException, IOException {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(clientKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(serverKeyStore, Constants.SERVER_KEYSTORE_PWD.toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(),
tmf.getTrustManagers(),
secureRandom);
}
@Override
public void run() {
try {
setupClientKeyStore();
setupServerKeystore();
setupSSLContext();
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
}
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
try {
ss = (SSLServerSocket)sf.createServerSocket(port);
} catch (IOException e) {
e.printStackTrace();
}
// Require client authorization
ss.setNeedClientAuth(true);
System.out.println("Listening on port "+port+"...");
while (isRunning()) {
Socket socket=null;
try {
socket = ss.accept();
} catch (IOException e) {
if(e.getClass() == SocketException.class){
System.out.print("accept() threw SocketException because of close\n");
}
}
if(socket!=null && socket.isConnected()){
System.out.println("Got connection from "+socket);
ConnectionProcessor cp = new ConnectionProcessor(this, socket);
connections.add(cp);
}
}
closeServer();
}
private void closeServer() {
for(ConnectionProcessor cp : connections){
cp.close();
}
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Remove a connection that has been closed from our set
* of open connections
*/
public void removeConnection(ConnectionProcessor cp) {
connections.remove(cp);
}
/**
* Return an iteration over open connections
*/
public Iterator getConnections() {
return connections.iterator();
}
/**
* Broadcast a report over all connections
*/
public void broadcastReport(String report){
for(ConnectionProcessor cp : connections){
cp.send(report);
}
}
/**
* Broadcast a report over all connections using a new thread
*/
public void broadcastOnThread(final String report) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if(isRunning())
broadcastReport(report);
}
}) ;
t.start();
}
/**
* recieve a new report to be broadcasted
*/
public void acceptReport(String report_string) {
broadcastOnThread(report_string);
}
}
任何帮助或洞察力会非常赞赏。谢谢。
您的异常处理非常差。在几乎所有情况下,您都会打印该信息,并继续进行,就像它没有发生过一样,那时应该放弃相关方法。在accept()循环中,您只能有条件地打印它,这更糟糕。首先解决它。然后运行-DJavax.net.debug = ssl,握手并将结果输出添加到您的帖子中。 – EJP
@EJP你对我的异常处事很正确,但我不认为它现在是相关的。我只想设置连接。关于SSL调试模式,我不认为它适用于android平台,或者是它? ...正如我解释的上述代码工作得很好,当两个代码(客户端和服务器)从同一台电脑运行。当我将客户端移植到android时,连接永远不会发生,并且在调试时我发现握手只会陷入僵局。但是感谢您的建议 – user1666216
当您建立连接时,请不要忘记验证服务器证书中的主机名。 – Bruno