JavaFX WebView and Client Certificate - ssl

I am trying to port a .net application to JavaFx that has an integrated web browser that opens a website that requires a certificate. In windows the certificate was installed from a provided .pfx file and a pass phrase.
When the browser calls the website, a pop up shows the installed certificates, user chose the right one if there is more than one and website opens.
With the following code, I get the website to open connect using my certificate.
private void Connect() throws NoSuchAlgorithmException, FileNotFoundException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
SSLContext ctx = SSLContext.getInstance("TLS");
KeyManager[] keyManagers;
KeyStore keyStore = KeyStore.getInstance("pkcs12");
FileInputStream keyStoreFile = new FileInputStream(new File("Certificate.pfx"));
String keyStorePassword = "password";
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
keyManagers = kmf.getKeyManagers();
ctx.init(keyManagers, null, new SecureRandom());
SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();
URL url = new URL("https://example.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslSocketFactory);
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
}
How can I get this working in WebView control?
Thanks

I solved the issue after spending days researching.
Adding this lines of code before opening the website will make it work.
System.setProperty("javax.net.ssl.keyStore", "/path/to/certificate.pfx");
System.setProperty("javax.net.ssl.keyStorePassword","password");
Hope this help!

Related

Apache camel - MQTT with SSL

Where can I find the exact configuration setup for MQTT with SSL. The official docs just have it one line as " SSL is supported " but I could not find anything on how to configure it.
I have read a few forums, but I could not make out anything from it.
Some help on this.
P.S : Before you ask me what have I tried. I just made a route with mqtt as component in camel. I have a couple of certificates which I dont how to use it here.
To everyone who is looking for the instructions in the which does not even exists. Here is our you configure the MQTT component with SSL.
MQTT + SSL with Client , CA Certificate and a Key
Route
MQTTEndpoint mqttEndpoint = null;
MQTTComponent mqttComponent = new MQTTComponent();
mqttComponent.setCamelContext( this.getContext()); //Set camel context
mqttEndpoint = (MQTTEndpoint) mqttComponent.createEndpoint("mqtt://mqtt-queue"); //mqtt://<any-name>
mqttEndpoint.getConfiguration().setHost( "ssl://<your-ssl-broker>" );
SSLContext sc = SSLManager
.getSocketFactory("<ca-certificate>.crt", "<trust-certificate>.crt", "<key>.key", <password>);
mqttEndpoint.getConfiguration().setSubscribeTopicNames("<topic>");
mqttEndpoint.getConfiguration().setSslContext( sc );
SSLContext
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import java.io.*;
import java.nio.file.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
public class SSLManager
{
public static SSLContext 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());
// create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
//Create socket factory if required
//context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
//return context.getSocketFactory();
return context;
}
}
Maven Dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.40</version>
</dependency>

Making HTTPS Request and opening SSL socket in JAVA

I am trying to build a login page. For that, I want to open a SSL socket and make a HTTPS request,but I'm getting Unknown Host Exception in the line
SSLSocket skt = (SSLSocket)sslsf.createSocket("https://31.21.18.222/room_info/x.txt" , 443);
Could someone please tell me what I'm doing wrong? Also, I've turned off host verification because it wont be needed in my program.
`public void clickLogin() throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
URL url = new URL ("https://31.21.18.222/room_info/x.txt");
HttpsURLConnection connection = null;
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null); //Make an empty store
InputStream fis = new FileInputStream("C:/Documents and Settings/user/Desktop/PK/localhost.crt");
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
java.security.cert.Certificate cert = cf.generateCertificate(bis);
keyStore.setCertificateEntry("localhost", cert);
}
// write code for turning off client verification
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, tmf.getTrustManagers() , null);
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
SSLSocketFactory sslsf = context.getSocketFactory();
SSLSocket skt = (SSLSocket)sslsf.createSocket("https://31.21.18.222/room_info/x.txt" , 443);
skt.setUseClientMode(true);
SSLSession s = skt.getSession(); // handshake implicitly done
skt.setKeepAlive(true);
connection = (HttpsURLConnection) url.openConnection();
// Host name verification off
connection.setHostnameVerifier(new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session)
{
return true;
}
}); `
If you want to open a socket with createSocket, you need to use the host name (or IP address), not the full URL:
example : sslsf.createSocket("31.21.18.222" , 443);
In addition:
Don't use Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()) (it's there by default).
It's probably better to use TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) instead of X.509, especially because the default algorithm for the TMF is PKIX, not X.509.
createSocket will verify the certificate against the trust anchors, but won't check the host name (which is also required to prevent MITM attacks). For this, it's also generally better to use a host name instead of an IP address.

