How to set keystore and truststore without using System.setProperty() - java

I've got a client certificate in my keystore, and server's public certificate in my truststore.
Currently, I'm setting my keystore and trustore as
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
System.setProperty("javax.net.ssl.keyStore", Constants.APPLICATION_HOME + File.separatorChar + this.certificateName);
System.setProperty("javax.net.ssl.keyStorePassword", certificatePass);
System.setProperty("javax.net.ssl.trustStore", Constants.APPLICATION_HOME + File.separatorChar + "jssecacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
But I want to do it without using System.setProperty(). At least the keystore part, truststore can stay this way since it never changes. I tried this:
keyStore = KeyStore.getInstance("PKCS12");
InputStream keyStoreData = new FileInputStream(Constants.APPLICATION_HOME + File.separatorChar + this.certificateName);
this.keyStore.load(keyStoreData, certificatePass.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(this.keyStore);
TrustManager[] trustManagers = trustFactory.getTrustManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
SSLContext.setDefault(sslContext);
But that's setting the truststore as far as I can see, and my handshake therefore fails because now I've only got a client certificate in my truststore, and not a server certificate from my jssecacerts file. It fails with this error:
http-bio-8080-exec-10, handling exception:
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
How do I achieve this?

This example can help you:
import java.io.File;
import java.io.FileInputStream;
import java.net.InetAddress;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.security.KeyStore;
import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
public class EventWebSocketSecureServer extends EventWebSocketServer {
private static EventWebSocketSecureServer instance;
public static EventWebSocketSecureServer instance() {
return instance;
}
public EventWebSocketSecureServer(int port, InetAddress ip) {
this(port, null, null, ip);
}
public EventWebSocketSecureServer(int port, String keystorepath, String keystorepassword, InetAddress ip) {
super(port, ip);
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
char ksPassword[] = keystorepassword.toCharArray();
if (!keystorepath.equals("")) {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(new File(keystorepath)), ksPassword);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ksPassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} else {
sslContext.init(null, null, null);
}
this.setWebSocketFactory(new DefaultSSLWebSocketServerFactory(sslContext));
} catch (Exception e) {
com.gmt2001.Console.out.println("Secure EventSocketServer failed: " + e);
e.printStackTrace();
}
}
}
https://www.programcreek.com/java-api-examples/?code=GloriousEggroll/quorrabot/quorrabot-master/src/com/simeonf/EventWebSocketSecureServer.java

Related

HttpsParameters cannot be resolved to a type

