package won.cryptography.ssl; import org.apache.http.conn.ssl.PrivateKeyDetails; import org.apache.http.conn.ssl.PrivateKeyStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import won.cryptography.service.KeyStoreService; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.X509KeyManager; import java.net.Socket; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Map; /** * User: ypanchenko * Date: 12.08.2015 * * This class is similar to the implementation of class TrustManagerDelegate of org.apache.http.conn.ssl * .SSLContextBuilder Unfortunately, they don't provide it as public class. It is useful when the default implementation * of X509KeyManager is used but additionally the strategy of how to choose the key when the key store contains many * keys is applied. * * For original see: * https://hc.apache.org/httpcomponents-client-4.4.x/httpclient/xref/org/apache/http/conn/ssl/SSLContextBuilder.html * */ public class KeyManagerWrapperWithKeyServiceAndStrategy implements X509KeyManager { private final Logger logger = LoggerFactory.getLogger(getClass()); private final X509KeyManager keyManager; private final PrivateKeyStrategy aliasStrategy; public KeyManagerWrapperWithKeyServiceAndStrategy(final KeyStoreService keyStoreService, final PrivateKeyStrategy aliasStrategy) { super(); this.aliasStrategy = aliasStrategy; KeyManagerFactory kmf = null; try { kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(keyStoreService.getUnderlyingKeyStore(), keyStoreService.getPassword().toCharArray()); } catch (Exception e) { logger.error("KeyManager could not be initialized"); throw new RuntimeException("KeyManager could not be initialized", e); } KeyManager[] kms = kmf.getKeyManagers(); if (kms != null) { if (aliasStrategy != null) { for (int i = 0; i < kms.length; i++) { KeyManager km = kms[i]; if (km instanceof X509KeyManager) { this.keyManager = (X509KeyManager) km; return; } } } } // we found no X509KeyManager in manager factory key managers this.keyManager = null; throw new RuntimeException("X509KeyManager could not be initialized"); } @Override public String[] getClientAliases(final String keyType, final Principal[] issuers) { return this.keyManager.getClientAliases(keyType, issuers); } @Override public String chooseClientAlias(final String[] keyTypes, final Principal[] issuers, final Socket socket) { final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>(); for (final String keyType: keyTypes) { final String[] aliases = this.keyManager.getClientAliases(keyType, issuers); if (aliases != null) { for (final String alias: aliases) { validAliases.put(alias, new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias))); } } } return this.aliasStrategy.chooseAlias(validAliases, socket); } @Override public String[] getServerAliases(final String keyType, final Principal[] issuers) { return this.keyManager.getServerAliases(keyType, issuers); } @Override public String chooseServerAlias(final String keyType, final Principal[] issuers, final Socket socket) { final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>(); final String[] aliases = this.keyManager.getServerAliases(keyType, issuers); if (aliases != null) { for (final String alias: aliases) { validAliases.put(alias, new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias))); } } return this.aliasStrategy.chooseAlias(validAliases, socket); } @Override public X509Certificate[] getCertificateChain(final String alias) { return this.keyManager.getCertificateChain(alias); } @Override public PrivateKey getPrivateKey(final String alias) { return this.keyManager.getPrivateKey(alias); } }