2014-05-03 163 views
0

我正在使用RMI編寫客戶端服務器應用程序,並且我想保護客戶端和服務器之間的通信。我想爲此使用SslRMIClientSocketFactorySslRMIServerSocketFactory帶有SSL的RMI:握手失敗

我創建了一個密鑰對的客戶端和服務器(client.privateserver.private),也爲客戶端證書和服務器(client.publicserver.public)。

我想我正確地將密鑰對添加到密鑰庫和證書到信任庫。 我只在導出對象時使用自定義套接字工廠,而不是在創建RMI註冊表時使用。這裏是我的代碼:

服務器:

public class Server implements ServerProtocol { 
    public Server() { 
     super(); 
     SecureRandom sr = new SecureRandom(); 
     sr.nextInt(); 

     KeyStore clientKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream client = new FileInputStream("src/client.public"); 
     String passphrase = // 
     clientKeyStore.load(client, passphrase.toCharArray()); 
     client.close(); 

     KeyStore serverKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream server = new FileInputStream("src/server.private"); 
     String password = // 
     serverKeyStore.load(server, password.toCharArray()); 
     server.close(); 

     TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(clientKeyStore); 

     KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(serverKeyStore, password.toCharArray()); 

     SSLContext SSLC = SSLContext.getInstance("TLS"); 
     SSLC.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr); 

     SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); 
     SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(null, null, true); 

     LocateRegistry.createRegistry(2020).rebind("server", this); 
     UnicastRemoteObject.exportObject(this, 2020, csf, ssf); 
    } 

    public void sayHello() { 
     System.out.println("Hello"); 
    } 
} 

客戶:

public class Client implements ClientProtocol { 

    public Client() { 
     SecureRandom sr = new SecureRandom(); 
     sr.nextInt(); 

     KeyStore serverKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream server = new FileInputStream("src/server.public"); 
     String passphrase = // 
     serverKeyStore.load(server, passphrase.toCharArray()); 
     server.close(); 

     KeyStore clientKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream client = new FileInputStream("src/client.private"); 
     String password = // 
     clientKeyStore.load(client, password.toCharArray()); 
     client.close(); 

     TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(serverKeyStore); 

     KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(clientKeyStore, password.toCharArray()); 

     SSLContext SSLC = SSLContext.getInstance("TLS"); 
     SSLC.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr); 

     SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); 
     SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(null, null, true); 

     Registry reg = LocateRegistry.getRegistry("localhost", 2020); 
     serverStub = (ServerService) reg.lookup("server"); 
     stub = (ClientService) UnicastRemoteObject.exportObject(this, 2020, csf, ssf); 

     serverStub.sayHello(); 
    } 
} 

當我跑,我得到了以下錯誤消息:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:654) 
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:100) 
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) 
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123) 
at java.io.DataOutputStream.flush(DataOutputStream.java:106) 
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:211) 
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184) 
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:110) 
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178) 
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132) 
at com.sun.proxy.$Proxy0.sayHello(Unknown Source) 
at project.Client.<init>(Client.java:100) 
at project.Client.main(Client.java:785) 

我你使用sed下面的命令來創建密鑰,導出和導入:

keytool -genkey -alias clientprivate -keystore client.private -storetype JKS -keyalg rsa -storepass * -keypass * -validity 360 
keytool -genkey -alias serverprivate -keystore server.private -storetype JKS -keyalg rsa -storepass * -keypass * -validity 360 

keytool -export -alias clientprivate -keystore client.private -file temp.key -storepass * 
keytool -import -noprompt -alias clientpublic -keystore client.public -file temp.key -storepass * 

keytool -export -alias serverprivate -keystore server.private -file temp.key -storepass * 
keytool -import -noprompt -alias serverpublic -keystore server.public -file temp.key -storepass * 

我需要配置別的東西,使這項工作? Eclipse中的東西?

回答

0

我能夠通過避免構建Java類SslRMIClientSocketFactorySslRMIServerSocketFactory並創建我自己的類實現RMIClientSocketFactoryRMIServerSocketFactory接口來解決此問題。

的RMIClientSocketFactory

public class MyClientSocketFactory implements RMIClientSocketFactory, Serializable { 

    public MyClientSocketFactory() {} 

    public Socket createSocket(String host, int port) { 

     SecureRandom sr = new SecureRandom(); 
     sr.nextInt(); 

     KeyStore serverKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream server = new FileInputStream("src/server.public"); 
     String passphrase = // 
     serverKeyStore.load(server, passphrase.toCharArray()); 
     server.close(); 

     KeyStore clientKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream client = new FileInputStream("src/client.private"); 
     String password = // 
     clientKeyStore.load(client, password.toCharArray()); 
     client.close(); 

     TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(serverKeyStore); 

     KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(clientKeyStore, password.toCharArray()); 

     SSLContext SSLC = SSLContext.getInstance("TLS"); 
     SSLC.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr); 

     SSLSocketFactory sf = SSLC.getSocketFactory(); 
     SSLSocket socket = (SSLSocket) sf.createSocket(host, port); 

     return socket; 
    } 

    public int hashCode() { 
     return getClass().hashCode(); 
    } 

    public boolean equals(Object obj) { 
     if (obj == this) { 
      return true; 
     } else if (obj == null || getClass() != obj.getClass()) { 
      return false; 
     } 
     return true; 
    } 

} 

的RMIServerSocketFactory

public class MyServerSocketFactory implements RMIClientSocketFactory, Serializable { 

    public MyServerSocketFactory() {} 

    public Socket createSocket(String host, int port) { 

     SecureRandom sr = new SecureRandom(); 
     sr.nextInt(); 

     KeyStore clientKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream client = new FileInputStream("src/client.public"); 
     String passphrase = // 
     clientKeyStore.load(client, passphrase.toCharArray()); 
     client.close(); 

     KeyStore serverKeyStore = KeyStore.getInstance("JKS"); 
     FileInputStream server = new FileInputStream("src/server.private"); 
     String password = // 
     serverKeyStore.load(server, password.toCharArray()); 
     server.close(); 

     TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(serverKeyStore); 

     KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(clientKeyStore, password.toCharArray()); 

     SSLContext SSLC = SSLContext.getInstance("TLS"); 
     SSLC.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr); 

     SSLServerSocketFactory sf = SSLC.getServerSocketFactory(); 
     SSLServerSocket socket = (SSLServerSocket) sf.createServerSocket(host, port); 

     return socket; 
    } 

    public int hashCode() { 
     return getClass().hashCode(); 
    } 

    public boolean equals(Object obj) { 
     if (obj == this) { 
      return true; 
     } else if (obj == null || getClass() != obj.getClass()) { 
      return false; 
     } 
     return true; 
    } 

} 
1

您正在使用SSL套接字工廠創建註冊表,但是您沒有爲getRegistry()提供套接字工廠。

+0

我已經把它添加到我的代碼,但是有另外一個錯誤,現在 – JNevens

+0

後堆棧跟蹤的其餘部分。將其編輯到您的問題中。至少需要在服務器中配置密鑰庫。 – EJP

+0

我已經發布了完整的堆棧跟蹤。什麼是密鑰庫,爲什麼我需要這個,如何配置它? – JNevens