2727
2828import javax .net .ssl .HostnameVerifier ;
2929import javax .net .ssl .KeyManager ;
30+ import javax .net .ssl .KeyManagerFactory ;
3031import javax .net .ssl .SSLContext ;
3132import javax .net .ssl .TrustManager ;
3233import javax .net .ssl .TrustManagerFactory ;
3334import java .io .FileInputStream ;
35+ import java .io .FileNotFoundException ;
3436import java .io .IOException ;
3537import java .security .KeyManagementException ;
3638import java .security .KeyStore ;
3739import java .security .KeyStoreException ;
3840import java .security .NoSuchAlgorithmException ;
3941import java .security .SecureRandom ;
42+ import java .security .UnrecoverableKeyException ;
4043import java .security .cert .CertificateException ;
4144import java .util .Objects ;
4245
@@ -60,10 +63,28 @@ class HttpsContextBuilder {
6063 * Constructor.
6164 * @param configuration client configuration instance.
6265 */
63- HttpsContextBuilder (final Configuration configuration ) {
66+ public HttpsContextBuilder (final Configuration configuration ) {
6467 this .configuration = Objects .requireNonNull (configuration );
6568 }
6669
70+ /**
71+ * Properly configured SslSocketFactory based on client configuration.
72+ * @return SslSocketFactory instance.
73+ */
74+ public LayeredConnectionSocketFactory createSslSocketFactory () {
75+ // Emit an warning letting everyone know we're using an insecure configuration.
76+ if (configuration .getIgnoreInvalidSslCertificates ()) {
77+ logger .warn ("Using insecure configuration, skipping server-side certificate validation checks." );
78+ }
79+
80+ return new SSLConnectionSocketFactory (
81+ getSslContext (),
82+ getSslProtocols (),
83+ null ,
84+ getHostnameVerifier ()
85+ );
86+ }
87+
6788 /**
6889 * Get HostnameVerifier instance based on client configuration.
6990 * @return HostnameVerifier instance.
@@ -83,28 +104,78 @@ HostnameVerifier getHostnameVerifier() {
83104 * @return SSLContext instance.
84105 */
85106 SSLContext getSslContext () {
86- // Create default SSLContext
87- final SSLContext sslcontext = SSLContexts .createDefault ();
107+ try {
108+ // Create default SSLContext
109+ final SSLContext sslcontext = SSLContexts .createDefault ();
110+
111+ // Initialize ssl context with configured key and trust managers.
112+ sslcontext .init (getKeyManagers (), getTrustManagers (), new SecureRandom ());
113+
114+ return sslcontext ;
115+ } catch (final KeyManagementException e ) {
116+ throw new RuntimeException (e .getMessage (), e );
117+ }
118+ }
119+
120+ /**
121+ * Based on client configuration, construct KeyManager instances to use.
122+ * @return Array of 0 or more KeyManagers.
123+ */
124+ KeyManager [] getKeyManagers () {
125+ // If not configured to use a KeyStore
126+ if (configuration .getKeyStoreFile () == null ) {
127+ // Return null array.
128+ return new KeyManager [0 ];
129+ }
130+
131+ // If configured to use a key store
132+ try {
133+ final KeyManagerFactory keyFactory = KeyManagerFactory .getInstance (KeyManagerFactory .getDefaultAlgorithm ());
134+
135+ // New JKS Keystore.
136+ final KeyStore keyStore = KeyStore .getInstance ("JKS" );
137+ final char [] password ;
138+ if (configuration .getKeyStorePassword () == null ) {
139+ password = new char [0 ];
140+ } else {
141+ password = configuration .getKeyStorePassword ().toCharArray ();
142+ }
143+
144+ try (final FileInputStream keyStoreFileInput = new FileInputStream (configuration .getKeyStoreFile ())) {
145+ keyStore .load (keyStoreFileInput , password );
146+ }
147+ keyFactory .init (keyStore , password );
148+ return keyFactory .getKeyManagers ();
149+ } catch (final FileNotFoundException exception ) {
150+ throw new RuntimeException (
151+ "Unable to find configured KeyStore file \" " + configuration .getKeyStoreFile () + "\" " ,
152+ exception
153+ );
154+ } catch (final KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException e ) {
155+ throw new RuntimeException (e .getMessage (), e );
156+ }
157+ }
88158
159+ /**
160+ * Based on Client Configuration, construct TrustManager instances to use.
161+ * @return Array of 0 or more TrustManager instances.
162+ */
163+ TrustManager [] getTrustManagers () {
89164 try {
165+ final TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
166+
90167 // If client configuration is set to ignore invalid certificates
91168 if (configuration .getIgnoreInvalidSslCertificates ()) {
92169 // Initialize ssl context with a TrustManager instance that just accepts everything blindly.
93170 // HIGHLY INSECURE / NOT RECOMMENDED!
94- sslcontext . init ( new KeyManager [ 0 ], new TrustManager []{new NoopTrustManager ()}, new SecureRandom ()) ;
171+ return new TrustManager []{ new NoopTrustManager () } ;
95172
96173 // If client configuration has a trust store defined.
97174 } else if (configuration .getTrustStoreFile () != null ) {
98-
99- final TrustManagerFactory trustManagerFactory = TrustManagerFactory
100- .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
101-
102-
103- // New JKS Keystore.
104- final KeyStore keyStore = KeyStore .getInstance ("JKS" );
105-
106175 // Attempt to read the trust store from disk.
107176 try (final FileInputStream trustStoreFileInput = new FileInputStream (configuration .getTrustStoreFile ())) {
177+ // New JKS Keystore.
178+ final KeyStore keyStore = KeyStore .getInstance ("JKS" );
108179
109180 // If no trust store password is set.
110181 if (configuration .getTrustStorePassword () == null ) {
@@ -114,15 +185,20 @@ SSLContext getSslContext() {
114185 }
115186 trustManagerFactory .init (keyStore );
116187 }
117-
118- // Initialize ssl context with our custom loaded trust store.
119- sslcontext .init (new KeyManager [0 ], trustManagerFactory .getTrustManagers (), new SecureRandom ());
188+ return trustManagerFactory .getTrustManagers ();
189+ } else {
190+ // use default TrustManager instances
191+ trustManagerFactory .init ((KeyStore ) null );
192+ return trustManagerFactory .getTrustManagers ();
120193 }
121- } catch (final KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e ) {
122- throw new RuntimeException (e .getMessage (), e );
194+ } catch (final FileNotFoundException exception ) {
195+ throw new RuntimeException (
196+ "Unable to find configured TrustStore file \" " + configuration .getTrustStoreFile () + "\" " ,
197+ exception
198+ );
199+ } catch (final KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException exception ) {
200+ throw new RuntimeException (exception .getMessage (), exception );
123201 }
124-
125- return sslcontext ;
126202 }
127203
128204 /**
@@ -132,22 +208,4 @@ SSLContext getSslContext() {
132208 private String [] getSslProtocols () {
133209 return sslProtocols ;
134210 }
135-
136- /**
137- * Properly configured SslSocketFactory based on client configuration.
138- * @return SslSocketFactory instance.
139- */
140- LayeredConnectionSocketFactory createSslSocketFactory () {
141- // Emit an warning letting everyone know we're using an insecure configuration.
142- if (configuration .getIgnoreInvalidSslCertificates ()) {
143- logger .warn ("Using insecure configuration, skipping server-side certificate validation checks." );
144- }
145-
146- return new SSLConnectionSocketFactory (
147- getSslContext (),
148- getSslProtocols (),
149- null ,
150- getHostnameVerifier ()
151- );
152- }
153211}
0 commit comments