How to authenticate SSL from java? - java

I need to call soap web services from java so i'm using ".p12" file for authentication. I'm using the same file in soap ui there it is working fine but in java it is giving SSL error.. how to link p12 file for authentication using ssl from java..
public static void setUp() {
System.setProperty("javax.net.ssl.keyStore", "ex.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
}
private static void initSSLFactories() {
final String KEYSTOREPATH = "ex.p12";
final char[] KEYSTOREPASS = "ff".toCharArray();
final char[] KEYPASS = "ff".toCharArray();
//ssl config
try (InputStream storeStream = FirstTest.class.getResourceAsStream(KEYSTOREPATH)) {
setSSLFactories(storeStream, "PKCS12", KEYSTOREPASS, KEYPASS);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void setSSLFactories(InputStream keyStream, String keystoreType, char[] keyStorePassword, char[] keyPassword) throws Exception
{
KeyStore keyStore = KeyStore.getInstance(keystoreType);
keyStore.load(keyStream, keyStorePassword);
KeyManagerFactory keyFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, keyPassword);
KeyManager[] keyManagers = keyFactory.getKeyManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, null, null);
SSLContext.setDefault(sslContext);
}

You can create a client something like this:
public Client getClient() {
SslConfigurator sslConfig = SslConfigurator
.newInstance()
.trustStoreFile(TRUST_STORE_FILE_PATH) //The key-store file where the certificate is saved.
.trustStorePassword(TRUST_STORE_PASSWORD_PATH);//password of the key-store file.
SSLContext sslContext = sslConfig.createSSLContext();
Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();
return client;
}

Related

Mqtt client ssl example in java

I am tired to connect facebook MQTT server ( edge-mqtt.facebook.com:443 ) with ssl , I'm using Eclipse Paho for MQTT connection .
private final String DEFAULT_HOST = "edge-mqtt.facebook.com";
private final int DEFAULT_PORT = 443;
public void connect(String protogle) throws Exception {
this.broker = protogle + "://"+ DEFAULT_HOST + ":" + DEFAULT_PORT;
this.mqttClient = new MqttClient(broker,getMqttClientId() ,new MemoryPersistence() );
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setKeepAliveInterval( MQTT_KEEPALIVE);
connOpts.setUserName( getMqttUsername() );
connOpts.setPassword( getMqttPassword().toCharArray() );
connOpts.setMqttVersion( 3 );
//connOpts.setSocketFactory(getSocketFactory (caCrtFile,crtFile,keyFile,password) );
Logger.w("Connecting to broker: "+broker);
Logger.w("isConnected:"+mqttClient.isConnected());
try {
IMqttToken cn = mqttClient.connectWithResult(connOpts);
Logger.w("connected");
}catch (MqttException me){
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
return;
}
this.mqttClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable me) {
Logger.w("Connection lost");
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
}
#Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
Logger.w("message Arrived");
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
Logger.w("deliverd--------");
try {
MqttDeliveryToken token = (MqttDeliveryToken) iMqttDeliveryToken;
String h = token.getMessage().toString();
Logger.w("deliverd message :"+h);
} catch (MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
} catch (Exception e) {
e.printStackTrace();
}
}
});
public SSLSocketFactory getSocketFactory (final String caCrtFile, final String crtFile, final String keyFile,
final String password) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
X509Certificate caCert = (X509Certificate)reader.readObject();
reader.close();
// load client certificate
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
X509Certificate cert = (X509Certificate)reader.readObject();
reader.close();
// load client private key
reader = new PEMReader(
new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
new PasswordFinder() {
#Override
public char[] getPassword() {
return password.toCharArray();
}
}
);
KeyPair key = (KeyPair)reader.readObject();
reader.close();
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate us
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("certificate", cert);
ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
}
I'm searching for how to create caCrtFile , crtFile and keyFile and got many answers . i confused and now i don't know which answer is true . for example i got this answer . but i can't implement that and all times i got SSL error . any one can give me example to creating these files for edge-mqtt.facebook.com:443 ?
You do only need a crtFile and keyFile if you are trying to do SSL mutual authentication. If this is the case then Facebook would issue you with the required files.
The caCrtFile is a certificate chain to verify the certificate supplied by the Facebook broker when you connect to it. The certificate for edge-mqtt.facebook.com issued by DigiCert Inc so the required CA cert should already be included in the Java Runtime.
All this means you should be able to use the default SSLSocketFactory witoout having to add your own truststore or keystore.
EDIT:
So delete all of the getSocketFactory() method and replace it with SSLContext.getDefault().getSocketFactory();

