diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/certificateviewer/CertificatePane.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/certificateviewer/CertificatePane.java index 5ac3b86c8..fd066936f 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/certificateviewer/CertificatePane.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/certificateviewer/CertificatePane.java @@ -42,6 +42,9 @@ import net.sourceforge.jnlp.runtime.JNLPRuntime; import net.sourceforge.jnlp.security.CertificateUtils; import net.sourceforge.jnlp.security.KeyStores; +import net.sourceforge.jnlp.security.KeyStores.KeyStoreWrap; +import net.sourceforge.jnlp.security.KeyStores.KeyStoreWindows; +import net.sourceforge.jnlp.security.KeyStores.KeyStoreWithPath; import net.sourceforge.jnlp.security.KeyStores.Level; import net.sourceforge.jnlp.security.SecurityUtil; import net.sourceforge.jnlp.util.RestrictedFileUtils; @@ -111,7 +114,7 @@ public class CertificatePane extends JPanel { }; JTabbedPane tabbedPane; - JTextField certPath = new JTextField(); + JTextField certLocation = new JTextField(); private final JTable userTable; private final JTable systemTable; private JComboBox certificateTypeCombo; @@ -120,6 +123,7 @@ public class CertificatePane extends JPanel { /** JComponents that should be disabled for system store */ private final List disableForSystem; + private final List disableForWindowsStores; private Window parent; private JComponent defaultFocusComponent = null; @@ -128,7 +132,7 @@ public class CertificatePane extends JPanel { * The Current KeyStore. Only one table/tab is visible for interaction to * the user. This KeyStore corresponds to that. */ - private KeyStores.KeyStoreWithPath keyStore = null; + private KeyStoreWrap keyStoreWrap = null; public CertificatePane(Window parent) { super(); @@ -139,6 +143,7 @@ public CertificatePane(Window parent) { systemTable = new JTable(null); systemTable.setAutoCreateRowSorter(true); disableForSystem = new ArrayList<>(); + disableForWindowsStores = new ArrayList<>(); addComponents(); @@ -157,7 +162,7 @@ public CertificatePane(Window parent) { */ private void initializeKeyStore() { try { - keyStore = KeyStores.getKeyStore(currentKeyStoreLevel, currentKeyStoreType); + keyStoreWrap = KeyStores.getWrapContainer(currentKeyStoreLevel, currentKeyStoreType).getWrap(); } catch (Exception e) { LOG.error(IcedTeaWebConstants.DEFAULT_ERROR_MESSAGE, e); } @@ -224,24 +229,24 @@ private void addComponents() { for (int i = 0; i < buttonNames.length; i++) { button = new JButton(buttonNames[i]); maxWidth = Math.max(maxWidth, button.getMinimumSize().width); - } - + } for (int i = 0; i < buttonNames.length; i++) { button = new JButton(buttonNames[i]); button.setMnemonic(buttonMnemonics[i]); button.addActionListener(listeners[i]); - button.setSize(maxWidth, button.getSize().height); + button.setSize(maxWidth, button.getSize().height); // import and remove buttons if (i == 0 || i == 2) { - disableForSystem.add(button); + disableForSystem.add(button); + disableForWindowsStores.add(button); } buttonPanel.add(button); } tablePanel.add(tabbedPane, BorderLayout.CENTER); JPanel buttonPanelWrapper = new JPanel(new BorderLayout()); - certPath.setEditable(false); - buttonPanelWrapper.add(certPath, BorderLayout.CENTER); + certLocation.setEditable(false); + buttonPanelWrapper.add(certLocation, BorderLayout.CENTER); buttonPanelWrapper.add(buttonPanel, BorderLayout.EAST); tablePanel.add(buttonPanelWrapper, BorderLayout.SOUTH); main.add(certificateTypePanel, BorderLayout.NORTH); @@ -277,9 +282,9 @@ private void readKeyStore() { try { //Get all of the X509Certificates and put them into an ArrayList - aliases = keyStore.getKs().aliases(); + aliases = keyStoreWrap.getKs().aliases(); while (aliases.hasMoreElements()) { - Certificate c = keyStore.getKs().getCertificate(aliases.nextElement()); + Certificate c = keyStoreWrap.getKs().getCertificate(aliases.nextElement()); if (c instanceof X509Certificate) { certs.add((X509Certificate) c); } @@ -308,15 +313,40 @@ private void repopulateTables() { initializeKeyStore(); readKeyStore(); try { - File src = new File(keyStore.getPath()); - File resolved = src.getCanonicalFile(); - if (resolved.equals(src)) { - certPath.setText(keyStore.getPath()); - LOG.info(keyStore.getPath()); - } else { - certPath.setText(keyStore.getPath() + " -> " + resolved.getCanonicalPath()); - LOG.info("{} -> {}", keyStore.getPath(), resolved.getCanonicalPath()); - } + + KeyStores.Family keyStoreFamily = keyStoreWrap.getFamily(); + + switch(keyStoreFamily) { + + case JKS: + KeyStoreWithPath keyStorePath = (KeyStoreWithPath)keyStoreWrap; + + File src = new File(keyStorePath.getPath()); + File resolved = src.getCanonicalFile(); + if (resolved.equals(src)) { + certLocation.setText(keyStorePath.getPath()); + LOG.info(keyStorePath.getPath()); + } else { + certLocation.setText(keyStorePath.getPath() + " -> " + resolved.getCanonicalPath()); + LOG.info("{} -> {}", keyStorePath.getPath(), resolved.getCanonicalPath()); + } + + if(currentKeyStoreLevel == Level.USER) { + for (JComponent component : disableForSystem) { + component.setEnabled(true); + } + } + case WINDOWS: + KeyStoreWindows keyStoreWin = (KeyStoreWindows)keyStoreWrap; + + certLocation.setText(keyStoreWin.getStoreType().getDescription()); + + for (JComponent component : disableForWindowsStores) { + component.setEnabled(false); + } + + LOG.info(keyStoreWin.getStoreType().getDescription()); + } } catch (Exception ex) { LOG.error(IcedTeaWebConstants.DEFAULT_ERROR_MESSAGE, ex); } @@ -380,6 +410,7 @@ public void actionPerformed(ActionEvent e) { * or vice versa). Changes the currentKeyStore Enables or disables buttons. */ private class TabChangeListener implements ChangeListener { + @Override public void stateChanged(ChangeEvent e) { JTabbedPane source = (JTabbedPane) e.getSource(); @@ -388,7 +419,8 @@ public void stateChanged(ChangeEvent e) { currentKeyStoreLevel = Level.USER; for (JComponent component : disableForSystem) { component.setEnabled(true); - } + } + break; case 1: currentKeyStoreLevel = Level.SYSTEM; @@ -410,11 +442,11 @@ public void actionPerformed(ActionEvent e) { int returnVal = chooser.showOpenDialog(parent); if (returnVal == JFileChooser.APPROVE_OPTION) { try { - KeyStore ks = keyStore.getKs(); + KeyStore ks = keyStoreWrap.getKs(); if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) { char[] password = getPassword(R("CVImportPasswordMessage")); if (password != null) { - final KeyStore caks = KeyStores.getKeyStore(currentKeyStoreLevel, KeyStores.Type.CA_CERTS).getKs(); + final KeyStore caks = KeyStores.getWrapContainer(currentKeyStoreLevel, KeyStores.Type.CA_CERTS).getWrap().getKs(); final int caksSize = caks.size(); CertificateUtils.addPKCS12ToKeyStore(chooser.getSelectedFile(), ks, password, caks); if (caks.size() > caksSize) { @@ -475,16 +507,16 @@ public void actionPerformed(ActionEvent e) { JFileChooser chooser = new JFileChooser(); int returnVal = chooser.showSaveDialog(parent); if (returnVal == JFileChooser.APPROVE_OPTION) { - String alias = keyStore.getKs().getCertificateAlias(certs + String alias = keyStoreWrap.getKs().getCertificateAlias(certs .get(selectedRow)); if (alias != null) { if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) { char[] password = getPassword(R("CVExportPasswordMessage")); if (password != null) { - CertificateUtils.dumpPKCS12(alias, chooser.getSelectedFile(), keyStore.getKs(), password); + CertificateUtils.dumpPKCS12(alias, chooser.getSelectedFile(), keyStoreWrap.getKs(), password); } } else { - Certificate c = keyStore.getKs().getCertificate(alias); + Certificate c = keyStoreWrap.getKs().getCertificate(alias); PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath()); CertificateUtils.dump(c, ps); } @@ -516,7 +548,7 @@ public void actionPerformed(ActionEvent e) { int selectedRow = table.getSelectedRow(); if (selectedRow != -1) { - String alias = keyStore.getKs().getCertificateAlias(certs.get(selectedRow)); + String alias = keyStoreWrap.getKs().getCertificateAlias(certs.get(selectedRow)); if (alias != null) { int i = JOptionPane.showConfirmDialog(parent, @@ -524,12 +556,12 @@ public void actionPerformed(ActionEvent e) { R("CVRemoveConfirmTitle"), JOptionPane.YES_NO_OPTION); if (i == 0) { - keyStore.getKs().deleteEntry(alias); + keyStoreWrap.getKs().deleteEntry(alias); File keyStoreFile = KeyStores.getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType).getFile(); if (!keyStoreFile.isFile()) { RestrictedFileUtils.createRestrictedFile(keyStoreFile); } - SecurityUtil.storeKeyStore(keyStore.getKs(), keyStoreFile); + SecurityUtil.storeKeyStore(keyStoreWrap.getKs(), keyStoreFile); } } repopulateTables(); diff --git a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertWarningPane.java b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertWarningPane.java index a509fe628..a9d585776 100644 --- a/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertWarningPane.java +++ b/core/src/main/java/net/adoptopenjdk/icedteaweb/client/parts/dialogs/security/CertWarningPane.java @@ -332,7 +332,7 @@ public void actionPerformed(ActionEvent e) { public void saveCert() { try { - KeyStore ks = KeyStores.getKeyStore(Level.USER, Type.CERTS).getKs(); + KeyStore ks = KeyStores.getWrapContainer(Level.USER, Type.CERTS).getWrap().getKs(); X509Certificate c = (X509Certificate) parent.getCertVerifier().getPublisher(null); CertificateUtils.addToKeyStore(c, ks); File keyStoreFile = KeyStores.getKeyStoreLocation(Level.USER, Type.CERTS).getFile(); diff --git a/core/src/main/java/net/sourceforge/jnlp/config/ConfigurationConstants.java b/core/src/main/java/net/sourceforge/jnlp/config/ConfigurationConstants.java index 1b63e1d07..0bb5eeab1 100644 --- a/core/src/main/java/net/sourceforge/jnlp/config/ConfigurationConstants.java +++ b/core/src/main/java/net/sourceforge/jnlp/config/ConfigurationConstants.java @@ -110,6 +110,15 @@ public interface ConfigurationConstants { String KEY_SECURITY_EXPIRED_WARNING = "deployment.security.expired.warning"; String KEY_SECURITY_JSSE_HOSTMISMATCH_WARNING = "deployment.security.jsse.hostmismatch.warning"; + + + /** + * Properties to manage to access Windows key stores + */ + String KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_ROOT = "deployment.security.use.rootca.store.type.windowsRoot"; + + String KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_MY = "deployment.security.use.rootca.store.type.windowsMy"; + /** * Boolean. Only show security prompts to user if true diff --git a/core/src/main/java/net/sourceforge/jnlp/config/Defaults.java b/core/src/main/java/net/sourceforge/jnlp/config/Defaults.java index 9619b8078..3a6365cf1 100644 --- a/core/src/main/java/net/sourceforge/jnlp/config/Defaults.java +++ b/core/src/main/java/net/sourceforge/jnlp/config/Defaults.java @@ -182,6 +182,21 @@ public class Defaults { ValidatorFactory.createFilePathValidator() ), + /* + * Windows certificates key stores + */ + Setting.createDefault( + ConfigurationConstants.KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_ROOT, + String.valueOf(false), + ValidatorFactory.createBooleanValidator() + ), + Setting.createDefault( + ConfigurationConstants.KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_MY, + String.valueOf(false), + ValidatorFactory.createBooleanValidator() + ), + + /* * security access and control */ diff --git a/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPRuntime.java b/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPRuntime.java index 7bffd2c48..9a94eccbe 100644 --- a/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPRuntime.java +++ b/core/src/main/java/net/sourceforge/jnlp/runtime/JNLPRuntime.java @@ -272,7 +272,7 @@ public static void initialize() throws IllegalStateException { try { SSLSocketFactory sslSocketFactory; SSLContext context = SSLContext.getInstance("SSL"); - KeyStore ks = KeyStores.getKeyStore(KeyStores.Level.USER, KeyStores.Type.CLIENT_CERTS).getKs(); + KeyStore ks = KeyStores.getWrapContainer(KeyStores.Level.USER, KeyStores.Type.CLIENT_CERTS).getWrap().getKs(); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); SecurityUtil.initKeyManagerFactory(kmf, ks); TrustManager[] trust = new TrustManager[] { getSSLSocketTrustManager() }; diff --git a/core/src/main/java/net/sourceforge/jnlp/security/CertificateUtils.java b/core/src/main/java/net/sourceforge/jnlp/security/CertificateUtils.java index 4cca1e3f1..19b3bb397 100644 --- a/core/src/main/java/net/sourceforge/jnlp/security/CertificateUtils.java +++ b/core/src/main/java/net/sourceforge/jnlp/security/CertificateUtils.java @@ -126,7 +126,7 @@ public static void addPKCS12ToKeyStore(File file, KeyStore ks, char[] password, BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(bis, password); - KeyStore systemCa = KeyStores.getKeyStore(KeyStores.Level.SYSTEM, KeyStores.Type.CA_CERTS).getKs(); + KeyStore systemCa = KeyStores.getWrapContainer(KeyStores.Level.SYSTEM, KeyStores.Type.CA_CERTS).getWrap().getKs(); Enumeration aliasList = keyStore.aliases(); @@ -182,7 +182,7 @@ public static boolean inKeyStores(X509Certificate c, List keyStores) { // Verify against this entry final String alias = aliases.nextElement(); if (c.equals(keyStore.getCertificate(alias))) { - LOG.debug("{} found in cacerts ({})", c.getSubjectX500Principal().getName(), KeyStores.getPathToKeystore(keyStore)); + LOG.debug("{} found in cacerts ({})", c.getSubjectX500Principal().getName(), KeyStores.getLocationToKeystore(keyStore)); return true; } // else continue } diff --git a/core/src/main/java/net/sourceforge/jnlp/security/KeyStores.java b/core/src/main/java/net/sourceforge/jnlp/security/KeyStores.java index 50f115ba4..fe86e2ca4 100644 --- a/core/src/main/java/net/sourceforge/jnlp/security/KeyStores.java +++ b/core/src/main/java/net/sourceforge/jnlp/security/KeyStores.java @@ -33,13 +33,6 @@ */ package net.sourceforge.jnlp.security; -import net.adoptopenjdk.icedteaweb.i18n.Translator; -import net.adoptopenjdk.icedteaweb.logging.Logger; -import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; -import net.sourceforge.jnlp.config.InfrastructureFileDescriptor; -import net.sourceforge.jnlp.config.PathsAndFiles; -import net.sourceforge.jnlp.util.RestrictedFileUtils; - import java.io.File; import java.io.IOException; import java.security.AllPermission; @@ -53,6 +46,15 @@ import java.util.Map; import java.util.StringTokenizer; +import net.adoptopenjdk.icedteaweb.i18n.Translator; +import net.adoptopenjdk.icedteaweb.logging.Logger; +import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; +import net.sourceforge.jnlp.config.InfrastructureFileDescriptor; +import net.sourceforge.jnlp.config.PathsAndFiles; +import net.sourceforge.jnlp.security.windows.WindowsKeyStoresManager; +import net.sourceforge.jnlp.security.windows.WindowsKeyStoresManager.WindowsKeyStoreType; +import net.sourceforge.jnlp.util.RestrictedFileUtils; + /** * The {@code KeyStores} class allows easily accessing the various KeyStores * used. @@ -61,7 +63,24 @@ public final class KeyStores { private static final Logger LOG = LoggerFactory.getLogger(KeyStores.class); - public static class KeyStoreWithPath { + public static class KeyStoreWrapContainer{ + private final T wrap; + + public KeyStoreWrapContainer(T t){ + this.wrap = t; + } + + public T getWrap() { + return wrap; + } + } + + public static interface KeyStoreWrap{ + public KeyStore getKs(); + public Family getFamily(); + } + + public static class KeyStoreWithPath implements KeyStoreWrap { private final KeyStore ks; private final String path; @@ -78,6 +97,40 @@ public KeyStore getKs() { public String getPath() { return path; } + + @Override + public Family getFamily() { + return Family.JKS; + } + } + + public static class KeyStoreWindows implements KeyStoreWrap { + + private final KeyStore ks; + private final WindowsKeyStoreType storeType; + + public KeyStoreWindows(KeyStore ks, WindowsKeyStoreType storeType) { + this.ks = ks; + this.storeType = storeType; + } + + public KeyStore getKs() { + return ks; + } + + public WindowsKeyStoreType getStoreType() { + return storeType; + } + + @Override + public Family getFamily() { + return Family.WINDOWS; + } + } + + public enum Family { + JKS, + WINDOWS } /* this gets turned into user-readable strings, see toUserReadableString */ @@ -94,39 +147,62 @@ public enum Type { CLIENT_CERTS, } - public static final Map keystoresPaths = new HashMap<>(); + public static final Map keystoresLocations = new HashMap<>(); private static final String KEYSTORE_TYPE = "JKS"; /** - * Returns a KeyStore corresponding to the appropriate level level (user or + * Returns a KeyStoreWrapContainer corresponding to the appropriate level level (user or * system) and type. * * @param level whether the KeyStore desired is a user-level or system-level KeyStore * @param type the type of KeyStore desired * @return a KeyStore containing certificates from the appropriate */ - public static KeyStoreWithPath getKeyStore(Level level, Type type) { + public static KeyStoreWrapContainer getWrapContainer(Level level, Type type) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new AllPermission()); } - final String location = getKeyStoreLocation(level, type).getFullPath(); + //The existence and accessibility of a Windows Key Store is checked if required by configuration + //Windows-ROOT --> "deployment.security.use.rootca.store.type.windowsRoot=true" + //Windows-My --> "deployment.security.use.rootca.store.type.windowsMy=true" + + final WindowsKeyStoresManager windowsStore = WindowsKeyStoresManager.getInfo(type); + final String location; + + KeyStoreWrapContainer keyStoreWrapContainer = null; + + if(windowsStore.isAccessible()) + location = windowsStore.getType().getStoreType(); + else + location = getKeyStoreLocation(level, type).getFullPath(); + KeyStore ks = null; try { - ks = createKeyStoreFromFile(new File(location), level == Level.USER); + if(windowsStore.isAccessible()) { + ks = createKeyStoreFromWindows(location); + keyStoreWrapContainer = new KeyStoreWrapContainer(new KeyStoreWindows(ks, windowsStore.getType())); + + } + else { + ks = createKeyStoreFromFile(new File(location), level == Level.USER); + keyStoreWrapContainer = new KeyStoreWrapContainer(new KeyStoreWithPath(ks, location)); + + } //hashcode is used instead of instance so when no references are left //to keystore, then this will not be blocker for garbage collection - keystoresPaths.put(ks.hashCode(), location); + keystoresLocations.put(ks.hashCode(), location); } catch (Exception e) { LOG.error("failed to get keystore " + level + " " + type + " -> " + location, e); } - return new KeyStoreWithPath(ks, location); + + return keyStoreWrapContainer; } - public static String getPathToKeystore(KeyStore k) { - final String s = keystoresPaths.get(k.hashCode()); + public static String getLocationToKeystore(KeyStore k) { + final String s = keystoresLocations.get(k.hashCode()); if (s == null) { return "unknown keystore location"; } @@ -141,24 +217,26 @@ public static String getPathToKeystore(KeyStore k) { */ public static List getCertKeyStores() { final List result = new ArrayList<>(10); - /* System-level JSSE certificates */ + KeyStore ks; - ks = getKeyStore(Level.SYSTEM, Type.JSSE_CERTS).getKs(); + + /* System-level JSSE certificates */ + ks = getWrapContainer(Level.SYSTEM, Type.JSSE_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* System-level certificates */ - ks = getKeyStore(Level.SYSTEM, Type.CERTS).getKs(); + ks = getWrapContainer(Level.SYSTEM, Type.CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* User-level JSSE certificates */ - ks = getKeyStore(Level.USER, Type.JSSE_CERTS).getKs(); + ks = getWrapContainer(Level.USER, Type.JSSE_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* User-level certificates */ - ks = getKeyStore(Level.USER, Type.CERTS).getKs(); + ks = getWrapContainer(Level.USER, Type.CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } @@ -173,24 +251,25 @@ public static List getCertKeyStores() { */ public static List getCAKeyStores() { List result = new ArrayList<>(10); - /* System-level JSSE CA certificates */ + KeyStore ks; - ks = getKeyStore(Level.SYSTEM, Type.JSSE_CA_CERTS).getKs(); + /* System-level JSSE CA certificates */ + ks = getWrapContainer(Level.SYSTEM, Type.JSSE_CA_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* System-level CA certificates */ - ks = getKeyStore(Level.SYSTEM, Type.CA_CERTS).getKs(); + ks = getWrapContainer(Level.SYSTEM, Type.CA_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* User-level JSSE CA certificates */ - ks = getKeyStore(Level.USER, Type.JSSE_CA_CERTS).getKs(); + ks = getWrapContainer(Level.USER, Type.JSSE_CA_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } /* User-level CA certificates */ - ks = getKeyStore(Level.USER, Type.CA_CERTS).getKs(); + ks = getWrapContainer(Level.USER, Type.CA_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } @@ -208,12 +287,12 @@ public static List getClientKeyStores() { List result = new ArrayList<>(); KeyStore ks; - ks = getKeyStore(Level.SYSTEM, Type.CLIENT_CERTS).getKs(); + ks = getWrapContainer(Level.SYSTEM, Type.CLIENT_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } - ks = getKeyStore(Level.USER, Type.CLIENT_CERTS).getKs(); + ks = getWrapContainer(Level.USER, Type.CLIENT_CERTS).getWrap().getKs(); if (ks != null) { result.add(ks); } @@ -342,4 +421,18 @@ private static KeyStore createKeyStoreFromFile(File file, boolean createIfNotFou } return ks; } + + + private static KeyStore createKeyStoreFromWindows(String windowsStoreType) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + final KeyStore ks = KeyStore.getInstance(windowsStoreType); + if (ks!=null) { + LOG.debug("Keystore windows {} exists.", windowsStoreType); + SecurityUtil.loadKeyStore(ks, null); + } else { + LOG.debug("Keystore windows {} does not exists.", windowsStoreType); + SecurityUtil.loadKeyStore(ks, null); + } + return ks; + } + } diff --git a/core/src/main/java/net/sourceforge/jnlp/security/SecurityUtil.java b/core/src/main/java/net/sourceforge/jnlp/security/SecurityUtil.java index 257856d74..2f6167eed 100644 --- a/core/src/main/java/net/sourceforge/jnlp/security/SecurityUtil.java +++ b/core/src/main/java/net/sourceforge/jnlp/security/SecurityUtil.java @@ -34,14 +34,10 @@ package net.sourceforge.jnlp.security; -import net.adoptopenjdk.icedteaweb.IcedTeaWebConstants; -import net.adoptopenjdk.icedteaweb.JavaSystemProperties; -import net.adoptopenjdk.icedteaweb.logging.Logger; -import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; -import net.sourceforge.jnlp.security.KeyStores.Level; -import net.sourceforge.jnlp.security.KeyStores.Type; +import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE; +import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE_PASSWORD; +import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE_TYPE; -import javax.net.ssl.KeyManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -54,9 +50,15 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; -import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE; -import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE_PASSWORD; -import static net.adoptopenjdk.icedteaweb.JavaSystemPropertiesConstants.SSL_TRUST_STORE_TYPE; +import javax.net.ssl.KeyManagerFactory; + +import net.adoptopenjdk.icedteaweb.IcedTeaWebConstants; +import net.adoptopenjdk.icedteaweb.JavaSystemProperties; +import net.adoptopenjdk.icedteaweb.logging.Logger; +import net.adoptopenjdk.icedteaweb.logging.LoggerFactory; +import net.sourceforge.jnlp.security.KeyStores.Level; +import net.sourceforge.jnlp.security.KeyStores.Type; +import net.sourceforge.jnlp.security.windows.WindowsKeyStoresManager; public class SecurityUtil { @@ -353,8 +355,14 @@ Key operateKeystore(char[] pass) throws KeyStoreException, NoSuchAlgorithmExcept } public static void loadKeyStore(KeyStore ks, File f) throws IOException, NoSuchAlgorithmException, CertificateException { - try { - LOG.debug("Loading Keystore {}", f != null ? f.toString() : "Unknown"); + try { + if(WindowsKeyStoresManager.isWindowsStore(ks)) { + LOG.debug("Loading Keystore {}", ks.getType()); + } + else { + LOG.debug("Loading Keystore {}", f != null ? f.toString() : "Unknown"); + } + KeystorePasswordAttempter.INSTANCE.unlockKeystore( new KeystorePasswordAttempter.KeystoreOperation(ks, f) { diff --git a/core/src/main/java/net/sourceforge/jnlp/security/windows/WindowsKeyStoresManager.java b/core/src/main/java/net/sourceforge/jnlp/security/windows/WindowsKeyStoresManager.java new file mode 100644 index 000000000..3453fd188 --- /dev/null +++ b/core/src/main/java/net/sourceforge/jnlp/security/windows/WindowsKeyStoresManager.java @@ -0,0 +1,127 @@ +package net.sourceforge.jnlp.security.windows; + +import java.security.KeyStore; +import java.util.ArrayList; + +import net.sourceforge.jnlp.config.ConfigurationConstants; +import net.sourceforge.jnlp.config.DeploymentConfiguration; +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.security.KeyStores; + +public class WindowsKeyStoresManager { + + private boolean accessible; + private WindowsKeyStoreType type; + + private static final ArrayList ADMITTED_STORE_TYPES; + private static final String KS_PROVIDER_NAME = "SunMSCAPI"; + + private static final String OS_NAME = System.getProperty("os.name") == null ? "" : System.getProperty("os.name"); + + private static final WindowsKeyStoresManager INSTANCE; + private static final WindowsKeyStoresManager EMPTY_INSTANCE = new WindowsKeyStoresManager(); + + static { + //Admitted Stores - Only Root CA admitted + ADMITTED_STORE_TYPES = new ArrayList(); + ADMITTED_STORE_TYPES.add(KeyStores.Type.CA_CERTS); + + boolean isWindowsMachine = OS_NAME.indexOf("Windows") >= 0; + if(isWindowsMachine) { + //Load configurations. Only for Windows OS machines. + WindowsKeyStoresManager windowsStoresManager = new WindowsKeyStoresManager(); + + DeploymentConfiguration config = JNLPRuntime.getConfiguration(); + + boolean windowsRoot = Boolean.parseBoolean(config.getProperty(ConfigurationConstants.KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_ROOT)); + boolean windowsMy = Boolean.parseBoolean(config.getProperty(ConfigurationConstants.KEY_SECURITY_USE_ROOTCA_STORE_TYPE_WINDOWS_MY)); + + windowsStoresManager.accessible = windowsRoot || windowsMy; + + if(windowsRoot && windowsMy) { + windowsStoresManager.type = WindowsKeyStoreType.WINDOWS_ROOT; + } + else if(!windowsRoot && windowsMy) { + windowsStoresManager.type = WindowsKeyStoreType.WINDOWS_MY; + } + else if(windowsRoot && !windowsMy) { + windowsStoresManager.type = WindowsKeyStoreType.WINDOWS_ROOT; + } + else { + windowsStoresManager.type = null; + } + + INSTANCE = windowsStoresManager; + } + else { + INSTANCE = EMPTY_INSTANCE; + } + + + } + + private WindowsKeyStoresManager () { + + } + + public enum WindowsKeyStoreType { + WINDOWS_ROOT("Windows-ROOT","Windows Trusted Root Certification Authorities"), + WINDOWS_MY("Windows-MY","Windows Personal"); + + private String type; + private String description; + + WindowsKeyStoreType(String storeType, String storeDescription){ + this.type = storeType; + this.description = storeDescription; + } + + public String getStoreType() { + return type; + } + + + public String getDescription() { + return description; + } + + public static WindowsKeyStoreType getValue(String storeType) { + for (WindowsKeyStoreType st : WindowsKeyStoreType.values()) { + if (st.getStoreType().equals(storeType)) { + return st; + } + } + + return null; + } + } + + public boolean isAccessible() { + return accessible; + } + + public WindowsKeyStoreType getType() { + return type; + } + + public static WindowsKeyStoresManager getInfo(KeyStores.Type storeType) { + + boolean admitted = ADMITTED_STORE_TYPES.contains(storeType); + + if(!admitted) + return EMPTY_INSTANCE; + else + return INSTANCE; + + + } + + public static boolean isWindowsStore(KeyStore ks) { + + if(ks!= null && ks.getProvider() != null) + return KS_PROVIDER_NAME.equals(ks.getProvider().getName()); + else + return false; + + } +} \ No newline at end of file diff --git a/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java b/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java index 2f4475fda..23605e6a0 100644 --- a/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java +++ b/core/src/test/java/net/sourceforge/jnlp/security/KeyStoresTest.java @@ -33,13 +33,16 @@ */ package net.sourceforge.jnlp.security; -import net.sourceforge.jnlp.config.InfrastructureFileDescriptor; -import net.sourceforge.jnlp.config.PathsAndFiles; +import java.security.Permission; + import org.junit.AfterClass; import org.junit.Assert; import org.junit.Test; -import java.security.Permission; +import net.sourceforge.jnlp.config.InfrastructureFileDescriptor; +import net.sourceforge.jnlp.config.PathsAndFiles; +import net.sourceforge.jnlp.security.KeyStores.KeyStoreWrap; +import net.sourceforge.jnlp.security.windows.WindowsKeyStoresManager; public class KeyStoresTest { @@ -124,6 +127,25 @@ public void getKeyStoreSystemLocationTestSM() { s = KeyStores.getKeyStoreLocation(KeyStores.Level.SYSTEM, KeyStores.Type.JSSE_CERTS); Assert.assertEquals(s.getFile(), PathsAndFiles.SYS_JSSECERT.getFile()); Assert.assertEquals(true, dm.called); - } + } + + @Test + public void getKeyStoreWindowsRootTestSM() { + DummySM dm = new DummySM(); + System.setSecurityManager(dm); + + KeyStoreWrap keyStoreWrap; + + final WindowsKeyStoresManager windowsStore = WindowsKeyStoresManager.getInfo(KeyStores.Type.CA_CERTS); + + if(windowsStore.isAccessible()) { + + keyStoreWrap = KeyStores.getWrapContainer(KeyStores.Level.SYSTEM, KeyStores.Type.CA_CERTS).getWrap(); + Assert.assertEquals(keyStoreWrap.getFamily(), KeyStores.Family.WINDOWS); + + keyStoreWrap = KeyStores.getWrapContainer(KeyStores.Level.USER, KeyStores.Type.CA_CERTS).getWrap(); + Assert.assertEquals(keyStoreWrap.getFamily(), KeyStores.Family.WINDOWS); + } + } }