HTTPS SSL Communitation - Yash-777/SteamingServlet GitHub Wiki
javax.net.ssl.SSLContext, <<KeyManager>>
, <<TrustManager>>
https://stackoverflow.com/questions/22250402/truststore-and-keystore-during-2-way-ssl-validation
A keystore contains keystore entries. A truststore contains public certificates.
The server’s public certificate, stored in the client’s key store, is authenticated against the private certificate stored in the server’s trust store. The client’s public certificate, stored in the server’s trust store, is authenticated against the private certificate stored in the client’s key store.
The trust store is typically one of the following files: \lib\security\jssecacerts \lib\security\cacerts The JSSE API recommends jssecacerts as the default trust store.
Enabling and Disabling SSL
- Generate the public and private keys for each Processing Server and Signaling Server. Repeat this for each server:
Generate the keys for the server:
keytool -genkeypair “distinguished_name" -alias server_keystore_entry -keypass key_password -keystore server_keystore -storepass server_keystore_password
Export the public key from the server keystore entry into a self-signed certificate:
keytool -exportcert -alias server_keystore_entry -keystore server_keystore -storepass server_keystore_password -rfc -file server_certificate.cer
- Generate the public and private keys for each administration client. Repeat this for each administration client:
keytool -genkeypair “distinguished_name" -alias client_keystore_entry -keypass key_password -keystore client_keystore -storepass client_keystore_password
Export the public key from the administration client keystore entry into a self-signed certificate:
keytool -exportcert -alias client_keystore_entry -keystore client_keystore -storepass client_keystore_password -rfc -file client_certificate.cer
Java TrustStore baeldung.com
A truststore is the opposite – while a keystore typically holds onto certificates that identify us, a truststore holds onto certificates that identify others. In Java, we use it to trust the third party we're about to communicate with.
C:\Yash>keytool -list -keystore %JAVA_HOME%/jre/lib/security/cacerts
Enter keystore password: <<changeit>>
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 111 entries
verisignclass2g2ca [jdk], 2018-06-13, trustedCertEntry,
Certificate fingerprint (SHA1): B3:EA:C4:47:76:C9:C8:1C:EA:F2:9D:95:B6:CC:A0:08:1B:67:EC:9D
<ssl certificateName="server_certificate.cer" alias="server_keystore_entry"/>
<ssltrust certificateName="client_certificate.pfx" password="client_keystore_password"/>
SSLSocketFactory sslSocketFactory = getCertificateFactoryBasedSSLContext(sslCertificateStream, certSSLAlias).getSocketFactory();
if (sslSocketFactory != null) {
connectionHttps.setSSLSocketFactory(sslSocketFactory);
}
public static SSLContext getCertificateFactoryBasedSSLContext(InputStream clientCertificateStream, String ceritificateAlias) {
SSLContext sslContext = null;
BufferedInputStream bufferedInputStream = null;
try {
bufferedInputStream = new BufferedInputStream(clientCertificateStream);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(bufferedInputStream);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);// In order to create an empty keystore, pass null as the stream argument.
keyStore.setCertificateEntry(ceritificateAlias, x509Certificate);// Assigns the given trusted certificate to the given alias.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);// The provider typically uses a KeyStore as a basis for making trust decisions
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
} catch (Exception e) {
e.printStackTrace();
} finally {
bufferedInputStream.close();
clientCertificateStream.close();
}
return sslContext;
}
public SSLContext getKeyStoreBasedSSLContext(InputStream clientCertificateStream, String clientCertificatePassword) {
SSLContext sslContext = null;
BufferedInputStream bufferedInputStream = new BufferedInputStream(clientCertificateStream);
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(bufferedInputStream, clientCertificatePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientStore, clientCertificatePassword.toCharArray());
// The provider typically uses a KeyStore for obtaining key material for use during secure socket negotiations. The KeyStore is generally password-protected.
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, null, new SecureRandom());
} catch (Exception e) {
e.printStackTrace();
} finally {
bufferedInputStream.close();
clientCertificateStream.close();
}
return sslContext;
}
TCP/IP Layer | Protocol |
---|---|
Application Layer HTTP, NNTP, Telnet, FTP, etc. | |
Secure Sockets Layer | SSL |
Transport Layer | TCP |
Internet Layer | IP |
SSLEngine
The core class in this new abstraction is javax.net.ssl.SSLEngine. It encapsulates an SSL/TLS state machine and operates on inbound and outbound byte buffers supplied by the user of the SSLEngine. The following diagram illustrates the flow of data from the application, to the SSLEngine, to the transport mechanism, and back.
Engine Class Implemented | Algorithm or Protocol |
---|---|
KeyStore | PKCS12 |
KeyManagerFactory | PKIX, SunX509 |
TrustManagerFactory | PKIX (a.k.a. X509 or SunPKIX), SunX509 |
SSLContext | SSLv3 (a.k.a. SSL), TLSv1 (a.k.a. TLS), TLSv1.1, TLSv1.2 |
if a truststore is specified by the javax.net.ssl.trustStore system property, then the TrustManager created by the default SSLContext will be a TrustManager implementation for managing the specified truststore. In this case, if such a property exists but the file it specifies doesn't, then no truststore is utilized. If no javax.net.ssl.trustStore property exists, then a default truststore is searched for. If a truststore named /lib/security/jssecacerts is found, it is used. If not, then a truststore named /lib/security/cacerts is searched for and used (if it exists). See The Installation Directory for information as to what refers to. Finally, if a truststore is still not found, then the truststore managed by the TrustManager will be a new empty truststore.
IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the /lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.
If system properties javax.net.ssl.keyStoreType and/or javax.net.ssl.keyStorePassword are also specified, they are treated as the default KeyManager keystore type and password, respectively. If there is no type specified, the default type is that returned by KeyStore.getDefaultType(), which is the value of the keystore.type security property, or "jks" if no such security property is specified. If there is no keystore password specified, it is assumed to be "".
Signature | Encryption |
---|---|
import java.io.*; import java.net.*; import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*; import javax.ws.rs.core.Configuration;
import org.apache.commons.logging.*;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties;
public class HttpConnectionFactory {
private static final Log log = LogFactory.getLog(HttpConnectionFactory.class);
private Proxy proxy;
private String proxyHost;
private Integer proxyPort;
private String clientCertificatePassword;
private InputStream clientCertificateStream;
private String ceritificateAlias;
public HttpConnectionFactory() { }
public HttpConnectionFactory(String proxyHost, Integer proxyPort) {
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
}
private void initializeProxy() {
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
}
public Configuration getClientConfig() {
ClientConfig config = new ClientConfig();
config.connectorProvider(new ApacheConnectorProvider());
//Commenting proxy host and port for CLOUD changes
//config.property(ClientProperties.PROXY_URI, "http://" + proxyHost + ":" + proxyPort);
// config.property(ClientProperties.PROXY_USERNAME, "****");
// config.property(ClientProperties.PROXY_PASSWORD, "****");
return config;
}
public HttpURLConnection getHttpURLConnection(URL url) throws IOException {
HttpURLConnection httpURLConnection = null;
HttpsURLConnection httpsURLConnection = null;
if (proxyHost != null && proxyPort != null) {
initializeProxy();
httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
} else {
httpURLConnection = (HttpURLConnection) url.openConnection();
}
if (httpURLConnection instanceof HttpsURLConnection) {
try {
httpsURLConnection = getHttpsConnection(url);
} catch (TechnicalDeliveryException e) {
log.error(e, e);
}
return httpsURLConnection;
} else {
return httpURLConnection;
}
}
private HttpsURLConnection getHttpsConnection(URL url) throws IOException, TechnicalDeliveryException {
HttpsURLConnection httpsURLConnection = null;
try {
if (proxy != null) {
httpsURLConnection = (HttpsURLConnection) url.openConnection(proxy);
} else {
httpsURLConnection = (HttpsURLConnection) url.openConnection();
}
httpsURLConnection.setHostnameVerifier(getHostnameVerifier());
SSLSocketFactory sslSocketFactory = null;
if (clientCertificatePassword != null) {
log.info("SSL with password::");
sslSocketFactory = this.getKeyStoreBasedSSLContext().getSocketFactory();
} else {
log.info("SSL without password::");
sslSocketFactory = this.getCertificateFactoryBasedSSLContext().getSocketFactory();
}
if (sslSocketFactory != null) {
httpsURLConnection.setSSLSocketFactory(sslSocketFactory);
} else {
throw new TechnicalDeliveryException("sslSocketFactory for sslcontext is null");
}
} catch (KeyManagementException e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
} catch (KeyStoreException e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
} catch (NoSuchAlgorithmException e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
} catch (CertificateException e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
} catch (UnrecoverableKeyException e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
}
return httpsURLConnection;
}
public HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession)
{
return true;
}
};
}
public SSLContext getCertificateFactoryBasedSSLContext() throws CertificateException, NoSuchAlgorithmException,
KeyStoreException, IOException, KeyManagementException, TechnicalDeliveryException {
CertificateFactory certificateFactory;
X509Certificate x509Certificate;
TrustManagerFactory trustManagerFactory;
KeyStore keyStore;
SSLContext sslContext = null;
BufferedInputStream bufferedInputStream = null;
try {
bufferedInputStream = new BufferedInputStream(clientCertificateStream);
certificateFactory = CertificateFactory.getInstance("X.509");
x509Certificate = (X509Certificate) certificateFactory.generateCertificate(bufferedInputStream);
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
keyStore.setCertificateEntry(ceritificateAlias, x509Certificate);
trustManagerFactory.init(keyStore);
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
} catch (Exception e) {
log.error(e, e);
throw new TechnicalDeliveryException(e);
} finally {
bufferedInputStream.close();
clientCertificateStream.close();
}
return sslContext;
}
public SSLContext getKeyStoreBasedSSLContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException, KeyManagementException, TechnicalDeliveryException {
SSLContext sslContext = null;
KeyStore clientStore = KeyStore.getInstance("PKCS12");
BufferedInputStream bufferedInputStream = new BufferedInputStream(clientCertificateStream);
try {
log.info("loading certificate into client store");
clientStore.load(bufferedInputStream, clientCertificatePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientStore, clientCertificatePassword.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, null, new SecureRandom());
log.info("initialized sslcontext");
} catch (Exception e) {
} finally {
bufferedInputStream.close();
clientCertificateStream.close();
}
return sslContext;
}
public void setClientCertificatePassword(String clientCertificatePassword) {
this.clientCertificatePassword = clientCertificatePassword;
}
public void setClientCertificateStream(InputStream clientCertificateStream) {
this.clientCertificateStream = clientCertificateStream;
}
public void setCeritificateAlias(String ceritificateAlias) {
this.ceritificateAlias = ceritificateAlias;
}
}
class TechnicalDeliveryException extends Exception {
private static final long serialVersionUID = 372683934322930080L;
public TechnicalDeliveryException() {
super();
}
public TechnicalDeliveryException(String message) {
super(message);
}
public TechnicalDeliveryException(Throwable cause) {
super(cause);
}
public TechnicalDeliveryException(String message, Throwable cause) {
super(message, cause);
}
}
InputStream sslCertificateStream = null;
URL url = new URL(null, myPage);
String protocol = url.getProtocol();
log.info("URL Protocol: "+protocol);
HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory();
httpConnectionFactory.setClientCertificateStream(sslCertificateStream);// InputStream
httpConnectionFactory.setCeritificateAlias(sslAlias);// String
System.out.println("Using SSL Certificate");
HttpURLConnection connection = (HttpsURLConnection) httpConnectionFactory.getHttpURLConnection(url);
connection.setRequestMethod(httpMethod); // POST
// Authorization: Basic ZW9uMDE5XzAxOkVsaWFfMTIz
String authString = username + ":" + password;
String authMsg = "Basic " + Base64.encode(authString.getBytes());
connection.setRequestProperty(javax.ws.rs.core.HttpHeaders.AUTHORIZATION, authMsg);
TrustStore: As the name indicates, its normally used to store the certificates of trusted entities. A process can maintain a store of certificates of all its trusted parties which it trusts.
Keystore: Used to store the server keys (both public and private) along with signed cert.
During the SSL handshake,
A client tries to access https://
And thus, Server responds by providing a SSL certificate (which is stored in its keyStore)
Now, the client receives the SSL certificate and verifies it via trustStore (i.e the client's trustStore already has pre-defined set of certificates which it trusts.). Its like : Can I trust this server ? Is this the same server whom I am trying to talk to ? No middle man attacks ?
Once, the client verifies that it is talking to server which it trusts, then SSL communication can happen over a shared secret key.