Using .cer certificate to make an HTTPS request

I've already saw this question: Need to do a GET&POST HTTPS Request using a .cer certificate
Mine is quite different:
It is possible to make an HTTPS request using Java (vanilla, or using any library), trusting a server certificate and providing a client certificate, without using a keystore but using plain certificates?
I have both certs in X.509 format, and I don't want to have every certificate in a keystore.
This is a rough example. Represents the X509KeyManager decorator.
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(null, null);
X509KeyManager manager = (X509KeyManager) kmf.getKeyManagers()[0];
KeyManager km = new X509KeyManager() {
#Override
public String[] getClientAliases(String s, Principal[] principals) {
return manager.getServerAliases(s, principals);
}
#Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
return manager.chooseClientAlias(strings, principals, socket);
}
#Override
public String[] getServerAliases(String s, Principal[] principals) {
return manager.getServerAliases(s, principals);
}
#Override
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
return manager.chooseServerAlias(s, principals, socket);
}
#Override
public X509Certificate[] getCertificateChain(String s) {
// You can use `s` to select the appropriate file
try {
File file = new File("path to certificate");
try(InputStream is = new FileInputStream(file)) {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
return new X509Certificate[] {
(X509Certificate) factory.generateCertificate(is)
};
}
}
catch (CertificateException| IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public PrivateKey getPrivateKey(String s) {
// You can use `s` to select the appropriate file
// load and private key from selected certificate
// this use for certificate authorisation
try {
File file = new File("private key file");
byte buffer[] = Files.readAllBytes(file.toPath());
KeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(keySpec);
}
catch (NoSuchAlgorithmException | IOException | InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
};
TrustManager tm = new X509TrustManager() {
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
try {
File file = new File("path to certificate");
try(InputStream is = new FileInputStream(file)) {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
return new X509Certificate[] {
(X509Certificate) factory.generateCertificate(is)
};
}
}
catch (CertificateException| IOException e) {
e.printStackTrace();
}
return null;
}
};
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore)null); //use java system trust certificates
TrustManager managers[] = new TrustManager[tmf.getTrustManagers().length + 1];
System.arraycopy(tmf.getTrustManagers(), 0, managers, 0, tmf.getTrustManagers().length);
managers[managers.length - 1] = tm;
SSLContext context = SSLContext.getInstance("TLS");
context.init(new KeyManager[]{ km }, managers, new SecureRandom());
URL url = new URL("https://............/");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(connection.getSSLSocketFactory());
connection.connect();
If you really don't want to create a new keystore file, then can use KeyStore API to create in memory and load certificate directly.
InputStream is = new FileInputStream("somecert.cer");
// You could get a resource as a stream instead.
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate)cf.generateCertificate(is);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null); // You don't need the KeyStore instance to come from a file.
ks.setCertificateEntry("caCert", caCert);
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
Alternatively, if you want to avoid modifying your default cacerts file, then you'll need to implement your own TrustManager. However a TrustManager needs a keystore to load, so you can either create a new keystore file importing just your certificate.
keytool -import -alias ca -file somecert.cer -keystore truststore.jks -storepass changeit
And use something like following snippet to load the keystore file.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Using null here initialises the TMF with the default trust store.
tmf.init((KeyStore) null);
// Get hold of the default trust manager
X509TrustManager defaultTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTm = (X509TrustManager) tm;
break;
}
}
FileInputStream myKeys = new FileInputStream("truststore.jks");
// Do the same with your trust store this time
// Adapt how you load the keystore to your needs
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "password".toCharArray());
myKeys.close();
tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(myTrustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

Java HTTPS Server "Unsupported Protocol Error" in Chrome

I'm making a custom HTTP/1.1 server implementation in Java. It's working fine in HTTP mode, but I also want to support HTTPS. I haven't generated a certificate for the server yet, but it should at least be trying to connect. I set the protocol and cipher suite to the same settings as google.com (TLS 1.2, ECDHE_RSA, AES_128_GCM), so I know Chrome supports them.
But when I try to connect to https://localhost in Chrome, it gives ERR_SSL_VERSION_OR_CIPHER_MISMATCH (localhost uses an unsupported protocol) error. On the Java side, I get "no cipher suites in common" error.
Java Code:
public class Server {
private final String dir;
private final ServerSocket server;
private final SSLServerSocket sslServer;
public static String jarDir() {
String uri = ClassLoader.getSystemClassLoader().getResource(".").getPath();
try { return new File(URLDecoder.decode(uri,"UTF-8")).getPath()+File.separator; }
catch (Exception e) { return null; }
}
private static SSLContext createSSLContext(String cert, char[] pass) throws Exception {
/*//Load KeyStore in JKS format:
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream(cert), pass);
//Create key manager:
KeyManagerFactory kmFactory = KeyManagerFactory.getInstance("SunX509");
kmFactory.init(keyStore, pass); KeyManager[] km = kmFactory.getKeyManagers();
//Create trust manager:
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("SunX509");
tmFactory.init(keyStore); TrustManager[] tm = tmFactory.getTrustManagers();
//Create SSLContext with protocol:
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(km, tm, null); return ctx;*/
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(null, null, null); return ctx;
}
Server(String localPath, int port) throws Exception {
this(localPath, port, 0);
}
//Server is being initialized with:
//new Server("root", 80, 443);
Server(String localPath, int port, int httpsPort) throws Exception {
dir = localPath; File fdir = new File(jarDir(), dir);
if(!fdir.isDirectory()) throw new Exception("No such directory '"+fdir.getAbsolutePath()+"'!");
//Init Server:
server = new ServerSocket(port);
if(httpsPort > 0) {
SSLContext ctx = createSSLContext("cert.jks", "pass".toCharArray());
sslServer = (SSLServerSocket)ctx.getServerSocketFactory().createServerSocket(httpsPort);
//TLS_DH_anon_WITH_AES_128_GCM_SHA256
sslServer.setEnabledCipherSuites(new String[]{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"});
sslServer.setEnabledProtocols(new String[]{"TLSv1.2"});
//Also does not work, same error:
//sslServer.setEnabledCipherSuites(sslServer.getSupportedCipherSuites());
//sslServer.setEnabledProtocols(sslServer.getSupportedProtocols());
} else sslServer = null;
/*new Thread(() -> { while(true) try {
new HTTPSocket(server.accept(), this);
} catch(Exception e) { Main.err("HTTP Server Error",e); }}).start();*/
if(httpsPort > 0) new Thread(() -> { while(true) try {
new HTTPSocket(sslServer.accept(), this);
} catch(Exception e) { Main.err("HTTPS Server Error",e); }}).start();
}
/* ... Other Stuff ... */
}
EDIT: I generated a certificate using keytool -genkey -keyalg RSA -alias selfsigned -keystore cert.jks -storepass password -validity 360 -keysize 2048, but now Java throws Keystore was tampered with, or password was incorrect error.
Like I said in the comments, using "password" in keyStore.load solved the issue.
private static SSLContext createSSLContext(String cert, char[] pass) throws Exception {
//Load KeyStore in JKS format:
KeyStore keyStore = KeyStore.getInstance("jks");
keyStore.load(new FileInputStream(cert), "password".toCharArray());
//Create key manager:
KeyManagerFactory kmFactory = KeyManagerFactory.getInstance("SunX509");
kmFactory.init(keyStore, pass); KeyManager[] km = kmFactory.getKeyManagers();
//Create trust manager:
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("SunX509");
tmFactory.init(keyStore); TrustManager[] tm = tmFactory.getTrustManagers();
//Create SSLContext with protocol:
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(km, tm, null); return ctx;
}

Android M - SSLHandshakeException in SSLSocket connection

I have a fairly simple client(Android)/server app to which I am trying to add SSL. Its working fine up to Android 4.4.4 but failing with SSLHandshakeException on Android M ( haven't tested on Lollipop), the server is telling me there are no cipher suites in common.
Here's the basic code (full source available here)..
Server.java
public class Server {
public static final int PORT = 4646;
TrustManagerFactory tmf;
KeyManagerFactory kmf;
KeyStore publicKeyStore;
KeyStore privateKeyStore;
SSLServerSocket serverSocket;
public static void main(String args[]) {
Server server = new Server();
server.init();
}
private void init() {
InputStream privateKeyStoreIns;
InputStream publicKeyStoreIns;
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
privateKeyStoreIns = Server.class.getResourceAsStream("/server.private");
publicKeyStoreIns = Server.class.getResourceAsStream("/client.public");
Security.addProvider(new BouncyCastleProvider());
try {
privateKeyStore = setupKeystore(privateKeyStoreIns, "private");
publicKeyStore = setupKeystore(publicKeyStoreIns, "public");
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(publicKeyStore);
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(privateKeyStore, "private".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(),
tmf.getTrustManagers(),
secureRandom);
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
serverSocket = (SSLServerSocket) sf.createServerSocket( PORT );
serverSocket.setNeedClientAuth(true);
Socket socket = serverSocket.accept();
ObjectInputStream objInputStream = new ObjectInputStream(socket.getInputStream());
while (objInputStream.readObject() != null) {
// do nothing
}
objInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private KeyStore setupKeystore(InputStream keyStoreInputStream, String passphrase)
throws GeneralSecurityException, IOException {
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreInputStream, passphrase.toCharArray());
return keyStore;
}
}
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getName();
public static final int PORT = 4646;
public static final String HOST = "192.168.1.12"; //Change to IP address of server
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect();
}
private void connect() {
new SocketConnector(this).execute();
}
static class SocketConnector extends AsyncTask<Void, Void, String> {
Activity activity;
TrustManagerFactory tmf;
KeyManagerFactory kmf;
KeyStore publicKeyStore;
KeyStore privateKeyStore;
SSLSocket socket;
public SocketConnector(Activity activity) {
this.activity = activity;
}
#Override
protected String doInBackground(Void... params) {
InputStream privateKeyStoreIns;
InputStream publicKeyStoreIns;
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
privateKeyStoreIns = activity.getResources().openRawResource(R.raw.client_private);
publicKeyStoreIns = activity.getResources().openRawResource(R.raw.server_public);
try {
privateKeyStore = setupKeystore(privateKeyStoreIns, "private");
publicKeyStore = setupKeystore(publicKeyStoreIns, "public");
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(publicKeyStore);
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(privateKeyStore, "private".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(),
tmf.getTrustManagers(),
secureRandom);
SSLSocketFactory sf = sslContext.getSocketFactory();
socket = (SSLSocket) sf.createSocket(HOST, PORT);
socket.startHandshake();
} catch (Exception e) {
e.printStackTrace();
return "Connection failure: " + e.getMessage();
}
return "Connection established!";
}
#Override
protected void onPostExecute(String s) {
TextView textView = (TextView) activity.findViewById(R.id.text_view);
textView.setText(s);
}
private KeyStore setupKeystore(InputStream keyStoreInputStream, String passphrase)
throws GeneralSecurityException, IOException {
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreInputStream, passphrase.toCharArray());
return keyStore;
}
}
}
Exception stacktrace on Android
javax.net.ssl.SSLHandshakeException: Handshake failed
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:396)
at com.sslsocketpoc.app.MainActivity$SocketConnector.doInBackground(MainActivity.java:71)
at com.sslsocketpoc.app.MainActivity$SocketConnector.doInBackground(MainActivity.java:31)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x9e7a3140: Failure in SSL library, usually a protocol error
error:100c5410:SSL routines:ssl3_read_bytes:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:972 0xb4071d20:0x00000001)
error:100c009f:SSL routines:ssl3_get_server_hello:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:750 0xab25d50f:0x0000
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
Server side exception
javax.net.ssl.SSLHandshakeException: no cipher suites in common
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1035)
Google has forked OpenSSL in API 23 (6.x) and now uses BoringSSL with no DSA support (but ECDSA), your public client key is a DSA 1024 KEY so you need check (and change) your keys to any supported algorithm.

