I have the following code:
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
public class TrackWrapper {
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" 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
*/
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
URL url = new URL("https://somedomain.com:1234");
URLConnection con = url.openConnection();
con.connect();
}
}
The first part of that is simply a copypasted quickfix to accept every certificate I've got from another StackOverflow Question (I'm sure that this isn't exactly ready for production), on the second part I try to connect to some SSL-secured site whichs client certificate is in my keystore, I receive the following error message:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
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:1806)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:986)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at TrackWrapper.main(TrackWrapper.java:54)
As I admittedly am rather clueless about SSL I'd be grateful for some insight and a walkthrough on how to fix this problem.
After some tries I now get the following error:
Exception in thread "main" java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:830)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1555)
at com.sun.net.ssl.internal.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:103)
at com.sun.net.ssl.internal.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:689)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:985)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:904)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:238)
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:925)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at TrackWrapper.main(TrackWrapper.java:54)
You should have correct SSL certificate in your keystore, of server to whom you are trying to connect. Check these examples. These are working for me.
example 1
example 2
You can export that server certificate from browser (if accessible) or there are other ways to get certificates over the internet. Your certificates should match. Once you get certificate you can make keystore from any tool. alternatively you can make keystore from this code.
Have you checked if you need a client certificate?
The error message could also be from the server side.
Also start your client with the parameter -Djavax.net.debug=all. There you should see some more hints about what failed.
Related
From the following website, I found codes to perform java AD authentication.
http://java2db.com/jndi-ldap-programming/solution-to-sslhandshakeexception
The followings are the codes:
MySSLSocketFactory.java
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
public class MySSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory socketFactory;
public MySSLSocketFactory() {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{new DummyTrustmanager()}, new SecureRandom());
socketFactory = ctx.getSocketFactory();
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
}
public static SocketFactory getDefault() {
return new MySSLSocketFactory();
}
#Override
public String[] getDefaultCipherSuites() {
return socketFactory.getDefaultCipherSuites();
}
#Override
public String[] getSupportedCipherSuites() {
return socketFactory.getSupportedCipherSuites();
}
#Override
public Socket createSocket(Socket socket, String string, int num, boolean bool) throws IOException {
return socketFactory.createSocket(socket, string, num, bool);
}
#Override
public Socket createSocket(String string, int num) throws IOException, UnknownHostException {
return socketFactory.createSocket(string, num);
}
#Override
public Socket createSocket(String string, int num, InetAddress netAdd, int i)
throws IOException, UnknownHostException {
return socketFactory.createSocket(string, num, netAdd, i);
}
#Override
public Socket createSocket(InetAddress netAdd, int num) throws IOException {
return socketFactory.createSocket(netAdd, num);
}
#Override
public Socket createSocket(InetAddress netAdd1, int num, InetAddress netAdd2, int i) throws IOException {
return socketFactory.createSocket(netAdd1, num, netAdd2, i);
}
}
DummyTrustmanager.java
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class DummyTrustmanager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] cert, String string) throws CertificateException
{
}
public void checkServerTrusted(X509Certificate[] cert, String string) throws CertificateException
{
}
public X509Certificate[] getAcceptedIssuers()
{
return new java.security.cert.X509Certificate[0];
}
}
TestAD.java
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class TestAD {
public static void main(String[] args) {
try {
//String url = "ldaps://abc.company.com:636";
String url = "ldaps://xyz.group.com:636";
String conntype = "simple";
// String id = "abc#abc.company.com";
String id = "xyz.group.com";
//String password = "abcpassword";
String password = "xyzpassword";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, url);
environment.put("java.naming.ldap.factory.socket", "MySSLSocketFactory");
environment.put(Context.SECURITY_AUTHENTICATION, conntype);
environment.put(Context.SECURITY_PRINCIPAL, id);
environment.put(Context.SECURITY_CREDENTIALS, password);
DirContext ldapContext = new InitialDirContext(environment);
System.out.println("Bind successful");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
My company has a few subsidiaries, and they have their own LDAPs. When I run TestAD against my company ABC's LDAP, it works fine. But when I run it against the subsidiary XYZ's LDAP, I got the following exception:
javax.naming.CommunicationException: simple bind failed: xyz.group.com:636
[Root exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.]
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:219)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2791)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:319)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.init(InitialContext.java:244)
at javax.naming.InitialContext.<init>(InitialContext.java:216)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101)
at TestAD.main(TestAD.java:26)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:931)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at com.sun.jndi.ldap.Connection.run(Connection.java:877)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching xyz.group.com found.
at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214)
at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:1125)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:1092)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
... 12 more
What could be the reason for the failure? I did not import ABC's or XYZ's certificate into my trust store. Why does it work fine for ABC but not for XYZ? Could it be that XYZ is expecting my certificate?
This caused by the endpoint identification algorithms, it checks the host name in your configuration matches the host name in your remote LDAPS TLS server certificate, and that those host names are valid.
Given this error No subject alternative DNS name matching xyz.group.com found, it must be that "xyz.group.com" doesn't match your ldap server certificate, while "abc.company.com" does match.
Java 8u181 brought some changes in core-libs/javax.naming and updated how secure LDAP connections are handled (cf. release note) :
Endpoint identification has been enabled on
LDAPS connections.
To improve the robustness of LDAPS (secure LDAP over TLS) connections,
endpoint identification algorithms have been enabled by default.
Note that there may be situations where some applications that were
previously able to successfully connect to an LDAPS server may no
longer be able to do so. Such applications may, if they deem
appropriate, disable endpoint identification using a new system
property: com.sun.jndi.ldap.object.disableEndpointIdentification.
Define this system property (or set it to true) to disable endpoint
identification algorithms.
Disabling the endpoint identification algorithms is a workaround, the long term solution is to fix the server certificate so that it matches "xyz.group.com" hostname.
I have been looking for answer everywhere and nothing help.
Thats my code :
BufferedImage img1 = ImageIO.read(new File(dir1));
URL url = new URL(image_srcURL);
BufferedImage img2 =
ImageIO.read(url.openStream());
Now I get the exception below when I'm trying to read the url.
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
java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java:198) at
java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1974)
at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:345)
at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:339)
at
java.base/sun.security.ssl.ClientHandshaker.checkServerCerts(ClientHandshaker.java:1968)
at
java.base/sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1777)
at
java.base/sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:264)
at
java.base/sun.security.ssl.Handshaker.processLoop(Handshaker.java:1098)
at
java.base/sun.security.ssl.Handshaker.processRecord(Handshaker.java:1026)
at
java.base/sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1137)
at
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1074)
at
java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at
java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at
java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
at
java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1581)
at
java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1509)
at
java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:245)
at
com.folderName.Tools.DataForAutomationV1.compareImg(DFA.java:606)
at
com.folderName.VendorTests.SettingsPage.editCompDets(SettingsPage.java:562)
at
com.folderName.VendorTests.SettingsPage.runTest(SettingsPage.java:62)
at com.folderName.Vendor.vendorTests(Vendor.java:36) at
com.folderName.Main.main(Main.java:40) 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
java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at
java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290)
at
java.base/sun.security.validator.Validator.validate(Validator.java:264)
at
java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:343)
at
java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:226)
at
java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:133)
at
java.base/sun.security.ssl.ClientHandshaker.checkServerCerts(ClientHandshaker.java:1947)
... 20 more Caused by:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target at
java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at
java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at
java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
at
java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 26 more
Any help would be great.
I'm trying to read an image inside the url and compare it to an existing file.
There wasn't any questions here that gave the answer.
Edit:
I've try to enter in my command line " keytool -list -keystore keystore ", but it showed me only trustedCertEntries. No solution worked yet.
Below is an example of how I implemented it. The code reads the the response body into an awt BufferedImage, then writes to a .jpg file, then reads the file back into a byte array and then deletes the file. I'm sure I found help with this on SO but I don't have the answer handy. I will try to find that so I can cite. Hope it helps you!
**Edit as #Srikanthkumar mentions in his answer, you will also need to get the cert and add it to your truststore of your JVM. You can get that through a browser via whatever browser you have cert exploring tools.
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.util.Base64;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Override
public String getImage(String productNumber) throws EcomWebException {
try {
BufferedImage image = ImageIO.read(url);
File file = new File(guid.toString() + ".jpg");
ImageIO.write(image, "jpg", file);
String base64ImageString = Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
file.delete();
return base64ImageString;
} catch (Exception e) {
throw new EcomWebException(IMAGE_NOT_FOUND_MESSAGE + productNumber, e);
}
}
First you need to obtain the certificate of the server, add it to a keystone file, either to the java truststore in jre or a separate file. If you are creating a new truststore then make sure that you supply truststore to your program
The following snippet from this post may help you:
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType
) {}
#Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType
) {}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
Trying to setup a simple RMI server with SSL encryption. It's for a simple chat application that has a java server app and a java client app, however, I can't even get it working with a simple RMI example at the moment!
The only way I can get it to work is if both the client & server have both the same truststore & keystore. To me though, this sounds incorrect as it means each client has the server's private key too..
I followed this guide to create the trust/keystores. I first tried generating a keystore & truststore and just running the server with the keystore & the client with the truststore. That didn't work so I then generated a pair for each and loaded as shown in the code below.
It think I might be missing something obvious somewhere just can't for the life of my figure out what I'm doing wrong. I currently have the following, but when running the server I get the errors below:
Error:
Server exception: 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
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(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.newCall(Unknown Source)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at Server.main(Server.java:38)
Hello.java
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
Server.java
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
public class Server extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = 5186776461749320975L;
protected Server(int port) throws IOException {
super(port, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
}
#Override
public String sayHello() {
return "Hello, world!";
}
public static void main(String[] args) throws RemoteException, IllegalArgumentException {
try {
setSettings();
Server server = new Server(2020);
LocateRegistry.createRegistry(2020, new SslRMIClientSocketFactory(), new SslRMIServerSocketFactory(null, null, true));
System.out.println("RMI registry running on port " + 2020);
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
registry.bind("Hello", server);
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\serverkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\servertruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
Client.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.rmi.ssl.SslRMIClientSocketFactory;
public class Client {
private Client() {}
public static void main(String[] args) {
try {
setSettings();
Registry registry = LocateRegistry.getRegistry("DAVE-PC", 2020, new SslRMIClientSocketFactory());
Hello hello = (Hello) registry.lookup("Hello");
String message = hello.sayHello();
System.out.println(message);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
private static void setSettings() {
String pass = "password";
System.setProperty("javax.net.ssl.debug", "all");
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\clientkeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", pass);
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\clienttruststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", pass);
}
}
The PKIX error means that the client didn't trust the server certificate, where the server in this case was the Registry.
To clarify, you need two private keys and two keystores to hold them in, one each. You then need to create certificates in each keystore, export them, and import them into the peer's truststore. The server's truststore must trust the client's keystore, and vice versa.
Your code looks mostly OK. The result of createRegistry() should be stored in a static variable, to prevent it being GC'd. You don't need a serialVersionUID in the server class, whatever your IDE may tell you. It doesn't get serialized, at least not by RMI.
EDIT The problem is here:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks");
which should be:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-server.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks");
and here:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-server.jks"
which should be:
System.setProperty("javax.net.ssl.keyStore", "C:\\ssl\\keystore-client.jks");
System.setProperty("javax.net.ssl.trustStore", "C:\\ssl\\truststore-client.jks"
EDIT 2 The underlying problem is that the trust store you need when binding to the Registry is the client truststore, but the truststore you need when running the server is the server truststore.
There are at least three possible solutions, in increasing order of merit:
Set up a subclass of SslRMIClientSocketFactory with its own SSLContext with its own TrustManager loaded from the client truststore, and override createSocket(). Ouch.
Import the server's certificate into the server's truststore as well.
Use the return value of createRegistry() to do the bind() instead of calling getRegistry() in the server at all, and avoid the whole problem.
I am getting "java.lang.ClassCastException" while trying to connect to a url using javax.net.ssl.HttpsURLConnection .
I am using Weblogic Server 10.3.4.
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* #author kmrgtm
*
*/
public class GatewayConnect {
public void ConnectURL()
{
try
{
System.out.println("***** Inside Class File *****");
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
String urlstr="https://www.google.co.in";
URL url = new URL(urlstr);
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn = (HttpsURLConnection)url.openConnection();
if (conn instanceof javax.net.ssl.HttpsURLConnection) {
System.out.println("*** openConnection returns an instanceof javax.net.ssl.HttpsURLConnection");
}
if (conn instanceof HttpURLConnection) {
System.out.println("*** openConnection returns an instnace of HttpURLConnection");
}
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader( conn.getInputStream()));
for (String line; (line = reader.readLine()) != null;) {
System.out.println("##### line iz :::"+line);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
The exception which i am getting is :
**java.lang.ClassCastException: weblogic.net.http.SOAPHttpsURLConnection cannot be cast to javax.net.ssl.HttpsURLConnection
Inside the MessageSendingAction
***** Inside Class File *****
at com.secureConnect.GatewayConnect.ConnectURL(GatewayConnect.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.el.parser.AstValue.invoke(Unknown Source)
at com.sun.el.MethodExpressionImpl.invoke(Unknown Source)
at javax.faces.component._MethodExpressionToMethodBinding.invoke(_MethodExpressionToMethodBinding.java:78)
at org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:57)
at javax.faces.component.UICommand.broadcast(UICommand.java:127)
at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:329)
at org.ajax4jsf.component.AjaxViewRoot.broadcastEventsForPhase(AjaxViewRoot.java:304)
at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:261)
at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:474)
at org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:32)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:103)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:76)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:183)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:206)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:207)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:176)**
Any possible reason of getting this error ?
I got the solution finally. If we are using Weblogic server, we must define:
set JAVA_OPTIONS=%JAVA_OPTIONS% -DUseSunHttpHandler=true
...in the class path inside the Server Domain.
This will tell the weblogic server to use the Sun Http Handlers and not install its own.
You also may explicitly define protocol handler. Just create URL using another constructor.
URL url = new URL(null, urlstr, new sun.net.www.protocol.http.Handler());
or
URL url = new URL(null, urlstr, new sun.net.www.protocol.https.Handler());
And it will make the code independent from -DUseSunHttpHandler option.
Begin from 12.2.1.3.0 you can to enable the new compatible HTTPS connection implementation class by using a new Java system property -DUseJSSECompatibleHttpsHandler=true to get a HttpsURLConnection instance extending javax.net.ssl.HttpsURLConnection.
weblogic.net.http.CompatibleSOAPHttpsURLConnection (extending
javax.net.ssl.HttpsURLConnection) is returned instead of
weblogic.net.http.SOAPHttpsURLConnection (not extending
javax.net.ssl.HttpsURLConnection) that can avoid the ClassCastException
Please note that when both -DUseSunHttpHandler=true and -DUseJSSECompatibleHttpsHandler=true are specified, -DUseSunHttpHandler will take precedence over -DUseJSSECompatibleHttpsHandler.
More detail on #KmrGtm solution:
Only thing to do is updating WebLogic domain settings in the setDomainEnv script file.
The relevant settings are in the setDomainEnv script file (setDomainEnv.cmd for Windows and setDomainEnv.sh for Linux).
The file is located in the bin subdirectory of the domain directory (/user_projects/domains//bin/) where:
is the directory where you installed WebLogic.
is the name of the domain where you are installing Studio.
In the file add the JAVA_OPTIONS argument close to the top of the file:
For setDomainEnv.cmd (Windows):
set JAVA_OPTIONS=%JAVA_OPTIONS% -DUseSunHttpHandler=true
For setDomainEnv.sh (Linux):
JAVA_OPTIONS="%JAVA_OPTIONS% -DUseSunHttpHandler=true"
export JAVA_OPTIONS
java.lang.ClassCastException: weblogic.net.http.SOAPHttpsURLConnection cannot be cast to javax.net.ssl.HttpsURLConnection (Doc ID 2332805.1)
According to the Oracle document above, the parameter
-DUseJSSECompatibleHttpsHandler=true
should be used.
This code connects to a HTTPS site and I am assuming I am not verifying the certificate. But why don't I have to install a certificate locally for the site? Shouldn't I have to install a certificate locally and load it for this program or is it downloaded behind the covers? Is the traffic between the client to the remote site still encrypted in transmission?
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class TestSSL {
public static void main(String[] args) throws Exception {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
URL url = new URL("https://www.google.com");
URLConnection con = url.openConnection();
final Reader reader = new InputStreamReader(con.getInputStream());
final BufferedReader br = new BufferedReader(reader);
String line = "";
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} // End of main
} // End of the class //
The reason why you don't have to load a certificate locally is that you've explicitly chosen not to verify the certificate, with this trust manager that trusts all certificates.
The traffic will still be encrypted, but you're opening the connection to Man-In-The-Middle attacks: you're communicating secretly with someone, you're just not sure whether it's the server you expect, or a possible attacker.
If your server certificate comes from a well-known CA, part of the default bundle of CA certificates bundled with the JRE (usually cacerts file, see JSSE Reference guide), you can just use the default trust manager, you don't have to set anything here.
If you have a specific certificate (self-signed or from your own CA), you can use the default trust manager or perhaps one initialised with a specific truststore, but you'll have to import the certificate explicitly in your trust store (after independent verification), as described in this answer. You may also be interested in this answer.
But why don't I have to install a certificate locally for the site?
Well the code that you are using is explicitly designed to accept the certificate without doing any checks whatsoever. This is not good practice ... but if that is what you want to do, then (obviously) there is no need to install a certificate that your code is explicitly ignoring.
Shouldn't I have to install a certificate locally and load it for this program or is it downloaded behind the covers?
No, and no. See above.
Is the traffic between the client to the remote site still encrypted in transmission?
Yes it is. However, the problem is that since you have told it to trust the server's certificate without doing any checks, you don't know if you are talking to the real server, or to some other site that is pretending to be the real server. Whether this is a problem depends on the circumstances.
If we used the browser as an example, typically a browser doesn't ask the user to explicitly install a certificate for each ssl site visited.
The browser has a set of trusted root certificates pre-installed. Most times, when you visit an "https" site, the browser can verify that the site's certificate is (ultimately, via the certificate chain) secured by one of those trusted certs. If the browser doesn't recognize the cert at the start of the chain as being a trusted cert (or if the certificates are out of date or otherwise invalid / inappropriate), then it will display a warning.
Java works the same way. The JVM's keystore has a set of trusted certificates, and the same process is used to check the certificate is secured by a trusted certificate.
Does the java https client api support some type of mechanism to download certificate information automatically?
No. Allowing applications to download certificates from random places, and install them (as trusted) in the system keystore would be a security hole.
Use the latest X509ExtendedTrustManager instead of X509Certificate as advised here: java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
package javaapplication8;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
/**
*
* #author hoshantm
*/
public class JavaApplication8 {
/**
* #param args the command line arguments
* #throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" 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
*/
TrustManager[] trustAllCerts = new TrustManager[]{
new X509ExtendedTrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
#Override
public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle) throws CertificateException {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
URL url = new URL("https://10.52.182.224/cgi-bin/dynamic/config/panel.bmp");
URLConnection con = url.openConnection();
//Reader reader = new ImageStreamReader(con.getInputStream());
InputStream is = new URL(url.toString()).openStream();
// Whatever you may want to do next
}
}
Java and HTTPS url connection without downloading certificate
If you really want to avoid downloading the server's certificate, then use an anonymous protocol like Anonymous Diffie-Hellman (ADH). The server's certificate is not sent with ADH and friends.
You select an anonymous protocol with setEnabledCipherSuites. You can see the list of cipher suites available with getEnabledCipherSuites.
Related: that's why you have to call SSL_get_peer_certificate in OpenSSL. You'll get a X509_V_OK with an anonymous protocol, and that's how you check to see if a certificate was used in the exchange.
But as Bruno and Stephed C stated, its a bad idea to avoid the checks or use an anonymous protocol.
Another option is to use TLS-PSK or TLS-SRP. They don't require server certificates either. (But I don't think you can use them).
The rub is, you need to be pre-provisioned in the system because TLS-PSK is Pres-shared Secret and TLS-SRP is Secure Remote Password. The authentication is mutual rather than server only.
In this case, the mutual authentication is provided by a property that both parties know the shared secret and arrive at the same premaster secret; or one (or both) does not and channel setup fails. Each party proves knowledge of the secret is the "mutual" part.
Finally, TLS-PSK or TLS-SRP don't do dumb things, like cough up the user's password like in a web app using HTTP (or over HTTPS). That's why I said each party proves knowledge of the secret...
A simple, but not pure java solution, is to shell out to curl from java, which gives you complete control over how the request is done. If you're just doing this for something simple, this allows you to ignore certificate errors at times, by using this method. This example shows how to make a request against a secure server with a valid or invalid certificate, pass in a cookie, and get the output using curl from java.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyTestClass
{
public static void main(String[] args)
{
String url = "https://www.google.com";
String sessionId = "faf419e0-45a5-47b3-96d1-8c62b2a3b558";
// Curl options are:
// -k: ignore certificate errors
// -L: follow redirects
// -s: non verbose
// -H: add a http header
String[] command = { "curl", "-k", "-L", "-s", "-H", "Cookie: MYSESSIONCOOKIENAME=" + sessionId + ";", "-H", "Accept:*/*", url };
String output = executeShellCmd(command, "/tmp", true, true);
System.out.println(output);
}
public String executeShellCmd(String[] command, String workingFolder, boolean wantsOutput, boolean wantsErrors)
{
try
{
ProcessBuilder pb = new ProcessBuilder(command);
File wf = new File(workingFolder);
pb.directory(wf);
Process proc = pb.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
StringBuffer sb = new StringBuffer();
String newLine = System.getProperty("line.separator");
String s;
// read stdout from the command
if (wantsOutput)
{
while ((s = stdInput.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
// read any errors from the attempted command
if (wantsErrors)
{
while ((s = stdError.readLine()) != null)
{
sb.append(s);
sb.append(newLine);
}
}
String result = sb.toString();
return result;
}
catch (IOException e)
{
throw new RuntimeException("Problem occurred:", e);
}
}
}
If you are using any Payment Gateway to hit any url just to send a message, then i used a webview by following it :
How can load https url without use of ssl in android webview
and make a webview in your activity with visibility gone. What you need to do : just load that webview.. like this:
webViewForSms.setWebViewClient(new SSLTolerentWebViewClient());
webViewForSms.loadUrl(" https://bulksms.com/" +
"?username=test&password=test#123&messageType=text&mobile="+
mobileEditText.getText().toString()+"&senderId=ATZEHC&message=Your%20OTP%20for%20A2Z%20registration%20is%20124");
Easy.
You will get this: SSLTolerentWebViewClient from this link:
How can load https url without use of ssl in android webview