How can I configure Simple Framework to require SSL client authentication?

I am writing an HTTP server using the Simple Framework and would like to require clients to present a valid certificate signed by my certificate authority in order to establish a connection.
I have the following bare-bones server written. How can I modify this code to require client certificate authentication for all SSL connections?
public static void main(String[] args) throws Exception {
Container container = createContainer();
Server server = new ContainerServer(container);
Connection connection = new SocketConnection(server);
SocketAddress address = new InetSocketAddress(8443);
KeyManagerFactory km = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
try(InputStream keystoreFile = new FileInputStream(SERVER_KEYSTORE_PATH)) {
serverKeystore.load(keystoreFile, "asdfgh".toCharArray());
}
km.init(serverKeystore, SERVER_KS_PASSWORD.toCharArray());
TrustManagerFactory tm = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore caKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
try(InputStream caCertFile = new FileInputStream(CA_CERT_PATH)) {
caKeystore.load(caCertFile, CA_KS_PASSWORD.toCharArray());
}
tm.init(caKeystore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(km.getKeyManagers(), tm.getTrustManagers(), null);
connection.connect(address, sslContext);
}
Try this
public class MyServer implements org.simpleframework.transport.Server {
private Server delegateServer;
public MyServer(Server delegateServer){
this.delegateServer = delegateServer;
}
public void process(Socket socket){
socket.getEngine().setNeedClientAuth(true);
delegateServer.process(socket);
}
}

Difference between KeyStore and KeyManager/TrustManager

What is the difference between using a KeyStore Object for the keystore and truststore; as opposed to using the KeyManager and TrustManager?
Let me explain why I am asking. I am working with RESTEasy and needed to make a REST call over HTTPS with SSL certificates. I needed to augment how RESTEasy created the ClientRequest. Here is what I figured out initially:
public void afterPropertiesSet() throws Exception {
Assert.isTrue(StringUtils.isNotBlank(getKeystoreName()), "Key Store Name is Blank");
Assert.isTrue(StringUtils.isNotBlank(getKeystorePassword()), "Key Store Password is Blank.");
Assert.isTrue(StringUtils.isNotBlank(getKeystorePath()), "Key Store Path is Blank");
Assert.isTrue(StringUtils.isNotBlank(getTruststoreName()), "Trust Store Name is Blank");
Assert.isTrue(StringUtils.isNotBlank(getTruststorePassword()), "Trust Store Password is Blank.");
Assert.isTrue(StringUtils.isNotBlank(getTruststorePath()), "Trust Store Path is Blank");
// Set the keystore and truststore for mutual authentication
createKeystore();
createTruststore();
if (getHttpClient() == null) {
// Initialize HTTP Client
initializeHttpClient();
}
Assert.notNull(getHttpClient(), "HTTP Client is NULL after initialization");
}
public ClientRequest createClientRequest(String uri) throws URISyntaxException {
ClientExecutor clientExecutor = new ApacheHttpClient4Executor(getHttpClient());
ClientRequestFactory fac = new ClientRequestFactory(clientExecutor, new URI(uri));
return fac.createRequest(uri);
}
private void createTruststore() throws KeyStoreException, FileNotFoundException, IOException,
NoSuchAlgorithmException, CertificateException {
String truststoreFilePath = getTruststorePath() + getTruststoreName();
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream truststoreInput = getClass().getClassLoader().getResourceAsStream(truststoreFilePath);
truststore.load(truststoreInput, getTruststorePassword().toCharArray());
}
private void createKeystore() throws KeyStoreException, FileNotFoundException, IOException,
NoSuchAlgorithmException, CertificateException {
String keystoreFilePath = getKeystorePath() + getKeystoreName();
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keystoreInput = getClass().getClassLoader().getResourceAsStream(keystoreFilePath);
keystore.load(keystoreInput, getKeystorePassword().toCharArray());
}
/**
* Initializes the HTTP Client
*
* #throws KeyStoreException
* #throws NoSuchAlgorithmException
* #throws UnrecoverableKeyException
* #throws KeyManagementException
*/
private void initializeHttpClient() throws KeyManagementException, UnrecoverableKeyException,
NoSuchAlgorithmException, KeyStoreException {
// Register https and http with scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(getKeystore(), getKeystorePassword(), getTrustStore());
schemeRegistry.register(new Scheme(HTTP, 80, PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme(HTTPS, 443, sslSocketFactory));
// Set connection params
HttpConnectionParams.setConnectionTimeout(httpParameters, serviceConnectionTimeout);
HttpConnectionParams.setSoTimeout(httpParameters, readTimeout);
HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);
// Create Connection Manager
PoolingClientConnectionManager clientManager = new PoolingClientConnectionManager(schemeRegistry);
clientManager.setMaxTotal(maxTotalConnections);
clientManager.setDefaultMaxPerRoute(defaultMaxConnectionsPerHost);
httpClient = new DefaultHttpClient(clientManager, httpParameters);
}
I ran into a problem with the Peer Certificates and kept getting an exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
I then searched around and found articles/blogs about setting up the HttpClient but using TrustManager and KeyManager. I refactored the code to do the following:
public void afterPropertiesSet() throws Exception {
Assert.isTrue(StringUtils.isNotBlank(getKeystoreName()), "Key Store Name is Blank");
Assert.isTrue(StringUtils.isNotBlank(getKeystorePassword()), "Key Store Password is Blank.");
Assert.isTrue(StringUtils.isNotBlank(getKeystorePath()), "Key Store Path is Blank");
Assert.isTrue(StringUtils.isNotBlank(getTruststoreName()), "Trust Store Name is Blank");
Assert.isTrue(StringUtils.isNotBlank(getTruststorePassword()), "Trust Store Password is Blank.");
Assert.isTrue(StringUtils.isNotBlank(getTruststorePath()), "Trust Store Path is Blank");
if (getHttpClient() == null) {
// Initialize HTTP Client
initializeHttpClient();
}
Assert.notNull(getHttpClient(), "HTTP Client is NULL after initialization");
}
public ClientRequest createClientRequest(String uri) throws URISyntaxException {
ClientExecutor clientExecutor = new ApacheHttpClient4Executor(getHttpClient());
ClientRequestFactory fac = new ClientRequestFactory(clientExecutor, new URI(uri));
return fac.createRequest(uri);
}
/**
* Initializes the HTTP Client
*
* #throws KeyStoreException
* #throws NoSuchAlgorithmException
* #throws UnrecoverableKeyException
* #throws KeyManagementException
*/
private void initializeHttpClient() throws Exception {
if (isCheckPeerCertificates()) {
checkPeerCerts();
}
// Create Trust and Key Managers
// Use TrustManager and KeyManager instead of KeyStore
TrustManager[] trustManagers = getTrustManagers(getTruststorePassword());
KeyManager[] keyManagers = getKeyManagers(getKeystorePassword());
// Create SSL Context
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(keyManagers, trustManagers, new SecureRandom());
// Create SSL Factory
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// Register https and http with scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme(HTTP, 80, PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme(HTTPS, 443, sslSocketFactory));
// Set connection params
HttpConnectionParams.setConnectionTimeout(httpParameters, serviceConnectionTimeout);
HttpConnectionParams.setSoTimeout(httpParameters, readTimeout);
HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);
// Create Connection Manager
PoolingClientConnectionManager clientManager = new PoolingClientConnectionManager(schemeRegistry);
clientManager.setMaxTotal(maxTotalConnections);
clientManager.setDefaultMaxPerRoute(defaultMaxConnectionsPerHost);
httpClient = new DefaultHttpClient(clientManager, httpParameters);
}
private TrustManager[] getTrustManagers(String trustStorePassword) throws Exception {
String truststoreFilePath = getTruststorePath() + getTruststoreName();
InputStream trustStoreInput = getClass().getClassLoader().getResourceAsStream(truststoreFilePath);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(trustStoreInput, trustStorePassword.toCharArray());
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(trustStore);
return tmfactory.getTrustManagers();
}
private KeyManager[] getKeyManagers(String keyStorePassword) throws Exception {
String keystoreFilePath = getKeystorePath() + getKeystoreName();
InputStream keyStoreInput = getClass().getClassLoader().getResourceAsStream(keystoreFilePath);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyStoreInput, keyStorePassword.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keyStore, keyStorePassword.toCharArray());
return kmfactory.getKeyManagers();
}
The second code works just fine. So, what is the a difference between the 2 types of usages?
I think this can help you:
Difference between trustStore and keyStore in Java - SSL
First and major difference between trustStore and keyStore is that trustStore is used by TrustManager and keyStore is used by KeyManager class in Java. KeyManager and TrustManager performs different job in Java, TrustManager determines whether remote connection should be trusted or not i.e. whether remote party is who it claims to and KeyManager decides which authentication credentials should be sent to the remote host for authentication during SSL handshake. if you are an SSL Server you will use private key during key exchange algorithm and send certificates corresponding to your public keys to client, this certificate is acquired from keyStore. On SSL client side, if its written in Java, it will use certificates stored in trustStore to verify identity of Server.
Read more: JavaRevisited blog: http://javarevisited.blogspot.com/2012/09/difference-between-truststore-vs-keyStore-Java-SSL.html (Archived here.)

