/* * SSLKeyManager.java * * Created on 20 July 2005, 10:05 * * To change this template, choose Tools | Options and locate the template under * the Source Creation and Management node. Right-click the template and choose * Open. You can then make changes to the template in the Source Editor. */ package org.owasp.webscarab.plugin; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.KeyManager; import javax.net.ssl.X509KeyManager; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.Principal; import java.security.PrivateKey; import java.security.Provider; import java.security.Security; import java.security.cert.X509Certificate; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.net.Socket; import java.util.Map; import java.util.TreeMap; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.Enumeration; import java.util.logging.Logger; import java.util.logging.Level; import java.io.IOException; import java.io.FileInputStream; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeListener; /** * * @author rdawes */ public class SSLKeyManager implements X509KeyManager { public final static String KEY_PROPERTY = "KEYS"; public final static String SELECTED_KEY = "SELECTED KEY"; private static final String SEP = " -:- "; private String _preferredStore = null; private String _preferredAlias = null; private X509KeyManager _preferredKeyManager = null; private Map<String, KeyStore> _stores = new TreeMap<String, KeyStore>(); private Map<String, X509KeyManager> _managers = new TreeMap<String, X509KeyManager>(); private PropertyChangeSupport _changeSupport = new PropertyChangeSupport(this); private Logger _logger = Logger.getLogger(getClass().getName()); /** * Creates a new instance of SSLKeyManager */ public SSLKeyManager() { _logger.setLevel(Level.FINEST); if (System.getProperty("os.name", "").toLowerCase().indexOf("windows")>-1) { Provider provider; try { provider = (Provider) Class.forName("se.assembla.jce.provider.ms.MSProvider").newInstance(); } catch (Throwable t) { return; } try { Security.insertProviderAt(provider, 2); KeyStore ks = KeyStore.getInstance("msks", "assembla"); ks.load(null, null); addKeyStore("Microsoft CAPI store", ks, null); } catch (Exception e) { _logger.info("Microsoft CAPI interface not available: " + e); } } } public synchronized String addPKCS12KeyStore(String filename, String keyStorePassword, String keyPassword) throws KeyStoreException, UnrecoverableKeyException, IOException, CertificateException { if (keyStorePassword == null) keyStorePassword = ""; if (keyPassword == null) keyPassword = keyStorePassword; try { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream(filename), keyStorePassword.toCharArray()); String description = "PKCS#12: " + filename; addKeyStore(description, ks, keyPassword.toCharArray()); return description; } catch (NoSuchAlgorithmException nsae) { _logger.severe("No SunX509 suport: " + nsae); return null; } } public synchronized void addKeyStore(String description, KeyStore ks, char[] password) throws KeyStoreException, UnrecoverableKeyException { try { KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, password); KeyManager km = kmf.getKeyManagers()[0]; if (!(km instanceof X509KeyManager)) throw new KeyStoreException("KeyManager for " + description + "is not X509!"); _stores.put(description, ks); _managers.put(description, (X509KeyManager) km); } catch (NoSuchAlgorithmException nsae) { _logger.severe("This should never happen! SunX509 algorithm not found: " + nsae.getMessage()); } _changeSupport.firePropertyChange(KEY_PROPERTY, null, null); } public String[] getKeyStoreDescriptions() { return _stores.keySet().toArray(new String[0]); } public synchronized void removeKeyStore(String description) { _stores.remove(description); _changeSupport.firePropertyChange(KEY_PROPERTY, null, null); } public void addPropertyChangeListener(PropertyChangeListener listener) { _changeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { _changeSupport.removePropertyChangeListener(listener); } public synchronized String[] getAliases(String description) { KeyStore ks = _stores.get(description); if (ks == null) { return null; } List<String> aliases = new ArrayList<String>(); try { Enumeration<String> e = ks.aliases(); while (e.hasMoreElements()) { aliases.add(e.nextElement()); } } catch (KeyStoreException kse) { _logger.severe("Error enumerating aliases: " + kse.getMessage()); } return aliases.toArray(new String[0]); } public synchronized boolean setPreferredAlias(String description, String alias) { String old = String.valueOf(_preferredStore) + SEP + String.valueOf(_preferredAlias); if (description != null && alias != null) { KeyStore ks = _stores.get(description); try { if (ks.isKeyEntry(alias)) { _preferredKeyManager = _managers.get(description); _preferredStore = description; _preferredAlias = alias; String now = String.valueOf(_preferredStore) + SEP + String.valueOf(_preferredAlias); if (!now.equals(old)) _changeSupport.firePropertyChange(SELECTED_KEY, null, null); return true; } } catch (KeyStoreException kse) { _logger.severe("Unexpected KeyStore exception: " + kse.getMessage()); } } _preferredKeyManager = null; _preferredStore = null; _preferredAlias = null; String now = String.valueOf(_preferredStore) + SEP + String.valueOf(_preferredAlias); if (!now.equals(old)) _changeSupport.firePropertyChange(SELECTED_KEY, null, null); return false; } public String getPreferredStore() { return _preferredStore; } public String getPreferredAlias() { return _preferredAlias; } public synchronized String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { _logger.entering(getClass().getName(), "chooseClientAlias"); if (_preferredStore != null && _preferredAlias != null) return _preferredStore + SEP + _preferredAlias; return null; } public synchronized String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { if (_preferredKeyManager != null) return _preferredKeyManager.chooseServerAlias(keyType, issuers, socket); Iterator<String> it = _managers.keySet().iterator(); while (it.hasNext()) { String source = it.next(); X509KeyManager km = _managers.get(source); String alias = km.chooseServerAlias(keyType, issuers, socket); if (alias != null) return source + SEP + alias; } return null; } public synchronized X509Certificate[] getCertificateChain(String alias) { String[] parts = alias.split(SEP, 2); String description = parts[0]; alias = parts[1]; X509KeyManager km = (X509KeyManager) _managers.get(description); return km.getCertificateChain(alias); } public synchronized String[] getClientAliases(String keyType, Principal[] issuers) { if (_preferredKeyManager != null) return _preferredKeyManager.getClientAliases(keyType, issuers); List<String> allAliases = new ArrayList<String>(); Iterator<String> it = _managers.keySet().iterator(); while (it.hasNext()) { String source = it.next(); X509KeyManager km = _managers.get(source); String[] aliases = km.getClientAliases(keyType, issuers); if (aliases != null) { for (int i=0; i<aliases.length; i++) { allAliases.add(source + SEP + aliases[i]); } } } return allAliases.toArray(new String[0]); } public synchronized PrivateKey getPrivateKey(String alias) { String[] parts = alias.split(SEP, 2); String description = parts[0]; alias = parts[1]; X509KeyManager km = _managers.get(description); return km.getPrivateKey(alias); } public synchronized String[] getServerAliases(String keyType, Principal[] issuers) { if (_preferredKeyManager != null) return _preferredKeyManager.getServerAliases(keyType, issuers); List<String> allAliases = new ArrayList<String>(); Iterator<String> it = _managers.keySet().iterator(); while (it.hasNext()) { String source = it.next(); X509KeyManager km = _managers.get(source); String[] aliases = km.getServerAliases(keyType, issuers); if (aliases != null) { for (int i=0; i<aliases.length; i++) { allAliases.add(source + SEP + aliases[i]); } } } return allAliases.toArray(new String[0]); } }