I want to secure my http request ,Im using something like http://123.456.789.123:1234 and I want secure it. I create a keystore.csr carets.jks server.cer and keystore.jks with the java keytool after that I implement my code, but it can't read HttpsParameters
String alias = "alias";
char [] storepass = "changeit".toCharArray();
String keystoreName = "c:\\keystore.jks";
FileInputStream in = new FileInputStream(keystoreName);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(in, storepass);
Certificate cert = keystore.getCertificate(alias);
Log.debug("the certification is here : " + cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
char [] keypass = "changeit".toCharArray();
kmf.init(keystore, keypass);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
HttpsServer server = HttpsServer.create(new InetSocketAddress(port), 0);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
SSLContext c = SSLContext.getDefault();
SSLEngine engine = c.createSSLEngine();
params.setNeedClientAuth(false);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
SSLParameters defaultSSLParameters=c.getDefaultSSLParameters();
params.setSSLParameters(defaultSSLParameters);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Failed to create HTTPS server");
}
}
});`
I did a mistake that I forgot to add the import to my class
import com.sun.net.httpserver.HttpsParameters;

Doubts about writing Java SSL client and server using keystore and truststore

I have created keystore, truststore, private key and certificate using keytool as follows:
Creating keystore, private key and certificate
keytool -genkey -alias ssl_key -keyalg RSA -keypass passwd123 -keystore keystore.jks -storepass passwd123
Exporting certificate from keystore to truststore
keytool -import -v -trustcacerts -alias ssl_key -keypass passwd123 -file ssl_key.cer -keystore truststore.jks -storepass passwd123
Now I wanted to write java SSL client server. I referred some articles (1,2)and code online and wrote simple Java SSL server and client as follows:
Server
public class Server {
static KeyStore ks;
static KeyManagerFactory kmf;
static TrustManagerFactory tmf;
static SSLContext sc;
static TrustManager[] trustManagers;
static {
try {
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("D:\\javasslstores\\keystore.jks"), "passwd123".toCharArray());
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "passwd123".toCharArray());
tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
}
}
public static void main(String[] args) throws IOException {
System.out.println("SSL Server");
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
SSLServerSocket s = (SSLServerSocket) ssf.createServerSocket(8089);
System.out.println("Listening on port 8089");
SSLSocket socket = (SSLSocket) s.accept();
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String line;
System.out.println("Data from client:");
while((line = bufferedReader.readLine()) != null){
System.out.println(line);
out.println(line);
}
}
System.out.println("Closed");
}
}
Client
public class Client {
static KeyStore ks;
static KeyManagerFactory kmf;
static TrustManagerFactory tmf;
static SSLContext sc;
static TrustManager[] trustManagers;
static
{
try
{
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("D:\\javasslstores\\keystore.jks"), "passwd123".toCharArray());
kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "passwd123".toCharArray());
tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.getStackTrace());
}
}
public static void main(String[] args) throws IOException {
SSLSocketFactory ssf = sc.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket("localhost", 8089);
socket.startHandshake();
PrintWriter out = new PrintWriter
(new BufferedWriter
(new OutputStreamWriter
(socket.getOutputStream())));
System.out.println("SSL Client");
out.println("GET / HTTP/1.0");
out.println("From java ssl client");
out.println("written by me");
out.flush();
if (out.checkError())
System.out.println("SSLSocketClient: java.io.PrintWriter error");
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
out.close();
socket.close();
}
}
Above code works.
Doubts
But I have following doubts:
What to do?: Pass either keystore or truststore to client and server or both?
Looking at examples at link 1, I have specified keystore and truststore in both client and server. That is I have following line in both:
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); //point 0
If I understand it correctly, server needs keystore and client need trustore. Thus, having following in server:
sc.init(kmf.getKeyManagers(), null, null); //point 1
and following in client:
sc.init(null, tmf.getTrustManagers(), null); //point 2
also works. But having this:
sc.init(null, tmf.getTrustManagers(), null);
in server AND/OR this:
sc.init(kmf.getKeyManagers(), null, null);
in client fails.
So am I correct with point 1 and 2 above?
When I need to specify both truststore and keystore as in point 0?
Which key and certificate is used if there are multiple of them for communication over SSL?
Keystore and truststore contains only single key and certificate.
But in code, I didnt specify which key and certificate to use. I
dont even know if I have to specify them explicitly. What if I have
multiple keys and certificates in the stores? Do I have to specify
which one to use explicitly. If yes, how can I do it? (It seems that am missing something basic :\ )
Are there any official examples on oracle site explaining writing java SSL server and client using keystore and truststore?

javax.net.ssl.SSLHandshakeException: null cert chain java error

Am trying to establish an ssl connection.I have a Server and I have a client. I have both of them running on the same machine. am trying to establish an SSL connection between the client and the server. i have generated certificates for both the server and the client with the following keytool command.
For Client
keytool -keystore clientstore -genkey -alias client -validity 3650
Then i export the root certificate of the client to a cer file callled client.cer
For Server
keytool -keystore serverstore -genkey -alias server -validity 3650 Then i export the root certificate of the server to a cer file callled server.cer
I now import the client certificate "client.cer" into the serverstore keystore with the following command
keytool -import -keystore serverstore -file client.cer -alias client
And also import the servers certificate "server.cer" into the clientstore keystore with the following command
keytool -import -keystore clientstore -file server.cer -alias server
After doing this, i imported both the server.cer and client.cer into the cacerts Keystore. But when i try to establish an ssl connection, i get this error on the server javax.net.ssl.SSLHandshakeException: null cert chain and this error on the client javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate.
My Servers Code.
package serverapplicationssl;
import java.io.*;
import java.security.KeyStore;
import java.security.Security;
import java.security.PrivilegedActionException;
import javax.net.ssl.*;
import com.sun.net.ssl.internal.ssl.Provider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
import java.io.*;
public class ServerApplicationSSL {
public static void main(String[] args) {
boolean debug = true;
System.out.println("Waiting For Connection");
int intSSLport = 4447;
{
Security.addProvider(new Provider());
}
if (debug) {
System.setProperty("javax.net.debug", "all");
}
FileWriter file = null;
try {
file = new FileWriter("C:\\SSLCERT\\Javalog.txt");
} catch (Exception ee) {
//message = ee.getMessage();
}
try {
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("C:\\SSLCERT\\OntechServerKS"), "server".toCharArray());
file.write("Incoming Connection\r\n");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keystore, "server".toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory sslServerSocketfactory = (SSLServerSocketFactory) context.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketfactory.createServerSocket(intSSLport);
sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites());
sslServerSocket.setNeedClientAuth(true);
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
//SSLServerSocket server_socket = (SSLServerSocket) sslServerSocket;
sslSocket.startHandshake();
// Start the session
System.out.println("Connection Accepted");
file.write("Connection Accepted\r\n");
while (true) {
PrintWriter out = new PrintWriter(sslSocket.getOutputStream(), true);
String inputLine;
//while ((inputLine = in.readLine()) != null) {
out.println("Hello Client....Welcome");
System.out.println("Hello Client....Welcome");
//}
out.close();
//in.close();
sslSocket.close();
sslServerSocket.close();
file.flush();
file.close();
}
} catch (Exception exp) {
try {
System.out.println(exp.getMessage() + "\r\n");
exp.printStackTrace();
file.write(exp.getMessage() + "\r\n");
file.flush();
file.close();
} catch (Exception eee) {
//message = eee.getMessage();
}
}
}
}
Here's My Clients Code
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.Enumeration;
import javax.net.ssl.*;
public class SSLConnect {
public String MakeSSlCall(String meternum) {
String message = "";
FileWriter file = null;
try {
file = new FileWriter("C:\\SSLCERT\\ClientJavalog.txt");
} catch (Exception ee) {
message = ee.getMessage();
}
//writer = new BufferedWriter(file );
try {
file.write("KeyStore Generated\r\n");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("C:\\SSLCERT\\SkyeClientKS"), "client".toCharArray());
file.write("KeyStore Generated\r\n");
Enumeration enumeration = keystore.aliases();
while (enumeration.hasMoreElements()) {
String alias = (String) enumeration.nextElement();
file.write("alias name: " + alias + "\r\n");
keystore.getCertificate(alias);
file.write(keystore.getCertificate(alias).toString() + "\r\n");
}
TrustManagerFactory tmf =TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
file.write("KeyStore Stored\r\n");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
SSLSocketFactory f = context.getSocketFactory();
file.write("About to Connect to Ontech\r\n");
SSLSocket c = (SSLSocket) f.createSocket("192.168.1.16", 4447);
file.write("Connection Established to 196.14.30.33 Port: 8462\r\n");
file.write("About to Start Handshake\r\n");
c.startHandshake();
file.write("Handshake Established\r\n");
file.flush();
file.close();
return "Connection Established";
} catch (Exception e) {
try {
file.write("An Error Occured\r\n");
file.write(e.getMessage() + "\r\n");
StackTraceElement[] arrmessage = e.getStackTrace();
for (int i = 0; i < arrmessage.length; i++) {
file.write(arrmessage[i] + "\r\n");
}
file.flush();
file.close();
} catch (Exception eee) {
message = eee.getMessage();
}
return "Connection Failed";
}
}
}
Stack Trace Execption on my Server
javax.net.ssl.SSLHandshakeException: null cert chain
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
at sun.security.ssl.ServerHandshaker.clientCertificate(ServerHandshaker.java:1804)
at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:222)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at serverapplicationssl.ServerApplicationSSL.main(ServerApplicationSSL.java:69)
Stack Trace Execption on my client
Received fatal alert: bad_certificate
sun.security.ssl.Alerts.getSSLException(Unknown Source)
sun.security.ssl.Alerts.getSSLException(Unknown Source)
sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
SSLConnect.MakeSSlCall(SSLConnect.java:96)
BankCollectSSLCon.main(BankCollectSSLCon.java:13)
What could be causing this error?, could it be because i am running both the server and the client on the same machine?...Been on this for quite a while now. i need help
Please try to include this code snippet so that all the certificates will be trusted.
public static void trustSelfSignedSSL() {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string)
throws CertificateException {}
public void checkServerTrusted(X509Certificate[] xcs, String string)
throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLContext.setDefault(ctx);
} catch (Exception ex) {
// LOGGER.error("Exception : ", ex.getStackTrace());
System.out.println(ex.getStackTrace());
}

How can I get the public key of a secure webpage using java

I need to get the public keys of a secured website programmatically through java. I have read this, this, this and this and others as well.
But I haven't found a solution of getting it through java.
EDIT:::
Based on Zielu's answer I wrote the following program:
import java.security.PublicKey;
import java.security.cert.Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class RetrievePublicKey {
private static PublicKey getKey(String hostname, int port) throws Exception {
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(hostname, port);
socket.startHandshake();
Certificate[] certs = socket.getSession().getPeerCertificates();
Certificate cert = certs[0];
PublicKey key = cert.getPublicKey();
System.out.println(key);
return key;
}
public static void main(String[] args) throws Exception {
System.out.println(getKey("bctcl-parasuram.bctchn.local", 8443));
}
}
But when I run it, i get the following exception:
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
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at RetrievePublicKey.getKey(RetrievePublicKey.java:22)
at RetrievePublicKey.main(RetrievePublicKey.java:30)
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:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460)
... 9 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 15 more
You can use SSLSocket to get the certificate and its public key:
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.security.cert.Certificate;
...
String hostname = "your.host";
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(hostname, 443);
socket.startHandshake();
Certificate[] certs = socket.getSession().getPeerCertificates();
Certificate cert = certs[0];
PublicKey key = cert.getPublicKey();
It works only if the certificate is valid (not self signed or signed by unknown authority). For self signed certificates, you can define your own TrustManager that will trust everything. See Allowing Java to use an untrusted certificate for SSL/HTTPS connection
But it should be avoided if can, as this kind of code left behind creates a security issue later on.
Getting the cert when the server is recognized by the app can be done using Zielu's answer. However if the server is unrecognized (e.g. self signed or signed by unknown root authority that is not contained in your JVM's keystore) you can retrieve the server's cert programmatically using InstallCert. An abbreviated version follows:
[Warning: as stated by others, using an untrusted cert this way should be done only if you know and trust the cert owner otherwise it is a security risk.]
import javax.net.ssl.*;
import java.io.*;
import java.security.*;
import java.security.cert.*;
public class FetchCert {
public static void main(String[] args) throws Exception {
//REPLACE THIS WITH YOUR TARGET HOST NAME
String hostname = "example.com";
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(hostname, 443);
try {
socket.startHandshake();
socket.close();
System.out.println("No errors, certificate is already trusted");
return;
} catch (SSLException e) {
System.out.println("cert likely not found in keystore, will pull cert...");
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] password = "changeit".toCharArray();
ks.load(null, password);
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[]{tm}, null);
factory = context.getSocketFactory();
socket = (SSLSocket) factory.createSocket(hostname, 443);
try {
socket.startHandshake();
} catch (SSLException e) {
//we should get to here
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("Could not obtain server certificate chain");
return;
}
X509Certificate cert = chain[0];
String alias = hostname;
ks.setCertificateEntry(alias, cert);
System.out.println("saving file jssecacerts to working dir");
System.out.println("copy this file to your jre/lib/security folder");
FileOutputStream fos = new FileOutputStream("jssecacerts");
ks.store(fos, password);
fos.close();
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
}

Access java keystore programmatically to create SSLSocketFactory

I am establishing an SSL connection to a server which has enabled ssl.There is a cacerts file in my hardware's filesystem java keystore and I extracted the certificate from it using keytool & I am giving this certificate file to create an SSLSocketfactory to establish the ssl connection , which works fine with the code snippet below.
I wanted to know how to access the cacerts ( java keystore ) file directly , and pick the certificate and establish the ssl connection. Right now , I am packaging the extracted certicate in the classpath with my jar file , which is not a good practice as I want it to be loaded from the keystore.
Below is the working code snippet of how I create a SSLSocketFactory currently.
private SSLSocketFactory createSSLFactory() {
KeyStore keyStore = null;
TrustManagerFactory tmf = null;
SSLContext ctx = null;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
is = SSLConnection.class.getResourceAsStream("/" + "my-keystore");
keyStore.load(is, "changeit".toCharArray());
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();
return factory;
} catch (Exception e) {
// exception handling
}
return null;
}
It doesn't make any sense to embed a KeyStore into a JAR file in the case of private keys and authenticating certificates. A client certificate is supposed to uniquely identify the client. It is a property of a host, not a JAR file, which can be copied around infinitely. It doesn't make sense to allow the use of the same client certificates for multiple clients. It is a misuse of PKI.
You can pass the keystore (and truststore) as system properties to the JVM. See here: https://stackoverflow.com/a/882479/131929
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS
Then you can do
URL url = new URL("https://someurl");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
InputStream inputstream = conn.getInputStream();
You need to add a trust manager :
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
TrustManagerFactory tmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
tmf = TrustManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("testkeys"), passphrase);
kmf.init(ks, passphrase);
tmf.init(ks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
factory = ctx.getSocketFactory();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);

Categories

Resources