SSL connection to ldap using certitificates and custom ssl socket factory

This is my scenario , i want to connect to ldap usign jndi , i am using custom SSLSOcketfactory which reads the truststore and keystore . The context is created successful but when i try to authenticate using the same credentials it throws an error telling that the authentication method is not supported.
here is my code of the custom ssl socket -
try {
StringBuffer trustStore = new StringBuffer("c:/Temp/certs/TrustStore");
StringBuffer keyStore = new StringBuffer("c:/Temp/certs/keystore.arun");
StringBuffer keyStorePass = new StringBuffer("xxxxx");
StringBuffer keyAlias = new StringBuffer("user");
StringBuffer keyPass = new StringBuffer("XXXX");
TrustManagerFactory tmf =TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
FileInputStream fis = new FileInputStream(trustStore.toString());
KeyStore ks1 = KeyStore.getInstance("jks");
ks1.load(fis, trustStorePass.toString().toCharArray());
fis.close();
tmf.init(ks1);
TrustManager[] tms = tmf.getTrustManagers();
FileInputStream fin = new FileInputStream(keyStore.toString());
KeyStore ks2 = KeyStore.getInstance("jks");
ks2.load(fin, keyStorePass.toString().toCharArray());
fin.close();
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks2, keyStorePass.toString().toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
if (keyAlias != null && keyAlias.length() > 0) {
for (int i = 0; i < kms.length; i++) {
// We can only deal with instances of X509KeyManager
if (kms[i] instanceof X509KeyManager)
kms[i] = new CustomKeyManager(
(X509KeyManager) kms[i], keyAlias.toString());
}
}
SSLContext context = SSLContext.getInstance("TLS");
context.init(kms,tms, null);
ssf = context.getSocketFactory();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SocketFactory getDefault() {
return new CustomSSLSocketFactory();
}
And the jndi code which uses this CustomSSLSocketFactory is as follows
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://wx64ads01a.vapps.esca.com:636");
env.put(Context.REFERRAL, "follow");
env.put("java.naming.ldap.derefAliases", "always");
env.put("java.naming.ldap.factory.socket","com.eterra.security.authz.dao.CustomSSLSocketFactory" );
try {
ctx = new InitialLdapContext(env, null);
// start ssl session for server authentication
}catch(Exception e ){
System.out.println(e);
}
try{
ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION,
"EXTERNAL");
String path = "CN=domain,DC=casa,DC=com"
String inFilter = "(&(objectClass=*))";
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> results = null;
results = ctx.search(path, inFilter, sc);
}
My Context is created perfectly but when i try to authenticate and bind to the ldap , i get Invalid Authentication method . ANy help will be appreciated , Struggling with these error over a long time now . Thanks in advance .
Context.SECURITY_AUTHENTICATION, "EXTERNAL"
when i try to authenticate and bind to the ldap , i get Invalid Authentication method
So your LDAP server doesn't support EXTERNAL authentication.