1717
1818import com .rabbitmq .client .impl .AMQConnection ;
1919
20- import javax .net .ssl .*;
20+ import javax .net .ssl .KeyManager ;
21+ import javax .net .ssl .KeyManagerFactory ;
22+ import javax .net .ssl .SSLContext ;
23+ import javax .net .ssl .TrustManager ;
24+ import javax .net .ssl .TrustManagerFactory ;
25+ import java .io .BufferedReader ;
2126import java .io .FileInputStream ;
2227import java .io .FileNotFoundException ;
2328import java .io .IOException ;
2429import java .io .InputStream ;
30+ import java .io .InputStreamReader ;
2531import java .net .URISyntaxException ;
26- import java .security .*;
32+ import java .security .GeneralSecurityException ;
33+ import java .security .KeyManagementException ;
34+ import java .security .KeyStore ;
35+ import java .security .KeyStoreException ;
36+ import java .security .NoSuchAlgorithmException ;
2737import java .security .cert .CertificateException ;
28- import java .util .*;
38+ import java .util .Arrays ;
39+ import java .util .Collections ;
40+ import java .util .HashMap ;
41+ import java .util .List ;
42+ import java .util .Map ;
43+ import java .util .Optional ;
44+ import java .util .Properties ;
2945import java .util .concurrent .ConcurrentHashMap ;
3046
47+ import static java .nio .charset .StandardCharsets .US_ASCII ;
48+
3149/**
3250 * Helper class to load {@link ConnectionFactory} settings from a property file.
3351 * <p>
@@ -72,6 +90,7 @@ public class ConnectionFactoryConfigurator {
7290 public static final String SSL_ENABLED = "ssl.enabled" ;
7391 public static final String SSL_KEY_STORE = "ssl.key.store" ;
7492 public static final String SSL_KEY_STORE_PASSWORD = "ssl.key.store.password" ;
93+ public static final String SSL_KEY_PASSWORD = "ssl.key.password" ;
7594 public static final String SSL_KEY_STORE_TYPE = "ssl.key.store.type" ;
7695 public static final String SSL_KEY_STORE_ALGORITHM = "ssl.key.store.algorithm" ;
7796 public static final String SSL_TRUST_STORE = "ssl.trust.store" ;
@@ -80,11 +99,13 @@ public class ConnectionFactoryConfigurator {
8099 public static final String SSL_TRUST_STORE_ALGORITHM = "ssl.trust.store.algorithm" ;
81100 public static final String SSL_VALIDATE_SERVER_CERTIFICATE = "ssl.validate.server.certificate" ;
82101 public static final String SSL_VERIFY_HOSTNAME = "ssl.verify.hostname" ;
102+ public static final String PEM_TYPE = "PEM" ;
83103
84104 // aliases allow to be compatible with keys from Spring Boot and still be consistent with
85105 // the initial naming of the keys
86106 private static final Map <String , List <String >> ALIASES = new ConcurrentHashMap <String , List <String >>() {{
87107 put (SSL_KEY_STORE , Arrays .asList ("ssl.key-store" ));
108+ put (SSL_KEY_PASSWORD , Arrays .asList ("ssl.key-password" ));
88109 put (SSL_KEY_STORE_PASSWORD , Arrays .asList ("ssl.key-store-password" ));
89110 put (SSL_KEY_STORE_TYPE , Arrays .asList ("ssl.key-store-type" ));
90111 put (SSL_KEY_STORE_ALGORITHM , Arrays .asList ("ssl.key-store-algorithm" ));
@@ -228,6 +249,7 @@ private static void setUpSsl(ConnectionFactory cf, Map<String, String> propertie
228249 String algorithm = lookUp (SSL_ALGORITHM , properties , prefix );
229250 String keyStoreLocation = lookUp (SSL_KEY_STORE , properties , prefix );
230251 String keyStorePassword = lookUp (SSL_KEY_STORE_PASSWORD , properties , prefix );
252+ String keyPassword = lookUp (SSL_KEY_PASSWORD , properties , prefix );
231253 String keyStoreType = lookUp (SSL_KEY_STORE_TYPE , properties , prefix , "PKCS12" );
232254 String keyStoreAlgorithm = lookUp (SSL_KEY_STORE_ALGORITHM , properties , prefix , "SunX509" );
233255 String trustStoreLocation = lookUp (SSL_TRUST_STORE , properties , prefix );
@@ -250,7 +272,7 @@ private static void setUpSsl(ConnectionFactory cf, Map<String, String> propertie
250272 algorithm
251273 );
252274 } else {
253- KeyManager [] keyManagers = configureKeyManagers (keyStoreLocation , keyStorePassword , keyStoreType , keyStoreAlgorithm );
275+ KeyManager [] keyManagers = configureKeyManagers (keyStoreLocation , keyStorePassword , keyStoreType , keyStoreAlgorithm , keyPassword );
254276 TrustManager [] trustManagers = configureTrustManagers (trustStoreLocation , trustStorePassword , trustStoreType , trustStoreAlgorithm );
255277
256278 // create ssl context
@@ -263,31 +285,57 @@ private static void setUpSsl(ConnectionFactory cf, Map<String, String> propertie
263285 cf .enableHostnameVerification ();
264286 }
265287 }
266- } catch (NoSuchAlgorithmException | IOException | CertificateException |
267- UnrecoverableKeyException | KeyStoreException | KeyManagementException e ) {
288+ } catch (IOException | GeneralSecurityException e ) {
268289 throw new IllegalStateException ("Error while configuring TLS" , e );
269290 }
270291 }
271292
272- private static KeyManager [] configureKeyManagers (String keystore , String keystorePassword , String keystoreType , String keystoreAlgorithm ) throws KeyStoreException , IOException , NoSuchAlgorithmException ,
273- CertificateException , UnrecoverableKeyException {
274- char [] keyPassphrase = null ;
275- if (keystorePassword != null ) {
276- keyPassphrase = keystorePassword .toCharArray ();
277- }
293+ private static KeyManager [] configureKeyManagers (String keyStoreLocation , String keystorePassword , String keystoreType , String keystoreAlgorithm , String keyPassword ) throws IOException , GeneralSecurityException {
278294 KeyManager [] keyManagers = null ;
279- if (keystore != null ) {
280- KeyStore ks = KeyStore .getInstance (keystoreType );
281- try (InputStream in = loadResource (keystore )) {
282- ks .load (in , keyPassphrase );
295+ if (keyStoreLocation != null ) {
296+ KeyStore ks = configureKeyStore (keyStoreLocation , keystorePassword , keystoreType , keyPassword );
297+
298+ char [] password = "" .toCharArray ();
299+ if (PEM_TYPE .equalsIgnoreCase (keystoreType ) && keyPassword != null ) {
300+ password = keyPassword .toCharArray ();
301+ } else if (keystorePassword != null ) {
302+ password = keystorePassword .toCharArray ();
283303 }
304+
284305 KeyManagerFactory kmf = KeyManagerFactory .getInstance (keystoreAlgorithm );
285- kmf .init (ks , keyPassphrase );
306+ kmf .init (ks , password );
286307 keyManagers = kmf .getKeyManagers ();
287308 }
288309 return keyManagers ;
289310 }
290311
312+ private static KeyStore configureKeyStore (String keyStoreLocation , String keyStorePassword , String keystoreType , String keyPassword ) throws GeneralSecurityException , IOException {
313+ try (InputStream in = loadResource (keyStoreLocation )) {
314+ if (PEM_TYPE .equalsIgnoreCase (keystoreType )) {
315+ if (keyStorePassword != null && !keyStorePassword .isEmpty ())
316+ throw new CertificateException ("KeyStore password cannot be specified with PEM format, only key password may be specified" );
317+ else {
318+ StringBuilder readerBuilder = new StringBuilder ();
319+ try (BufferedReader br = new BufferedReader (new InputStreamReader (in , US_ASCII ))) {
320+ String inputLine ;
321+ while ((inputLine = br .readLine ()) != null ) {
322+ readerBuilder .append (inputLine ).append ('\n' );
323+ }
324+ }
325+
326+ String pemFileContents = readerBuilder .toString ();
327+ return PemReader .loadKeyStore (pemFileContents , pemFileContents , Optional .ofNullable (keyPassword ));
328+ }
329+ } else {
330+ char [] keyPassphrase = keyStorePassword == null ? null : keyStorePassword .toCharArray ();
331+
332+ KeyStore ks = KeyStore .getInstance (keystoreType );
333+ ks .load (in , keyPassphrase );
334+ return ks ;
335+ }
336+ }
337+ }
338+
291339 private static TrustManager [] configureTrustManagers (String truststore , String truststorePassword , String truststoreType , String truststoreAlgorithm )
292340 throws KeyStoreException , IOException , NoSuchAlgorithmException , CertificateException {
293341 char [] trustPassphrase = null ;
0 commit comments