Вот попробовал написать программу на основе этого примераMyService.java| Код | package impls;
import java.rmi.Remote; import java.rmi.RemoteException;
public interface MyService extends Remote { public String getTimeNow() throws RemoteException; }
|
MySSLServerSocketFactory.java| Код | package rserver;
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.ServerSocket; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.TrustManagerFactory; import javax.rmi.ssl.SslRMIServerSocketFactory;
public class MySSLServerSocketFactory extends SslRMIServerSocketFactory {
@Override public ServerSocket createServerSocket(int port) throws IOException { System.out.println("Creating SSLRMIServerSocket..."); try { return createServerSocketFactory().createServerSocket(port); } catch (Exception ex) { ex.printStackTrace(); }
return null; }
public SSLServerSocketFactory createServerSocketFactory() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException, NoSuchProviderException { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(new File("E:\\serverkeystore.keystore")), "serverpassword".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, "serverkeypassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks);
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
SSLContext sslContext = SSLContext.getInstance("SSLv3"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
return sslContext.getServerSocketFactory(); } }
|
MySSLClientSocketFactory.java| Код | package rclient;
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import javax.rmi.ssl.SslRMIClientSocketFactory;
public class MySSLClientSocketFactory extends SslRMIClientSocketFactory {
public Socket createSocket(int port, String host) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException, NoSuchProviderException { System.out.println("Creating SSLRMIClientSocket... "); return creareClientSocketFactory().createSocket(host, port); }
public SSLSocketFactory creareClientSocketFactory() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException, NoSuchProviderException { KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(new File("E:\\clientkeystore.keystore")), "clientpassword".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, "clientkeypassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks);
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
SSLContext sslContext = SSLContext.getInstance("SSLv3"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
return sslContext.getSocketFactory(); } }
|
ServerImpl.java| Код | package rserver;
import impls.MyService; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.util.Calendar; import java.util.Date; import rclient.MySSLClientSocketFactory;
public class ServerImpl extends UnicastRemoteObject implements MyService { private static final int REMOTE_PORT = 1098;
public ServerImpl() throws RemoteException { super(); }
public static void main(String argc[]) throws RemoteException { System.out.println("Server started."); System.out.println("Getting stub..."); ServerImpl obj = new ServerImpl(); MyService stub = (MyService)UnicastRemoteObject.toStub(obj);
System.out.println("Registrating RMI on port..." + REMOTE_PORT); Registry registry = LocateRegistry.createRegistry(REMOTE_PORT, new MySSLClientSocketFactory(), new MySSLServerSocketFactory());
System.out.println("Rebindind..."); registry.rebind("rmi:\\localhost:" + REMOTE_PORT + "\\MyService", stub); System.out.println("Server ready"); }
public String getTimeNow() throws RemoteException { return new Date().toString(); } }
|
Client.java| Код | package rclient;
import impls.MyService; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry;
public class Client { private static final int REMOTE_PORT = 1098;
public Client() throws RemoteException {
}
public static void main(String argc[]) throws RemoteException, NotBoundException { System.out.println("Client started."); System.out.println("Getting registry..."); Registry registry = LocateRegistry.getRegistry("localhost", REMOTE_PORT, new MySSLClientSocketFactory());
System.out.println("Getting stub..."); MyService stub = (MyService)registry.lookup("rmi:\\localhost:" + REMOTE_PORT + "\\MyService");
System.out.println("Getting date from server...\nDate is: "); System.out.println(stub.getTimeNow()); } }
|
Сервер запускается нормально, а вот client(run): | Цитата | run: Client started. Getting registry... Getting stub... Exception in thread "main" java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:286) at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184) at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322) at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source) at rclient.Client.main(Client.java:31) Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632) at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59) 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) ... 4 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217) at sun.security.validator.Validator.validate(Validator.java:218) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185) ... 15 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318) ... 21 more Java Result: 1
|
Т.е. ошибка возникает при попытке выполнить | Цитата | System.out.println("Getting stub..."); MyService stub = (MyService)registry.lookup("rmi:\\localhost:" + REMOTE_PORT + "\\MyService");
|
Т.е. почему-то клиенту не нравится сертификат сервера. Хотя оба сертификата импортированы в оба хранилища, и keytool -list -keystore "pathtostore" это подтверждают. В дополнение к этому посоветовали эту программу - она добавляет доверенный сертификат сервера в хранилище, если он там отсутствует. Подсунул ей свое хранилище, результат - No errors, certificate is already trusted. Не понимаю, как такое возможно, из за чего? Может что в создании защищенного RMI сокета косяк? Проверял несколько раз, вроде все правильно...
|