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());
}
Related
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
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?
I have been googling this error for hours and nothing worked so far and tbh I have no idea why...I generate my certificates like this:
client:
keytool -genkey -alias babicaprivate -keystore babica.private -storetype JKS -keyalg rsa -dname "CN=Babica" -storepass babicapwd -keypass babicapwd -validity 365
keytool -export -alias babicaprivate -keystore babica.private -file temp.key -storepass babicapwd
keytool -import -noprompt -alias babicapublic -keystore client.public -file temp.key -storepass public
del temp.key
server:
keytool -genkey -alias serverprivate -keystore server.private -storetype JKS -keyalg rsa -dname "CN=localhost" -storepass serverpwd -keypass serverpwd -validity 365
keytool -export -alias serverprivate -keystore server.private -file temp.key -storepass serverpwd
keytool -import -noprompt -alias serverpublic -keystore server.public -file temp.key -storepass public
del temp.key
this gives me public and private certificates for server and client
then I start the server and client and when I try to sign on the server and try to read the "Common name" from the client on server with
Socket newClientSocket = ss.accept();
((SSLSocket)newClientSocket).startHandshake();
String username = ((SSLSocket) newClientSocket).getSession().getPeerPrincipal().getName();
and it's the username fetching that gives me the error and I have no idea why. Is there something wrong with how I make the certificates?
Here is my full code for server:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.net.ssl.*;
import java.security.*;
public class ChatServer {
protected List<Socket> clients = new ArrayList<Socket>(); // list of clients
private String[][] portUserPair = new String[10][2];
int i = 0;
private String passphrase = "serverpwd";
private int port = 1234;
public static void main(String[] args) throws Exception {
new ChatServer();
}
public ChatServer() throws Exception {
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.public"), "public".toCharArray());
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.private"), passphrase.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(serverKeyStore, passphrase.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLContext.setDefault(sslContext);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), (new SecureRandom()));
SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket ss = (SSLServerSocket) factory.createServerSocket(port);
ss.setNeedClientAuth(false);
ss.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
// start listening for new connections
System.out.println("[system] listening ...");
try {
while (true) {
Socket newClientSocket = ss.accept(); // wait for a new client connection
((SSLSocket)newClientSocket).startHandshake();
String username = ((SSLSocket) newClientSocket).getSession().getPeerPrincipal().getName();
System.out.println("Established SSL connection with: " + username);
synchronized(this) {
portUserPair[i][0] = Integer.toString(newClientSocket.getPort());
clients.add(newClientSocket); // add client to the list of clients
}
ChatServerConnector conn = new ChatServerConnector(this, newClientSocket); // create a new thread for communication with the new client
conn.start(); // run the new thread
}
} catch (Exception e) {
System.err.println("[error] Accept failed.");
e.printStackTrace(System.err);
System.exit(1);
}
// close socket
System.out.println("[system] closing server socket ...");
try {
ss.close();
} catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
// send a message to all clients connected to the server
public void sendToAllClients(String message) throws Exception {
Iterator<Socket> i = clients.iterator();
while (i.hasNext()) { // iterate through the client list
Socket socket = (Socket) i.next(); // get the socket for communicating with this client
try {
DataOutputStream out = new DataOutputStream(socket.getOutputStream()); // create output stream for sending messages to the client
out.writeUTF(message); // send message to the client
} catch (Exception e) {
System.err.println("[system] could not send message to a client");
e.printStackTrace(System.err);
}
}
}
public void sendToAClient(String message, String userInfo) throws Exception {
Socket userSocket = null;
String userPort = "";
Iterator<Socket> i = clients.iterator();
for (int k = 0; k < portUserPair.length; k++) {
if(portUserPair[k][1].equals(userInfo)) {
userPort = portUserPair[k][0];
break;
}
}
System.out.println(userPort);
while (i.hasNext()) { // iterate through the client list
Socket socket = (Socket) i.next(); // get the socket for communicating with this client
if(Integer.toString(socket.getPort()).equals(userPort)) {
userSocket = socket;
break;
}
}
message = message.substring(userInfo.length()+2);
try {
DataOutputStream out = new DataOutputStream(userSocket.getOutputStream()); // create output stream for sending messages to the client
out.writeUTF(message); // send message to the client
} catch (Exception e) {
System.err.println("[system] could not send message to the client");
e.printStackTrace(System.err);
}
}
public void removeClient(Socket socket) {
synchronized(this) {
clients.remove(socket);
}
}
public void saveUserInfo(String userInfo) {
portUserPair[i][1] = userInfo;
System.out.println(portUserPair[i][0] + " : " + portUserPair[i][1]);
i++;
}
}
class ChatServerConnector extends Thread {
private ChatServer server;
private Socket socket;
public ChatServerConnector(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
public void run() {
System.out.println("[system] connected with " + this.socket.getInetAddress().getHostName() + ":" + this.socket.getPort());
DataInputStream in;
try {
in = new DataInputStream(this.socket.getInputStream()); // create input stream for listening for incoming messages
} catch (IOException e) {
System.err.println("[system] could not open input stream!");
e.printStackTrace(System.err);
this.server.removeClient(socket);
return;
}
while (true) { // infinite loop in which this thread waits for incoming messages and processes them
String msg_received;
try {
msg_received = in.readUTF(); // read the message from the client
} catch (Exception e) {
System.err.println("[system] there was a problem while reading message client on port " + this.socket.getPort());
e.printStackTrace(System.err);
this.server.removeClient(this.socket);
return;
}
if (msg_received.length() == 0) // invalid message
continue;
String[] msg = msg_received.split(" ");
System.out.println(msg_received);
if (msg[1].equals("system")) {
// try {
// server.saveUserInfo(((SSLSocket) socket).getSession().getPeerPrincipal().getName());
// } catch (SSLPeerUnverifiedException ex) {
// Logger.getLogger(ChatServerConnector.class.getName()).log(Level.SEVERE, null, ex);
// }
continue;
}
System.out.println(msg_received); // print the incoming message in the console
String msg_send = msg_received.toUpperCase();
if (msg[3].charAt(0) == '/') {
String[] privateMsg = msg[3].split(" ");
try {
this.server.sendToAClient(msg_send, privateMsg[0].replace("/", "")); // send message to the client
} catch (Exception e) {
System.err.println("[system] there was a problem while sending the message to the client");
e.printStackTrace(System.err);
continue;
}
continue;
}
try {
this.server.sendToAllClients(msg_send); // send message to all clients
} catch (Exception e) {
System.err.println("[system] there was a problem while sending the message to all clients");
e.printStackTrace(System.err);
continue;
}
}
}
}
and here is my cleint:
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
import javax.net.ssl.*;
import java.security.*;
public class ChatClient extends Thread {
private String userInfo = "";
private String passphrase = "pwd";
private int port = 1234;
public static void main(String[] args) throws Exception {
new ChatClient();
}
public ChatClient() throws Exception {
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
serverKeyStore.load(new FileInputStream("server.public"), "public".toCharArray());
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
Scanner s = new Scanner(System.in);
String username = s.nextLine();
clientKeyStore.load(new FileInputStream(username + ".private"), (username + passphrase).toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(serverKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(clientKeyStore, (username + passphrase).toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLContext.setDefault(sslContext);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory sf = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) sf.createSocket("localhost", port);
socket.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
socket.startHandshake();
DataInputStream in = null;
DataOutputStream out = null;
// connect to the chat server
try {
System.out.println("[system] connecting to chat server ...");
System.out.println("[system] you are signed in as: " + username);
in = new DataInputStream(socket.getInputStream()); // create input stream for listening for incoming messages
out = new DataOutputStream(socket.getOutputStream()); // create output stream for sending messages
this.sendMessage(username, out, "system");
System.out.println("[system] connected");
System.out.println("[system] to send a private message type \"/<NameOfUser>\" and then type the message");
ChatClientMessageReceiver message_receiver = new ChatClientMessageReceiver(in); // create a separate thread for listening to messages from the chat server
message_receiver.start(); // run the new thread
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
// read from STDIN and send messages to the chat server
BufferedReader std_in = new BufferedReader(new InputStreamReader(System.in));
String userInput;
while ((userInput = std_in.readLine()) != null) { // read a line from the console
this.sendMessage(userInput, out, userInfo); // send the message to the chat server
}
// cleanup
out.close();
in.close();
std_in.close();
socket.close();
}
private void sendMessage(String message, DataOutputStream out, String userInfo) {
message = "[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + userInfo + " : " + message;
try {
out.writeUTF(message); // send the message to the chat server
out.flush(); // ensure the message has been sent
} catch (IOException e) {
System.err.println("[system] could not send message");
e.printStackTrace(System.err);
}
}
}
// wait for messages from the chat server and print the out
class ChatClientMessageReceiver extends Thread {
private DataInputStream in;
public ChatClientMessageReceiver(DataInputStream in) {
this.in = in;
}
public void run() {
try {
String message;
while ((message = this.in.readUTF()) != null) { // read new message
System.out.println(message); // print the message to the console
}
} catch (Exception e) {
System.err.println("[system] could not read message");
e.printStackTrace(System.err);
}
}
}
the whole thing is supposed to be a "chat" that uses SSL to encrypt messages and should get the username from the certificate...so I have everything figured out except the "getting the usename out of the certificate's 'Common name' field"
Help, I'm losing my mind over this! :'(
ss.setNeedClientAuth(false);
The problem is here. You never asked for the client certificate, so it never got sent. Change this to true.
Am trying to establish an SSL Connection between a client and a server. But anytime time i try to connect from my client, i get a javax.net.ssl.SSLHandshakeException: no cipher suites in common no cipher suites in common error on my server. I have generated a keystore with signed certificates and i am referencing the keystore on both my client and server. I have gotten fed up after numerous research on this issue and related post on this site hasn't been helpful.
Here is my Server code
public class ServerApplicationSSL {
public static void main(String[] args) {
boolean debug = true;
System.out.println("Waiting For Connection");
int intSSLport = 4444;
{
Security.addProvider(new Provider());
//Security.addProvider(new BouncyCastleProvider());
//System.setProperty("javax.net.ssl.keyStore","C:\\SSLCERT\\NEWAEDCKSSKYE");
//System.setProperty("javax.net.ssl.keyStorePassword", "skyebank");
}
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\\NEWAEDCKSSKYE"), "skyebank".toCharArray());
file.write("Incoming Connection\r\n");
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keystore, "skyebank".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), trustManagers, null);
SSLServerSocketFactory sslServerSocketfactory = (SSLServerSocketFactory) context.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketfactory.createServerSocket(intSSLport);
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
SSLServerSocket server_socket = (SSLServerSocket) sslServerSocket;
server_socket.setNeedClientAuth(true);
sslSocket.startHandshake();
System.out.println("Connection Accepted");
file.write("Connection Accepted\r\n");
while (true) {
PrintWriter out = new PrintWriter(sslSocket.getOutputStream(), true);
//BufferedReader in = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
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");
System.out.println(exp.getStackTrace() + "\r\n");
file.write(exp.getMessage() + "\r\n");
file.flush();
file.close();
} catch (Exception eee) {
//message = eee.getMessage();
}
}
}
}
Here is my clients code
public String MakeSSlCall(String meternum) {
String message = "";
FileWriter file = null;
try {
file = new FileWriter("C:\\SSLCERT\\ClientJavalog.txt");
} catch (Exception ee) {
message = ee.getMessage();
}
try {
file.write("KeyStore Generated\r\n");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("C:\\SSLCERT\\NEWAEDCKSSKYE"), "skyebank".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");
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keystore, "skyebank".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(keystore);
file.write("KeyStore Stored\r\n");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager[] trustManagers = tmf.getTrustManagers();
KeyManager[] AllKeysMan = kmf.getKeyManagers();
file.write("Key Manager Length is " + AllKeysMan.length + "\r\n");
for (int i = 0; i < AllKeysMan.length; i++) {
file.write("Key Manager At This Point is " + AllKeysMan[i] + "\r\n");
}
context.init(kmf.getKeyManagers(), trustManagers, null);
SSLSocketFactory f = context.getSocketFactory();
file.write("About to Connect to Ontech\r\n");
SSLSocket c = (SSLSocket) f.createSocket("192.168.1.16", 4444);
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");
file.flush();
file.close();
} catch (Exception eee) {
message = eee.getMessage();
}
return "Connection Failed";
}
}
}
can someone please tell me what am doing wrong?
You will have to use SSLContext for this purpose. Check out the sample code which I implemented in one of my applications below. Client context means you become the client and call some back end. Server context means you accept the client requests.
public class SSLUtil {
private static String KEY_STORE_TYPE = "JKS";
private static String TRUST_STORE_TYPE = "JKS";
private static String KEY_MANAGER_TYPE = "SunX509";
private static String TRUST_MANAGER_TYPE = "SunX509";
private static String PROTOCOL = "TLS";
private static SSLContext serverSSLCtx = null;
private static SSLContext clientSSLCtx = null;
public static SSLContext createServerSSLContext(final String keyStoreLocation,
final String keyStorePwd)
throws KeyStoreException,
NoSuchAlgorithmException,
CertificateException,
FileNotFoundException,
IOException,
UnrecoverableKeyException,
KeyManagementException {
if (serverSSLCtx == null) {
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
keyStore.load(new FileInputStream(keyStoreLocation), keyStorePwd.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KEY_MANAGER_TYPE);
keyManagerFactory.init(keyStore, keyStorePwd.toCharArray());
serverSSLCtx = SSLContext.getInstance(PROTOCOL);
serverSSLCtx.init(keyManagerFactory.getKeyManagers(), null, null);
}
return serverSSLCtx;
}
public static SSLContext createClientSSLContext(final String trustStoreLocation,
final String trustStorePwd)
throws KeyStoreException,
NoSuchAlgorithmException,
CertificateException,
FileNotFoundException,
IOException,
KeyManagementException {
if (clientSSLCtx == null) {
KeyStore trustStore = KeyStore.getInstance(TRUST_STORE_TYPE);
trustStore.load(new FileInputStream(trustStoreLocation), trustStorePwd.toCharArray());
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TRUST_MANAGER_TYPE);
trustManagerFactory.init(trustStore);
clientSSLCtx = SSLContext.getInstance(PROTOCOL);
clientSSLCtx.init(null, trustManagerFactory.getTrustManagers(), null);
}
return clientSSLCtx;
}
}
Finally make sure you import the trusted server certificate to the client key store. Literally server and client should have different key stores. The key store used in the client side is referred to as client trust store since we are trusting the server certificate here. This article may help.
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);
}
}
}