Package: SslManagerServiceImpl

SslManagerServiceImpl

nameinstructionbranchcomplexitylinemethod
SslManagerServiceImpl()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
accessKeystore()
M: 0 C: 43
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 14
100%
M: 0 C: 1
100%
activate(ComponentContext, Map)
M: 0 C: 40
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
changeDefaultKeystorePassword()
M: 5 C: 44
90%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 1 C: 9
90%
M: 0 C: 1
100%
changeKeyStorePassword(String, char[], char[])
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
createSSLContext(String, String, KeyManager[], TrustManager[], boolean)
M: 3 C: 34
92%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 2 C: 8
80%
M: 0 C: 1
100%
deactivate(ComponentContext)
M: 8 C: 14
64%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 2 C: 4
67%
M: 0 C: 1
100%
deleteTrustCertificate(String)
M: 0 C: 21
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
getKeyManagers(String, char[], String)
M: 0 C: 16
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getKeyStore(String, char[], String)
M: 0 C: 69
100%
M: 2 C: 6
75%
M: 2 C: 3
60%
M: 0 C: 14
100%
M: 0 C: 1
100%
getKeyStorePassword()
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getOldKeystorePassword(String)
M: 0 C: 31
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
getSSLContext()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getSSLContext(String)
M: 0 C: 30
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
getSSLContext(String, String, String, String, char[], String)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getSSLContext(String, String, String, String, char[], String, boolean)
M: 0 C: 38
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 12
100%
M: 0 C: 1
100%
getSSLContextInternal(ConnectionSslOptions)
M: 0 C: 44
100%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 9
100%
M: 0 C: 1
100%
getSSLSocketFactory()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getSSLSocketFactory(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getSSLSocketFactory(String, String, String, String, char[], String)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getSSLSocketFactory(String, String, String, String, char[], String, boolean)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getTrustCertificates()
M: 1 C: 40
98%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 9
100%
M: 0 C: 1
100%
getTrustManagers(String, char[])
M: 0 C: 40
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 13
100%
M: 0 C: 1
100%
getUnencryptedSslKeystorePassword()
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
installPrivateKey(String, PrivateKey, char[], Certificate[])
M: 0 C: 24
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
installTrustCertificate(String, X509Certificate)
M: 0 C: 22
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
isDefaultFromCrypto()
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
isDefaultFromUser()
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isFirstBoot()
M: 0 C: 15
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
isKeyStoreAccessible(String, char[])
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
isSnapshotPasswordDefault()
M: 0 C: 14
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
loadKeystore(String, char[])
M: 0 C: 18
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
saveKeystore(String, char[], KeyStore)
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
setConfigurationService(ConfigurationService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setCryptoService(CryptoService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setSystemService(SystemService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
unsetConfigurationService(ConfigurationService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
unsetCryptoService(CryptoService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
unsetSystemService(SystemService)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
updateKeyEntiesPasswords(KeyStore, char[], char[])
M: 0 C: 36
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 9
100%
M: 0 C: 1
100%
updateKeystorePassword(char[], char[])
M: 0 C: 25
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
updatePasswordInConfigService(char[])
M: 0 C: 35
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
updated(Map)
M: 0 C: 23
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011, 2019 Eurotech and/or its affiliates
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License v1.0
6: * which accompanies this distribution, and is available at
7: * http://www.eclipse.org/legal/epl-v10.html
8: *
9: * Contributors:
10: * Eurotech
11: *******************************************************************************/
12: package org.eclipse.kura.core.ssl;
13:
14: import java.io.File;
15: import java.io.FileInputStream;
16: import java.io.FileOutputStream;
17: import java.io.IOException;
18: import java.io.InputStream;
19: import java.math.BigInteger;
20: import java.security.GeneralSecurityException;
21: import java.security.KeyManagementException;
22: import java.security.KeyStore;
23: import java.security.KeyStore.Entry;
24: import java.security.KeyStore.PasswordProtection;
25: import java.security.KeyStoreException;
26: import java.security.NoSuchAlgorithmException;
27: import java.security.PrivateKey;
28: import java.security.SecureRandom;
29: import java.security.UnrecoverableEntryException;
30: import java.security.cert.Certificate;
31: import java.security.cert.CertificateException;
32: import java.security.cert.X509Certificate;
33: import java.util.Arrays;
34: import java.util.Enumeration;
35: import java.util.HashMap;
36: import java.util.Map;
37: import java.util.concurrent.ConcurrentHashMap;
38: import java.util.concurrent.Executors;
39: import java.util.concurrent.ScheduledExecutorService;
40: import java.util.concurrent.ScheduledFuture;
41: import java.util.concurrent.TimeUnit;
42:
43: import javax.net.ssl.KeyManager;
44: import javax.net.ssl.KeyManagerFactory;
45: import javax.net.ssl.SSLContext;
46: import javax.net.ssl.SSLSocketFactory;
47: import javax.net.ssl.TrustManager;
48: import javax.net.ssl.TrustManagerFactory;
49: import javax.net.ssl.X509TrustManager;
50:
51: import org.eclipse.kura.KuraException;
52: import org.eclipse.kura.configuration.ConfigurableComponent;
53: import org.eclipse.kura.configuration.ConfigurationService;
54: import org.eclipse.kura.configuration.Password;
55: import org.eclipse.kura.crypto.CryptoService;
56: import org.eclipse.kura.ssl.SslManagerService;
57: import org.eclipse.kura.ssl.SslServiceListener;
58: import org.eclipse.kura.system.SystemService;
59: import org.osgi.service.component.ComponentContext;
60: import org.osgi.util.tracker.ServiceTracker;
61: import org.slf4j.Logger;
62: import org.slf4j.LoggerFactory;
63:
64: public class SslManagerServiceImpl implements SslManagerService, ConfigurableComponent {
65:
66: private static final Logger logger = LoggerFactory.getLogger(SslManagerServiceImpl.class);
67:
68: private SslServiceListeners sslServiceListeners;
69:
70: private ComponentContext ctx;
71: private Map<String, Object> properties;
72: private SslManagerServiceOptions options;
73:
74: private CryptoService cryptoService;
75: private ConfigurationService configurationService;
76:
77: private ScheduledExecutorService selfUpdaterExecutor;
78: private ScheduledFuture<?> selfUpdaterFuture;
79:
80: private Map<ConnectionSslOptions, SSLContext> sslContexts;
81:
82: private SystemService systemService;
83:
84: // ----------------------------------------------------------------
85: //
86: // Dependencies
87: //
88: // ----------------------------------------------------------------
89:
90: public void setCryptoService(CryptoService cryptoService) {
91: this.cryptoService = cryptoService;
92: }
93:
94: public void unsetCryptoService(CryptoService cryptoService) {
95: this.cryptoService = null;
96: }
97:
98: public void setConfigurationService(ConfigurationService configurationService) {
99: this.configurationService = configurationService;
100: }
101:
102: public void unsetConfigurationService(ConfigurationService configurationService) {
103: this.configurationService = null;
104: }
105:
106: public void setSystemService(SystemService systemService) {
107: this.systemService = systemService;
108: }
109:
110: public void unsetSystemService(SystemService systemService) {
111: this.systemService = null;
112: }
113:
114: // ----------------------------------------------------------------
115: //
116: // Activation APIs
117: //
118: // ----------------------------------------------------------------
119:
120: protected void activate(ComponentContext componentContext, Map<String, Object> properties) {
121: logger.info("activate...");
122:
123: //
124: // save the bundle context and the properties
125: this.ctx = componentContext;
126: this.properties = properties;
127: this.options = new SslManagerServiceOptions(properties);
128: this.sslContexts = new ConcurrentHashMap<>();
129:
130: this.selfUpdaterExecutor = Executors.newSingleThreadScheduledExecutor();
131:
132: ServiceTracker<SslServiceListener, SslServiceListener> listenersTracker = new ServiceTracker<>(
133: componentContext.getBundleContext(), SslServiceListener.class, null);
134:
135: // Deferred open of tracker to prevent
136: // java.lang.Exception: Recursive invocation of
137: // ServiceFactory.getService
138: // on ProSyst
139: this.sslServiceListeners = new SslServiceListeners(listenersTracker);
140:
141: accessKeystore();
142: }
143:
144: public void updated(Map<String, Object> properties) {
145: logger.info("updated...");
146:
147: this.properties = properties;
148: this.options = new SslManagerServiceOptions(properties);
149: this.sslContexts = new ConcurrentHashMap<>();
150:
151: accessKeystore();
152:
153: // Notify listeners that service has been updated
154: this.sslServiceListeners.onConfigurationUpdated();
155: }
156:
157: protected void deactivate(ComponentContext componentContext) {
158: logger.info("deactivate...");
159: this.sslServiceListeners.close();
160:• if (this.selfUpdaterFuture != null && !this.selfUpdaterFuture.isDone()) {
161:
162: logger.info("Self updater task running. Stopping it");
163:
164: this.selfUpdaterFuture.cancel(true);
165: }
166: }
167:
168: // ----------------------------------------------------------------
169: //
170: // Service APIs
171: //
172: // ----------------------------------------------------------------
173:
174: @Override
175: public SSLContext getSSLContext() throws GeneralSecurityException, IOException {
176: return getSSLContext("");
177: }
178:
179: @Override
180: public SSLContext getSSLContext(String keyAlias) throws GeneralSecurityException, IOException {
181: String protocol = this.options.getSslProtocol();
182: String ciphers = this.options.getSslCiphers();
183: String trustStore = this.options.getSslKeyStore();
184: char[] keyStorePassword = getKeyStorePassword();
185: boolean hostnameVerifcation = this.options.isSslHostnameVerification();
186:
187: return getSSLContext(protocol, ciphers, trustStore, trustStore, keyStorePassword, keyAlias,
188: hostnameVerifcation);
189: }
190:
191: @Override
192: public SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore,
193: char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException {
194: return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias,
195: this.options.isSslHostnameVerification());
196: }
197:
198: @Override
199: public SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore,
200: char[] keyStorePassword, String keyAlias, boolean hostnameVerification)
201: throws GeneralSecurityException, IOException {
202: ConnectionSslOptions connSslOpts = new ConnectionSslOptions(this.options);
203: connSslOpts.setProtocol(protocol);
204: connSslOpts.setCiphers(ciphers);
205: connSslOpts.setTrustStore(trustStore);
206: connSslOpts.setKeyStore(keyStore);
207:• if (keyStorePassword == null) {
208: connSslOpts.setKeyStorePassword(getKeyStorePassword());
209: } else {
210: connSslOpts.setKeyStorePassword(keyStorePassword);
211: }
212: connSslOpts.setAlias(keyAlias);
213: connSslOpts.setHostnameVerification(hostnameVerification);
214:
215: return getSSLContextInternal(connSslOpts);
216: }
217:
218: @Override
219: public SSLSocketFactory getSSLSocketFactory() throws GeneralSecurityException, IOException {
220: return getSSLContext().getSocketFactory();
221: }
222:
223: @Override
224: public SSLSocketFactory getSSLSocketFactory(String keyAlias) throws GeneralSecurityException, IOException {
225: return getSSLContext(keyAlias).getSocketFactory();
226: }
227:
228: @Override
229: public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore,
230: char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException {
231: return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias).getSocketFactory();
232: }
233:
234: @Override
235: public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore,
236: char[] keyStorePassword, String keyAlias, boolean hostnameVerification)
237: throws GeneralSecurityException, IOException {
238: return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias, hostnameVerification)
239: .getSocketFactory();
240: }
241:
242: @Override
243: public X509Certificate[] getTrustCertificates() throws GeneralSecurityException, IOException {
244: X509Certificate[] cacerts = null;
245: String trustStore = this.options.getSslKeyStore();
246: TrustManager[] tms = getTrustManagers(trustStore, this.options.getSslKeystorePassword().toCharArray());
247:• for (TrustManager tm : tms) {
248:• if (tm instanceof X509TrustManager) {
249: X509TrustManager x509tm = (X509TrustManager) tm;
250: cacerts = x509tm.getAcceptedIssuers();
251: break;
252: }
253: }
254: return cacerts;
255: }
256:
257: @Override
258: public void installTrustCertificate(String alias, X509Certificate x509crt)
259: throws GeneralSecurityException, IOException {
260:
261: String keyStore = this.options.getSslKeyStore();
262: char[] keyStorePassword = getKeyStorePassword();
263:
264: KeyStore ks = loadKeystore(keyStore, keyStorePassword);
265:
266: ks.setCertificateEntry(alias, x509crt);
267:
268: saveKeystore(keyStore, keyStorePassword, ks);
269: }
270:
271: @Override
272: public void deleteTrustCertificate(String alias) throws GeneralSecurityException, IOException {
273: String keyStore = this.options.getSslKeyStore();
274: char[] keyStorePassword = getKeyStorePassword();
275:
276: KeyStore ks = loadKeystore(keyStore, keyStorePassword);
277:
278: ks.deleteEntry(alias);
279:
280: saveKeystore(keyStore, keyStorePassword, ks);
281: }
282:
283: @Override
284: public void installPrivateKey(String alias, PrivateKey privateKey, char[] password, Certificate[] publicCerts)
285: throws GeneralSecurityException, IOException {
286: // Note that password parameter is unused
287:
288: String keyStore = this.options.getSslKeyStore();
289: char[] keyStorePassword = getKeyStorePassword();
290:
291: KeyStore ks = loadKeystore(keyStore, keyStorePassword);
292:
293: ks.setKeyEntry(alias, privateKey, keyStorePassword, publicCerts);
294:
295: saveKeystore(keyStore, keyStorePassword, ks);
296: }
297:
298: private void saveKeystore(String keyStoreFileName, char[] keyStorePassword, KeyStore ks)
299: throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
300: try (FileOutputStream tsOutStream = new FileOutputStream(keyStoreFileName);) {
301: ks.store(tsOutStream, keyStorePassword);
302: }
303: }
304:
305: private KeyStore loadKeystore(String keyStore, char[] keyStorePassword)
306: throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
307: KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
308:
309: try (InputStream tsReadStream = new FileInputStream(keyStore);) {
310: ks.load(tsReadStream, keyStorePassword);
311: }
312:
313: return ks;
314: }
315:
316: private void accessKeystore() {
317: String keystorePath = this.options.getSslKeyStore();
318: File fKeyStore = new File(keystorePath);
319:• if (!fKeyStore.exists()) {
320: return;
321: }
322:
323:• if (isFirstBoot()) {
324: changeDefaultKeystorePassword();
325: } else {
326: char[] oldPassword = getOldKeystorePassword(keystorePath);
327:
328: char[] newPassword = null;
329: try {
330: newPassword = this.cryptoService.decryptAes(this.options.getSslKeystorePassword().toCharArray());
331: } catch (KuraException e) {
332: logger.warn("Failed to decrypt keystore password");
333: }
334: updateKeystorePassword(oldPassword, newPassword);
335: }
336: }
337:
338: private char[] getOldKeystorePassword(String keystorePath) {
339: char[] password = this.cryptoService.getKeyStorePassword(keystorePath);
340:• if (password != null && isKeyStoreAccessible(this.options.getSslKeyStore(), password)) {
341: return password;
342: }
343:
344: try {
345: password = this.cryptoService.decryptAes(this.options.getSslKeystorePassword().toCharArray());
346: } catch (KuraException e) {
347: password = new char[0];
348: }
349:
350: return password;
351: }
352:
353: private void updateKeystorePassword(char[] oldPassword, char[] newPassword) {
354: try {
355: changeKeyStorePassword(this.options.getSslKeyStore(), oldPassword, newPassword);
356:
357: this.cryptoService.setKeyStorePassword(this.options.getSslKeyStore(), newPassword);
358: } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | UnrecoverableEntryException
359: | IOException e) {
360: logger.warn("Failed to change keystore password");
361: } catch (KuraException e) {
362: logger.warn("Failed to persist keystore password");
363: }
364: }
365:
366: private void changeDefaultKeystorePassword() {
367:
368: char[] oldPassword = this.systemService.getJavaKeyStorePassword();
369:
370:• if (isDefaultFromCrypto()) {
371: oldPassword = this.cryptoService.getKeyStorePassword(this.options.getSslKeyStore());
372: }
373:
374: char[] newPassword = new BigInteger(160, new SecureRandom()).toString(32).toCharArray();
375:
376: try {
377: changeKeyStorePassword(this.options.getSslKeyStore(), oldPassword, newPassword);
378:
379: this.cryptoService.setKeyStorePassword(this.options.getSslKeyStore(), newPassword);
380:
381: updatePasswordInConfigService(newPassword);
382: } catch (Exception e) {
383: logger.warn("Keystore password change failed", e);
384: }
385: }
386:
387: private void updatePasswordInConfigService(char[] newPassword) {
388: // update our configuration with the newly generated password
389: final String pid = (String) this.properties.get("service.pid");
390:
391: Map<String, Object> props = new HashMap<>(this.properties);
392: props.put(SslManagerServiceOptions.PROP_TRUST_PASSWORD, new Password(newPassword));
393:
394: this.selfUpdaterFuture = this.selfUpdaterExecutor.scheduleAtFixedRate(new Runnable() {
395:
396: @Override
397: public void run() {
398: try {
399: if (SslManagerServiceImpl.this.ctx.getServiceReference() != null
400: && SslManagerServiceImpl.this.configurationService.getComponentConfiguration(pid) != null) {
401: SslManagerServiceImpl.this.configurationService.updateConfiguration(pid, props);
402: throw new RuntimeException("Updated. The task will be terminated.");
403: } else {
404: logger.info("No service or configuration available yet.");
405: }
406: } catch (KuraException e) {
407: logger.warn("Cannot get/update configuration for pid: {}", pid, e);
408: }
409: }
410: }, 1000, 1000, TimeUnit.MILLISECONDS);
411: }
412:
413: private boolean isFirstBoot() {
414: boolean result = false;
415:• if (isSnapshotPasswordDefault() && (isDefaultFromUser() || isDefaultFromCrypto())) {
416: result = true;
417: }
418: return result;
419: }
420:
421: private boolean isSnapshotPasswordDefault() {
422: boolean result = false;
423:
424: char[] snapshotPassword = getUnencryptedSslKeystorePassword();
425:• if (Arrays.equals(SslManagerServiceOptions.PROP_DEFAULT_TRUST_PASSWORD.toCharArray(), snapshotPassword)) {
426: result = true;
427: }
428:
429: return result;
430: }
431:
432: private char[] getUnencryptedSslKeystorePassword() {
433: char[] snapshotPassword = this.options.getSslKeystorePassword().toCharArray();
434: try {
435: snapshotPassword = this.cryptoService.decryptAes(snapshotPassword);
436: } catch (KuraException e) {
437: // Nothing to do
438: }
439: return snapshotPassword;
440: }
441:
442: private boolean isDefaultFromCrypto() {
443: char[] cryptoPassword = this.cryptoService.getKeyStorePassword(this.options.getSslKeyStore());
444:
445: return isKeyStoreAccessible(this.options.getSslKeyStore(), cryptoPassword);
446: }
447:
448: private boolean isDefaultFromUser() {
449: return isKeyStoreAccessible(this.options.getSslKeyStore(), this.systemService.getJavaKeyStorePassword());
450: }
451:
452: // ----------------------------------------------------------------
453: //
454: // Private methods
455: //
456: // ----------------------------------------------------------------
457:
458: private SSLContext getSSLContextInternal(ConnectionSslOptions options)
459: throws GeneralSecurityException, IOException {
460: // Only create a new SSLSocketFactory instance if the configuration has
461: // changed or
462: // for a new alias.
463: // This allows for SSL Context Resumption and abbreviated SSL handshake
464: // in case of reconnects to the same host.
465: SSLContext context = this.sslContexts.get(options);
466:• if (context == null) {
467: logger.info("Creating a new SSLSocketFactory instance");
468:
469: TrustManager[] tms = getTrustManagers(options.getTrustStore(), options.getKeyStorePassword());
470:
471: KeyManager[] kms = getKeyManagers(options.getKeyStore(), options.getKeyStorePassword(), options.getAlias());
472:
473: context = createSSLContext(options.getProtocol(), options.getCiphers(), kms, tms,
474: options.getHostnameVerification());
475: this.sslContexts.put(options, context);
476: }
477:
478: return context;
479: }
480:
481: private static SSLContext createSSLContext(String protocol, String ciphers, KeyManager[] kms, TrustManager[] tms,
482: boolean hostnameVerification) throws NoSuchAlgorithmException, KeyManagementException {
483: // inits the SSL context
484: SSLContext sslCtx;
485:• if (protocol == null) {
486: sslCtx = SSLContext.getDefault();
487: } else {
488: sslCtx = SSLContext.getInstance(protocol);
489: sslCtx.init(kms, tms, null);
490: }
491:
492: // get the SSLSocketFactory
493: final SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();
494: final SSLSocketFactoryWrapper socketFactoryWrapper = new SSLSocketFactoryWrapper(sslSocketFactory, ciphers,
495: hostnameVerification);
496:
497: // wrap it
498: return new SSLContext(new SSLContextSPIWrapper(sslCtx, socketFactoryWrapper), sslCtx.getProvider(),
499: sslCtx.getProtocol()) {
500: };
501: }
502:
503: private static TrustManager[] getTrustManagers(String trustStore, char[] keyStorePassword)
504: throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
505: TrustManager[] result = new TrustManager[0];
506: TrustManagerFactory tmf = null;
507:• if (trustStore != null) {
508:
509: // Load the configured the Trust Store
510: File fTrustStore = new File(trustStore);
511:• if (fTrustStore.exists()) {
512:
513: KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
514: InputStream tsReadStream = new FileInputStream(trustStore);
515: ts.load(tsReadStream, keyStorePassword);
516: tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
517: tmf.init(ts);
518: result = tmf.getTrustManagers();
519: tsReadStream.close();
520: }
521: }
522: return result;
523: }
524:
525: private KeyManager[] getKeyManagers(String keyStore, char[] keyStorePassword, String keyAlias)
526: throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
527: UnrecoverableEntryException {
528: KeyStore ks = getKeyStore(keyStore, keyStorePassword, keyAlias);
529:
530: KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
531: kmf.init(ks, keyStorePassword);
532:
533: return kmf.getKeyManagers();
534: }
535:
536: private KeyStore getKeyStore(String keyStore, char[] keyStorePassword, String keyAlias) throws KeyStoreException,
537: IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableEntryException {
538:
539: // Load the configured the Key Store
540: File fKeyStore = new File(keyStore);
541:• if (!fKeyStore.exists() || !isKeyStoreAccessible(keyStore, keyStorePassword)) {
542: logger.warn("The referenced keystore does not exist or is not accessible");
543: throw new KeyStoreException("The referenced keystore does not exist or is not accessible");
544: }
545:
546: try (InputStream ksReadStream = new FileInputStream(keyStore);) {
547: KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
548: ks.load(ksReadStream, keyStorePassword);
549:
550: // if we have an alias, then build KeyStore with such key
551:• if (ks.containsAlias(keyAlias) && ks.isKeyEntry(keyAlias)) {
552: PasswordProtection pp = new PasswordProtection(keyStorePassword);
553: Entry entry = ks.getEntry(keyAlias, pp);
554: ks = KeyStore.getInstance(KeyStore.getDefaultType());
555: ks.load(null, null);
556: ks.setEntry(keyAlias, entry, pp);
557: }
558:
559: return ks;
560: }
561: }
562:
563: private char[] getKeyStorePassword() {
564: return this.cryptoService.getKeyStorePassword(this.options.getSslKeyStore());
565: }
566:
567: private boolean isKeyStoreAccessible(String location, char[] password) {
568: try {
569: loadKeystore(location, password);
570: return true;
571: } catch (Exception e) {
572: return false;
573: }
574: }
575:
576: private void changeKeyStorePassword(String location, char[] oldPassword, char[] newPassword) throws IOException,
577: NoSuchAlgorithmException, CertificateException, KeyStoreException, UnrecoverableEntryException {
578:
579: KeyStore keystore = loadKeystore(location, oldPassword);
580:
581: updateKeyEntiesPasswords(keystore, oldPassword, newPassword);
582: saveKeystore(location, newPassword, keystore);
583: }
584:
585: private static void updateKeyEntiesPasswords(KeyStore keystore, char[] oldPassword, char[] newPassword)
586: throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
587: Enumeration<String> aliases = keystore.aliases();
588:• while (aliases.hasMoreElements()) {
589: String alias = aliases.nextElement();
590:• if (keystore.isKeyEntry(alias)) { // TODO: not sure why this check
591: PasswordProtection oldPP = new PasswordProtection(oldPassword);
592: Entry entry = keystore.getEntry(alias, oldPP);
593: PasswordProtection newPP = new PasswordProtection(newPassword);
594: keystore.setEntry(alias, entry, newPP);
595: }
596: }
597: }
598:
599: }