2014-05-03 166 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