/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.security.ssl; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import com.emc.storageos.coordinator.client.service.*; import com.emc.storageos.security.keystore.impl.DistributedKeyStoreImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.security.keystore.impl.CoordinatorConfigStoringHelper; import com.emc.storageos.security.keystore.impl.KeyStoreUtil; /** * The official ViPR trust manager. Decides whether or not to accept certificates * according to trust material in the ViPR keystore, and the system settings. * NOTE: this object cannot be injected by spring, since it has a dependency on the keystore */ public class ViPRX509TrustManager implements X509TrustManager { private final static String X509_ALGORITHM = "SunX509"; private static Logger log = LoggerFactory.getLogger(ViPRX509TrustManager.class); private X509TrustManager defaultViPRTrustManager; private KeyStore keystore; private final CoordinatorConfigStoringHelper coordConfigStoringHelper; public ViPRX509TrustManager(CoordinatorClient coordinator) { coordConfigStoringHelper = new CoordinatorConfigStoringHelper(coordinator); try { keystore = KeyStoreUtil.getViPRKeystore(coordinator); } catch (GeneralSecurityException | IOException | InterruptedException e) { log.error(e.getMessage(), e); } loadTrustManager(); addTrustStoreListener(coordinator); } private void addTrustStoreListener(CoordinatorClient coordinator) { try { coordinator.addNodeListener(new TrustStoreListener()); } catch (Exception e) { log.error("Fail to add TrustStoreListener.", e); } } /** * loads the trust manager using the vipr keystore. */ private synchronized void loadTrustManager() { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance(X509_ALGORITHM); tmf.init(keystore); for (TrustManager trustManager : tmf.getTrustManagers()) { if (trustManager instanceof X509TrustManager) { defaultViPRTrustManager = (X509TrustManager) trustManager; log.debug("found a X509TrustManager instance"); break; } } log.info("renew trust manager. the # of certificates in trust store is {}", defaultViPRTrustManager.getAcceptedIssuers().length); } catch (GeneralSecurityException e) { log.error(e.getMessage(), e); } } /* * (non-Javadoc) * * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String) */ @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { defaultViPRTrustManager.checkClientTrusted(chain, authType); } catch (CertificateException e) { log.debug("Client certificate was not trusted by default trust manager, checking accept all certs config. Certificate: " + chain[0]); // if setting for accepting all connections is set to true if (KeyStoreUtil.getAcceptAllCerts(coordConfigStoringHelper)) { log.warn("The following certificate is not trusted." + chain[0]); } else { log.debug( "Accept all certs is set to false, the certificate will not be trusted", e); throw e; } } } /* * (non-Javadoc) * * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String) */ @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { defaultViPRTrustManager.checkServerTrusted(chain, authType); } catch (CertificateException e) { log.debug("Server certificate was not trusted by default trust manager, checking accept all certs config. Certificate: " + chain[0]); // if setting for accepting all connections is set to true if (KeyStoreUtil.getAcceptAllCerts(coordConfigStoringHelper)) { log.warn("The following certificate is not trusted." + chain[0]); } else { log.debug( "Accept all certs is set to false, the certificate will not be trusted", e); throw e; } } } /* * (non-Javadoc) * * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() */ @Override public X509Certificate[] getAcceptedIssuers() { X509Certificate[] acceptedIssuers = defaultViPRTrustManager.getAcceptedIssuers(); List<String> names = new ArrayList<String>(); for (X509Certificate x509Certificate : acceptedIssuers) { names.add(x509Certificate.getIssuerDN().getName()); } log.debug("Accepted issuers are: " + names); return acceptedIssuers; } /** * the listener class to listen the trust store node change. */ class TrustStoreListener implements NodeListener { public String getPath() { String path = String.format("/config/%s/%s", DistributedKeyStoreImpl.TRUSTED_CERTIFICATES_CONFIG_KIND, DistributedKeyStoreImpl.UPDATE_LOG); return path; } /** * called when user add/remove certificate from trust store. */ @Override public void nodeChanged() { log.info("Trust store changed. renewing the trust manager " + defaultViPRTrustManager); loadTrustManager(); } /** * called when connection state changed. */ @Override public void connectionStateChanged(State state) { if (state.equals(State.CONNECTED)) { log.info("Connection reconnected. reloading the trust manager " + defaultViPRTrustManager); loadTrustManager(); } } } }