Setting the certificate used by a Java SSL ServerSocket

I want to open a secure listening socket in a Java server application. I know that the recommended way to do that is to just do this:
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = ssf.createServerSocket(443);
But this requires to pass the certificate of the server to the JVM when launching java. Because this would make some things in deployment more complicated for me, I would prefer to load the certificate at runtime.
So I have a key file and a password and I want a server socket. How do I get there? Well, I read the documentation and the only way I could find is this:
// these are my parameters for SSL encryption
char[] keyPassword = "P#ssw0rd!".toCharArray();
FileInputStream keyFile = new FileInputStream("ssl.key");
// init keystore
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyFile, keyPassword);
// init KeyManagerFactory
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyPassword);
// init KeyManager
KeyManager keyManagers[] = keyManagerFactory.getKeyManagers();
// init the SSL context
SSLContext sslContext = SSLContext.getDefault();
sslContext.init(keyManagers, null, new SecureRandom());
// get the socket factory
SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
// and finally, get the socket
ServerSocket serverSocket = socketFactory.createServerSocket(443);
And that doesn't even have any error handling. Is it really that complicated? Isn't there an easier way to do it?
But this requires to pass the certificate of the server to the JVM when launching java.
No it doesn't. Just set these system properties before you create the SSLServerSocket:
javax.net.ssl.keyStore ssl.key
javax.net.ssl.keyStorePassword P#ssw0rd!
You can do that with System.setProperties() or on the command line.
If you look at the code, you can see why it's necessarily complicated. This code decouples the implementation of the SSL protocol from:
the source of your key material (KeyStore)
certificate algorithm choice and key management (KeyManager)
management of peer trust rules (TrustManager) - not used here
secure random algorithm (SecureRandom)
NIO or socket implementation (SSLServerSocketFactory) - could use SSLEngine for NIO
Consider what your own implementation would look like if you were trying to reach the same goals!
Use this.
public class KeyMaster
{
public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String sslAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(sslAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
catch(Exception e)
{
Assistance.log("Err: getSSLSocketFactory(), ");
}
return null;
}
public static SSLServerSocketFactory getSSLServerSocketFactory(KeyStore trustKey, String sslAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(sslAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getServerSocketFactory();
}
catch(Exception e)
{
Assistance.log("Err: getSSLSocketFactory(), ");
}
return null;
}
public static SSLServerSocket getSSLServerSocket(SSLServerSocketFactory socketFactory, int port)
{
try
{
return (SSLServerSocket) socketFactory.createServerSocket(port);
}
catch(Exception e)
{Assistance.log("Err: getSSLSocket(), ");}
return null;
}
public static KeyStore getFromPath(String path, String algorithm, String filePassword)//PKSC12
{
try
{
File f = new File(path);
if(!f.exists())
throw new RuntimeException("Err: File not found.");
FileInputStream keyFile = new FileInputStream(f);
KeyStore keystore = KeyStore.getInstance(algorithm);
keystore.load(keyFile, filePassword.toCharArray());
keyFile.close();
return keystore;
}
catch(Exception e)
{
Assistance.log("Err: getFromPath(), " + e.toString());
}
return null;
}
and in main.
KeyStore key = KeyMaster.getFromPath(".\\cssl.pfx", "PKCS12", "123");
SSLServerSocketFactory fac = KeyMaster.getSSLServerSocketFactory(key, "TLS");
listener = KeyMaster.getSSLServerSocket(fac, 49015);

Categories