changeset 34:9dd09feb371b

integrate multiple keystore support into certificate viewer 2010-11-04 Omair Majid <omajid@redhat.com> * netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java: Add KEY_USER_TRUSTED_CA_CERTS, KEY_USER_TRUSTED_JSSE_CA_CERTS, KEY_USER_TRUSTED_CERTS, KEY_USER_TRUSTED_JSSE_CERTS, KEY_USER_TRUSTED_CLIENT_CERTS, KEY_SYSTEM_TRUSTED_CA_CERTS, KEY_SYSTEM_TRUSTED_JSSE_CA_CERTS, KEY_SYSTEM_TRUSTED_CERTS, KEY_SYSTEM_TRUSTED_JSSE_CERTS, KEY_SYSTEM_TRUSTED_CLIENT_CERTS (loadDefaultProperties): Use the defined constants. * netx/net/sourceforge/jnlp/security/KeyStores.java: New class. (getPassword): New method. Return the default password used for KeyStores. (getKeyStore(Level,Type)): New method. Returns the appropriate KeyStore. (getKeyStore(Level,Type,String)): Likewise. (getCertKeyStores): New method. Return all the trusted certificate KeyStores. (getCAKeyStores): New method. Return all the trusted CA certificate KeyStores. (getKeyStoreLocation): New method. Return the location of the appropriate KeyStore. (toTranslatableString): New method. Return a string that can be used to create a human-readable name for the KeyStore. (toDisplayableString): New method. Return a human-readable name for the KeyStore. (createKeyStoreFromFile): New method. Creates a new KeyStore object, initializing it from the given file if possible. * netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java (CertificatePane): Create two JTables. Populate the tables when done creating the user interface. (initializeKeyStore): Use the correct keystore. (addComponents): Do not read KeyStore. Create more interface elements to show the new possible KeyStores. Mark some buttons to be disabled when needed. (repopulateTable): Renamed to... (repopulateTables): New method. Read KeyStore and use the contents to create the user and system tables. (CertificateType): New class. (CertificateTypeListener): New class. Listens to JComboBox change events. (TabChangeListener): New class. Listens to new tab selections. (ImportButtonListener): Import certificates to the appropriate KeyStore. (ExportButtonListener): Find the certificate from the right table. (RemoveButtonListener): Find the certificate from the right table and right the KeyStore. (DetailsButtonListener): Find the certificate from the right table. * netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java (showCertficaiteViewer): Initialize the JNLPRuntime so the configuration gets loaded. * netx/net/sourceforge/jnlp/tools/KeyTool.java (addToKeyStore(File,KeyStore)): New method. Adds certificate from the file to the KeyStore. (addToKeyStore(X509Certificate,KeyStore)): New method. Adds a certificate to a KeyStore.
author Omair Majid <omajid@redhat.com>
date Mon, 08 Nov 2010 16:36:17 -0500
parents 8e66d9386273
children f089abbcf019
files ChangeLog netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java netx/net/sourceforge/jnlp/security/KeyStores.java netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java netx/net/sourceforge/jnlp/tools/KeyTool.java
diffstat 6 files changed, 637 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Nov 04 16:44:27 2010 -0700
+++ b/ChangeLog	Mon Nov 08 16:36:17 2010 -0500
@@ -1,3 +1,59 @@
+2010-11-04  Omair Majid  <omajid@redhat.com>
+
+	* netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java:
+	Add KEY_USER_TRUSTED_CA_CERTS, KEY_USER_TRUSTED_JSSE_CA_CERTS,
+	KEY_USER_TRUSTED_CERTS, KEY_USER_TRUSTED_JSSE_CERTS,
+	KEY_USER_TRUSTED_CLIENT_CERTS, KEY_SYSTEM_TRUSTED_CA_CERTS,
+	KEY_SYSTEM_TRUSTED_JSSE_CA_CERTS, KEY_SYSTEM_TRUSTED_CERTS,
+	KEY_SYSTEM_TRUSTED_JSSE_CERTS, KEY_SYSTEM_TRUSTED_CLIENT_CERTS
+	(loadDefaultProperties): Use the defined constants.
+	* netx/net/sourceforge/jnlp/security/KeyStores.java: New class.
+	(getPassword): New method. Return the default password used for
+	KeyStores.
+	(getKeyStore(Level,Type)): New method. Returns the appropriate
+	KeyStore.
+	(getKeyStore(Level,Type,String)): Likewise.
+	(getCertKeyStores): New method. Return all the trusted certificate
+	KeyStores.
+	(getCAKeyStores): New method. Return all the trusted CA certificate
+	KeyStores.
+	(getKeyStoreLocation): New method. Return the location of the
+	appropriate KeyStore.
+	(toTranslatableString): New method. Return a string that can be
+	used to create a human-readable name for the KeyStore.
+	(toDisplayableString): New method. Return a human-readable name
+	for the KeyStore.
+	(createKeyStoreFromFile): New method. Creates a new KeyStore object,
+	initializing it from the given file if possible.
+	* netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java
+	(CertificatePane): Create two JTables. Populate the tables when
+	done creating the user interface.
+	(initializeKeyStore): Use the correct keystore.
+	(addComponents): Do not read KeyStore. Create more interface
+	elements to show the new possible KeyStores. Mark some buttons to
+	be disabled when needed.
+	(repopulateTable): Renamed to...
+	(repopulateTables): New method. Read KeyStore and use the contents
+	to create the user and system tables.
+	(CertificateType): New class.
+	(CertificateTypeListener): New class. Listens to JComboBox change
+	events.
+	(TabChangeListener): New class. Listens to new tab selections.
+	(ImportButtonListener): Import certificates to the appropriate
+	KeyStore.
+	(ExportButtonListener): Find the certificate from the right table.
+	(RemoveButtonListener): Find the certificate from the right table
+	and right the KeyStore.
+	(DetailsButtonListener): Find the certificate from the right table.
+	* netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java
+	(showCertficaiteViewer): Initialize the JNLPRuntime so the
+	configuration gets loaded.
+	* netx/net/sourceforge/jnlp/tools/KeyTool.java
+	(addToKeyStore(File,KeyStore)): New method. Adds certificate from
+	the file to the KeyStore.
+	(addToKeyStore(X509Certificate,KeyStore)): New method. Adds a
+	certificate to a KeyStore.
+
 2010-11-04  Deepak Bhole <dbhole@redhat.com>
 
 	* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java (update):
--- a/netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java	Thu Nov 04 16:44:27 2010 -0700
+++ b/netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java	Mon Nov 08 16:36:17 2010 -0500
@@ -142,6 +142,18 @@
      */
     public static final String KEY_USER_NETX_RUNNING_FILE = "deployment.user.runningfile";
 
+    public static final String KEY_USER_TRUSTED_CA_CERTS = "deployment.user.security.trusted.cacerts";
+    public static final String KEY_USER_TRUSTED_JSSE_CA_CERTS = "deployment.user.security.trusted.jssecacerts";
+    public static final String KEY_USER_TRUSTED_CERTS = "deployment.user.security.trusted.certs";
+    public static final String KEY_USER_TRUSTED_JSSE_CERTS = "deployment.user.security.trusted.jssecerts";
+    public static final String KEY_USER_TRUSTED_CLIENT_CERTS = "deployment.user.security.trusted.clientauthcerts";
+
+    public static final String KEY_SYSTEM_TRUSTED_CA_CERTS = "deployment.system.security.cacerts";
+    public static final String KEY_SYSTEM_TRUSTED_JSSE_CA_CERTS = "deployment.system.security.jssecacerts";
+    public static final String KEY_SYSTEM_TRUSTED_CERTS = "deployment.system.security.trusted.certs";
+    public static final String KEY_SYSTEM_TRUSTED_JSSE_CERTS = "deployment.system.security.trusted.jssecerts";
+    public static final String KEY_SYSTEM_TRUSTED_CLIENT_CERTS = "deployment.system.security.trusted.clientautcerts";
+
     public enum ConfigType {
         System, User
     }
@@ -315,17 +327,17 @@
             { KEY_USER_NETX_RUNNING_FILE, LOCKS_DIR + File.separator + "netx_running" },
             /* certificates and policy files */
             { "deployment.user.security.policy", "file://" + USER_SECURITY + File.separator + "java.policy" },
-            { "deployment.user.security.trusted.cacerts", USER_SECURITY + File.separator + "trusted.cacerts" },
-            { "deployment.user.security.trusted.jssecacerts", USER_SECURITY + File.separator + "trusted.jssecacerts" },
-            { "deployment.user.security.trusted.certs", USER_SECURITY + File.separator + "trusted.certs" },
-            { "deployment.user.security.trusted.jssecerts", USER_SECURITY + File.separator + "trusted.jssecerts"},
-            { "deployment.user.security.trusted.clientauthcerts", USER_SECURITY + File.separator + "trusted.clientcerts" },
+            { KEY_USER_TRUSTED_CA_CERTS, USER_SECURITY + File.separator + "trusted.cacerts" },
+            { KEY_USER_TRUSTED_JSSE_CA_CERTS, USER_SECURITY + File.separator + "trusted.jssecacerts" },
+            { KEY_USER_TRUSTED_CERTS, USER_SECURITY + File.separator + "trusted.certs" },
+            { KEY_USER_TRUSTED_JSSE_CERTS, USER_SECURITY + File.separator + "trusted.jssecerts"},
+            { KEY_USER_TRUSTED_CLIENT_CERTS, USER_SECURITY + File.separator + "trusted.clientcerts" },
             { "deployment.system.security.policy", null },
-            { "deployment.system.security.cacerts", SYSTEM_SECURITY + File.separator + "cacerts" },
-            { "deployment.system.security.jssecacerts", SYSTEM_SECURITY + File.separator + "jssecacerts" },
-            { "deployment.system.security.trusted.certs", SYSTEM_SECURITY + File.separator + "trusted.certs" },
-            { "deployment.system.security.trusted.jssecerts", SYSTEM_SECURITY + File.separator + "trusted.jssecerts" },
-            { "deployment.system.security.trusted.clientautcerts", SYSTEM_SECURITY + File.separator + "trusted.clientcerts" },
+            { KEY_SYSTEM_TRUSTED_CA_CERTS , SYSTEM_SECURITY + File.separator + "cacerts" },
+            { KEY_SYSTEM_TRUSTED_JSSE_CA_CERTS, SYSTEM_SECURITY + File.separator + "jssecacerts" },
+            { KEY_SYSTEM_TRUSTED_CERTS, SYSTEM_SECURITY + File.separator + "trusted.certs" },
+            { KEY_SYSTEM_TRUSTED_JSSE_CERTS, SYSTEM_SECURITY + File.separator + "trusted.jssecerts" },
+            { KEY_SYSTEM_TRUSTED_CLIENT_CERTS, SYSTEM_SECURITY + File.separator + "trusted.clientcerts" },
             /* security access and control */
             { "deployment.security.askgrantdialog.show", String.valueOf(true) },
             { "deployment.security.askgrantdialog.notinca", String.valueOf(true) },
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/security/KeyStores.java	Mon Nov 08 16:36:17 2010 -0500
@@ -0,0 +1,337 @@
+/* KeyStores.java
+   Copyright (C) 2010 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 2.
+
+IcedTea is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+*/
+
+package net.sourceforge.jnlp.security;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import net.sourceforge.jnlp.runtime.DeploymentConfiguration;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.runtime.Translator;
+
+/**
+ * The <code>KeyStores</code> class allows easily accessing the various KeyStores
+ * used.
+ */
+public final class KeyStores {
+
+    /* this gets turned into user-readable strings, see toUserReadableString */
+
+    public enum Level {
+        USER,
+        SYSTEM,
+    }
+
+    public enum Type {
+        CERTS,
+        JSSE_CERTS,
+        CA_CERTS,
+        JSSE_CA_CERTS,
+        CLIENT_CERTS,
+    }
+
+    private static final String KEYSTORE_TYPE = "JKS";
+    /** the default password used to protect the KeyStores */
+    private static final String DEFAULT_PASSWORD = "changeit";
+
+    public static final char[] getPassword() {
+        return DEFAULT_PASSWORD.toCharArray();
+    }
+
+    /**
+     * Returns a KeyStore 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 final KeyStore getKeyStore(Level level, Type type) {
+        boolean create = false;
+        if (level == Level.USER) {
+            create = true;
+        } else {
+            create = false;
+        }
+        return getKeyStore(level, type, create);
+    }
+
+    /**
+     * Returns a KeyStore 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 final KeyStore getKeyStore(Level level, Type type, boolean create) {
+        String location = getKeyStoreLocation(level, type);
+        KeyStore ks = null;
+        try {
+            ks = createKeyStoreFromFile(new File(location), create, DEFAULT_PASSWORD);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return ks;
+    }
+
+    /**
+     * Returns an array of KeyStore that contain certificates that are trusted.
+     * The KeyStores contain certificates from different sources.
+     *
+     * @return an array of KeyStore containing trusted Certificates
+     */
+    public static final KeyStore[] getCertKeyStores() {
+        List<KeyStore> result = new ArrayList<KeyStore>(10);
+        KeyStore ks = null;
+
+        /* System-level JSSE certificates */
+        ks = getKeyStore(Level.SYSTEM, Type.JSSE_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* System-level certificates */
+        ks = getKeyStore(Level.SYSTEM, Type.CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* User-level JSSE certificates */
+        ks = getKeyStore(Level.USER, Type.JSSE_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* User-level certificates */
+        ks = getKeyStore(Level.USER, Type.CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+
+        return result.toArray(new KeyStore[result.size()]);
+    }
+
+    /**
+     * Returns an array of KeyStore that contain trusted CA certificates.
+     *
+     * @return an array of KeyStore containing trusted CA certificates
+     */
+    public static final KeyStore[] getCAKeyStores() {
+        List<KeyStore> result = new ArrayList<KeyStore>(10);
+        KeyStore ks = null;
+
+        /* System-level JSSE CA certificates */
+        ks = getKeyStore(Level.SYSTEM, Type.JSSE_CA_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* System-level CA certificates */
+        ks = getKeyStore(Level.SYSTEM, Type.CA_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* User-level JSSE CA certificates */
+        ks = getKeyStore(Level.USER, Type.JSSE_CA_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+        /* User-level CA certificates */
+        ks = getKeyStore(Level.USER, Type.CA_CERTS);
+        if (ks != null) {
+            result.add(ks);
+        }
+
+        return result.toArray(new KeyStore[result.size()]);
+    }
+
+    /**
+     * Returns the location of a KeyStore corresponding to the given level and type.
+     * @param level
+     * @param type
+     * @return
+     */
+    public static final String getKeyStoreLocation(Level level, Type type) {
+        String configKey = null;
+        switch (level) {
+            case SYSTEM:
+                switch (type) {
+                    case JSSE_CA_CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_JSSE_CA_CERTS;
+                        break;
+                    case CA_CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_CA_CERTS;
+                        break;
+                    case JSSE_CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_JSSE_CERTS;
+                        break;
+                    case CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_CERTS;
+                        break;
+                    case CLIENT_CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_CLIENT_CERTS;
+                        break;
+                }
+                break;
+            case USER:
+                switch (type) {
+                    case JSSE_CA_CERTS:
+                        configKey = DeploymentConfiguration.KEY_USER_TRUSTED_JSSE_CA_CERTS;
+                        break;
+                    case CA_CERTS:
+                        configKey = DeploymentConfiguration.KEY_USER_TRUSTED_CA_CERTS;
+                        break;
+                    case JSSE_CERTS:
+                        configKey = DeploymentConfiguration.KEY_USER_TRUSTED_JSSE_CERTS;
+                        break;
+                    case CERTS:
+                        configKey = DeploymentConfiguration.KEY_USER_TRUSTED_CERTS;
+                        break;
+                    case CLIENT_CERTS:
+                        configKey = DeploymentConfiguration.KEY_SYSTEM_TRUSTED_CLIENT_CERTS;
+                        break;
+                }
+                break;
+        }
+
+        if (configKey == null) {
+            throw new RuntimeException("Unspported");
+        }
+
+        return JNLPRuntime.getConfiguration().getProperty(configKey);
+    }
+
+    /**
+     * Returns a String that can be used as a translation key to create a
+     * user-visible representation of this KeyStore. Creates a string by
+     * concatenating a level and type, converting everything to Title Case and
+     * removing the _'s. (USER,CA_CERTS) becomes UserCaCerts.
+     *
+     * @param level
+     * @param type
+     * @return
+     */
+    public static final String toTranslatableString(Level level, Type type) {
+        StringBuilder response = new StringBuilder();
+
+        if (level != null) {
+            String levelString = level.toString();
+            response.append(levelString.substring(0, 1).toUpperCase());
+            response.append(levelString.substring(1).toLowerCase());
+        }
+
+        if (type != null) {
+            String typeString = type.toString();
+            StringTokenizer tokenizer = new StringTokenizer(typeString, "_");
+            while (tokenizer.hasMoreTokens()) {
+                String token = tokenizer.nextToken();
+                response.append(token.substring(0, 1).toUpperCase());
+                response.append(token.substring(1).toLowerCase());
+            }
+        }
+
+        return response.toString();
+    }
+
+    /**
+     * Returns a human readable name for this KeyStore
+     *
+     * @param level the level of the KeyStore
+     * @param type the type of KeyStore
+     * @return a localized name for this KeyStore
+     */
+    public static String toDisplayableString(Level level, Type type) {
+        return Translator.R(toTranslatableString(level, type));
+    }
+
+    /**
+     * Reads the file (using the password) and uses it to create a new
+     * {@link KeyStore}. If the file does not exist and should not be created,
+     * it returns an empty but initialized KeyStore
+     *
+     * @param file the file to load information from
+     * @param password the password to unlock the KeyStore file.
+     * @return a KeyStore containing data from the file
+     */
+    private static final KeyStore createKeyStoreFromFile(File file, boolean createIfNotFound,
+            String password) throws IOException, KeyStoreException, NoSuchAlgorithmException,
+            CertificateException {
+        FileInputStream fis = null;
+        KeyStore ks = null;
+
+        try {
+            if (createIfNotFound && !file.exists()) {
+                File parent = file.getParentFile();
+                if (!parent.isDirectory() && !parent.mkdirs()) {
+                    throw new IOException("unable to create " + parent);
+                }
+                ks = KeyStore.getInstance(KEYSTORE_TYPE);
+                ks.load(null, password.toCharArray());
+                FileOutputStream fos = new FileOutputStream(file);
+                ks.store(fos, password.toCharArray());
+                fos.close();
+            }
+
+            // TODO catch exception when password is incorrect and prompt user
+
+            if (file.exists()) {
+                fis = new FileInputStream(file);
+                ks = KeyStore.getInstance(KEYSTORE_TYPE);
+                ks.load(fis, password.toCharArray());
+            } else {
+                ks = KeyStore.getInstance(KEYSTORE_TYPE);
+                ks.load(null, password.toCharArray());
+            }
+        } finally {
+            if (fis != null) {
+                fis.close();
+            }
+        }
+
+        return ks;
+    }
+
+}
--- a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Thu Nov 04 16:44:27 2010 -0700
+++ b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Mon Nov 08 16:36:17 2010 -0500
@@ -44,93 +44,153 @@
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.io.FileOutputStream;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.security.KeyStore;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.List;
 
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
+import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
+import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTabbedPane;
 import javax.swing.JTable;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 import javax.swing.table.DefaultTableModel;
 
+import net.sourceforge.jnlp.security.KeyStores;
 import net.sourceforge.jnlp.security.SecurityUtil;
 import net.sourceforge.jnlp.security.SecurityWarningDialog;
+import net.sourceforge.jnlp.security.KeyStores.Level;
 import net.sourceforge.jnlp.tools.KeyTool;
 
 public class CertificatePane extends JPanel {
 
         /**
-         * The certificates stored in the user's trusted.certs file.
+         * The certificates stored in the certificates file.
          */
         private ArrayList<X509Certificate> certs = null;
 
+        private static final Dimension TABLE_DIMENSION = new Dimension(500,200);
+
         /**
          * "Issued To" and "Issued By" string pairs for certs.
          */
         private String[][] issuedToAndBy = null;
         private final String[] columnNames = { "Issued To", "Issued By" };
 
-        private JTable table;
+        private final CertificateType[] certificateTypes = new CertificateType[] {
+            new CertificateType(KeyStores.Type.CA_CERTS),
+            new CertificateType(KeyStores.Type.JSSE_CA_CERTS),
+            new CertificateType(KeyStores.Type.CERTS),
+            new CertificateType(KeyStores.Type.JSSE_CERTS),
+        };
+
+        JTabbedPane tabbedPane;
+        private final JTable userTable;
+        private final JTable systemTable;
+        private JComboBox certificateTypeCombo;
+        private KeyStores.Type currentKeyStoreType;
+        private KeyStores.Level currentKeyStoreLevel;
+
+        /** JComponents that should be disbled for system store */
+        private final List<JComponent> disableForSystem;
 
         private JDialog parent;
-
         private JComponent defaultFocusComponent = null;
 
         /**
-         * The KeyStore associated with the user's trusted.certs file.
+         * The Current KeyStore. Only one table/tab is visible for interaction to
+         * the user. This KeyStore corresponds to that.
          */
         private KeyStore keyStore = null;
 
         public CertificatePane(JDialog parent) {
                 super();
                 this.parent = parent;
-                initializeKeyStore();
+
+                userTable = new JTable(null);
+                systemTable = new JTable(null);
+                disableForSystem = new ArrayList<JComponent>();
+
                 addComponents();
+
+                currentKeyStoreType = ((CertificateType)(certificateTypeCombo.getSelectedItem())).getType();
+                if (tabbedPane.getSelectedIndex() == 0) {
+                    currentKeyStoreLevel = Level.USER;
+                } else {
+                    currentKeyStoreLevel = Level.SYSTEM;
+                }
+
+                repopulateTables();
         }
 
         /**
          * Reads the user's trusted.cacerts keystore.
          */
         private void initializeKeyStore() {
-                try {
-                        keyStore = SecurityUtil.getUserKeyStore();
-                } catch (Exception e) {
-                        // TODO Auto-generated catch block
-                        e.printStackTrace();
-                }
+            try {
+                keyStore = KeyStores.getKeyStore(currentKeyStoreLevel, currentKeyStoreType);
+            } catch (Exception e) {
+                    e.printStackTrace();
+            }
         }
 
         //create the GUI here.
         protected void addComponents() {
-                readKeyStore();
 
                 JPanel main = new JPanel(new BorderLayout());
 
+                JPanel certificateTypePanel = new JPanel(new BorderLayout());
+                certificateTypePanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+
+                JLabel certificateTypeLabel = new JLabel("Certificate Type:");
+
+                certificateTypeCombo = new JComboBox(certificateTypes);
+                certificateTypeCombo.addActionListener(new CertificateTypeListener());
+
+                certificateTypePanel.add(certificateTypeLabel, BorderLayout.LINE_START);
+                certificateTypePanel.add(certificateTypeCombo, BorderLayout.CENTER);
+
                 JPanel tablePanel = new JPanel(new BorderLayout());
 
-                //Table
-                DefaultTableModel tableModel
+                // User Table
+                DefaultTableModel userTableModel
                         = new DefaultTableModel(issuedToAndBy, columnNames);
-                table = new JTable(tableModel);
-                table.getTableHeader().setReorderingAllowed(false);
-                table.setFillsViewportHeight(true);
-                JScrollPane tablePane = new JScrollPane(table);
-                tablePane.setPreferredSize(new Dimension(500,200));
-                tablePane.setSize(new Dimension(500,200));
-                tablePane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+                userTable.setModel(userTableModel);
+                userTable.getTableHeader().setReorderingAllowed(false);
+                userTable.setFillsViewportHeight(true);
+                JScrollPane userTablePane = new JScrollPane(userTable);
+                userTablePane.setPreferredSize(TABLE_DIMENSION);
+                userTablePane.setSize(TABLE_DIMENSION);
+                userTablePane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
 
-                JTabbedPane tabbedPane = new JTabbedPane();
-                tabbedPane.addTab("User", tablePane);
+                // System Table
+                DefaultTableModel systemTableModel = new DefaultTableModel(issuedToAndBy, columnNames);
+                systemTable.setModel(systemTableModel);
+                systemTable.getTableHeader().setReorderingAllowed(false);
+                systemTable.setFillsViewportHeight(true);
+                JScrollPane systemTablePane = new JScrollPane(systemTable);
+                systemTablePane.setPreferredSize(TABLE_DIMENSION);
+                systemTablePane.setSize(TABLE_DIMENSION);
+                systemTablePane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+
+                tabbedPane = new JTabbedPane();
+                tabbedPane.addTab("User", userTablePane);
+                tabbedPane.addTab("System", systemTablePane);
+                tabbedPane.addChangeListener(new TabChangeListener());
+
                 JPanel buttonPanel = new JPanel(new FlowLayout());
 
                 String[] buttonNames = {"Import", "Export", "Remove", "Details"};
@@ -156,6 +216,10 @@
                         button.setMnemonic(buttonMnemonics[i]);
                         button.addActionListener(listeners[i]);
                         button.setSize(maxWidth, button.getSize().height);
+                        // import and remove buttons
+                        if (i == 0 || i == 2) {
+                            disableForSystem.add(button);
+                        }
                         buttonPanel.add(button);
                 }
 
@@ -169,6 +233,7 @@
                 defaultFocusComponent = closeButton;
                 closePanel.add(closeButton, BorderLayout.EAST);
 
+                main.add(certificateTypePanel, BorderLayout.NORTH);
                 main.add(tablePanel, BorderLayout.CENTER);
                 main.add(closePanel, BorderLayout.SOUTH);
 
@@ -204,6 +269,7 @@
                 }
                 } catch (Exception e) {
                         //TODO
+                        e.printStackTrace();
                 }
         }
 
@@ -211,14 +277,16 @@
          * Re-reads the certs file and repopulates the JTable. This is typically
          * called after a certificate was deleted from the keystore.
          */
-        private void repopulateTable() {
+        private void repopulateTables() {
                 initializeKeyStore();
                 readKeyStore();
                 DefaultTableModel tableModel
                         = new DefaultTableModel(issuedToAndBy, columnNames);
 
-                table.setModel(tableModel);
-                repaint();
+                userTable.setModel(tableModel);
+
+                tableModel = new DefaultTableModel(issuedToAndBy, columnNames);
+                systemTable.setModel(tableModel);
         }
 
         public void focusOnDefaultButton() {
@@ -227,6 +295,61 @@
             }
         }
 
+    /** Allows storing KeyStores.Types in a JComponent */
+    private class CertificateType {
+        private final KeyStores.Type type;
+
+        public CertificateType(KeyStores.Type type) {
+            this.type = type;
+        }
+
+        public KeyStores.Type getType() {
+            return type;
+        }
+
+        public String toString() {
+            return KeyStores.toTranslatableString(null, type);
+        }
+    }
+
+    /** Invoked when a user selects a different certificate type */
+    private class CertificateTypeListener implements ActionListener {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JComboBox source = (JComboBox) e.getSource();
+            CertificateType type = (CertificateType) source.getSelectedItem();
+            currentKeyStoreType = type.getType();
+            repopulateTables();
+        }
+    }
+
+    /**
+     * Invoked when a user selects a different tab (switches from user to system
+     * 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();
+            switch (source.getSelectedIndex()) {
+                case 0:
+                    currentKeyStoreLevel = Level.USER;
+                    for (JComponent component : disableForSystem) {
+                        component.setEnabled(true);
+                    }
+                    break;
+                case 1:
+                    currentKeyStoreLevel = Level.SYSTEM;
+                    for (JComponent component : disableForSystem) {
+                        component.setEnabled(false);
+                    }
+                    break;
+            }
+            repopulateTables();
+
+        }
+    }
+
         private class ImportButtonListener implements ActionListener {
         public void actionPerformed(ActionEvent e) {
 
@@ -235,8 +358,12 @@
                 if(returnVal == JFileChooser.APPROVE_OPTION) {
                         try {
                                 KeyTool kt = new KeyTool();
-                                kt.importCert(chooser.getSelectedFile());
-                                repopulateTable();
+                                KeyStore ks = keyStore;
+                                kt.addToKeyStore(chooser.getSelectedFile(), ks);
+                                OutputStream os = new FileOutputStream(
+                                        KeyStores.getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                ks.store(os, KeyStores.getPassword());
+                                repopulateTables();
                         } catch (Exception ex) {
                                 // TODO: handle exception
                                 ex.printStackTrace();
@@ -247,6 +374,14 @@
 
         private class ExportButtonListener implements ActionListener {
                 public void actionPerformed(ActionEvent e) {
+
+                    JTable table = null;
+                    if (currentKeyStoreLevel == Level.USER) {
+                        table = userTable;
+                    } else {
+                        table = systemTable;
+                    }
+
                         //For now, let's just export in -rfc mode as keytool does.
                         //we'll write to a file the exported certificate.
 
@@ -263,7 +398,7 @@
                                                 Certificate c = keyStore.getCertificate(alias);
                                                 PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath());
                                                 KeyTool.dumpCert(c, ps);
-                                                repopulateTable();
+                                                repopulateTables();
                                         }
                                 }
                                 }
@@ -281,6 +416,12 @@
                  */
         public void actionPerformed(ActionEvent e) {
 
+            JTable table = null;
+            if (currentKeyStoreLevel == Level.USER) {
+                table = userTable;
+            } else {
+                table = systemTable;
+            }
                 try {
                         int selectedRow = table.getSelectedRow();
 
@@ -295,12 +436,12 @@
                                         if (i == 0) {
                                                 keyStore.deleteEntry(alias);
                                                 FileOutputStream fos = new FileOutputStream(
-                                                        SecurityUtil.getTrustedCertsFilename());
-                                                keyStore.store(fos, SecurityUtil.getTrustedCertsPassword());
+                                                        KeyStores.getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
+                                                keyStore.store(fos, KeyStores.getPassword());
                                                 fos.close();
                                         }
                                 }
-                                repopulateTable();
+                                repopulateTables();
                         }
                 } catch (Exception ex) {
                         // TODO
@@ -317,6 +458,13 @@
                  */
         public void actionPerformed(ActionEvent e) {
 
+            JTable table = null;
+            if (currentKeyStoreLevel == Level.USER) {
+                table = userTable;
+            } else {
+                table = systemTable;
+            }
+
                 int selectedRow = table.getSelectedRow();
                 if (selectedRow != -1 && selectedRow >= 0) {
                         X509Certificate c = certs.get(selectedRow);
--- a/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Thu Nov 04 16:44:27 2010 -0700
+++ b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Mon Nov 08 16:36:17 2010 -0500
@@ -48,6 +48,8 @@
 import javax.swing.JDialog;
 import javax.swing.UIManager;
 
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+
 public class CertificateViewer extends JDialog {
 
     private boolean initialized = false;
@@ -97,6 +99,7 @@
 
 
         public static void showCertificateViewer() throws Exception {
+            JNLPRuntime.initialize(true);
             setSystemLookAndFeel();
 
                 CertificateViewer cv = new CertificateViewer();
--- a/netx/net/sourceforge/jnlp/tools/KeyTool.java	Thu Nov 04 16:44:27 2010 -0700
+++ b/netx/net/sourceforge/jnlp/tools/KeyTool.java	Mon Nov 08 16:36:17 2010 -0500
@@ -32,7 +32,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
+import java.math.BigInteger;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
 import java.security.MessageDigest;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
@@ -117,6 +119,43 @@
                 return importCert((Certificate)cert);
         }
 
+    /**
+     * Adds the X509Certficate in the file to the KeyStore
+     */
+    public final void addToKeyStore(File file, KeyStore ks) throws CertificateException,
+            IOException, KeyStoreException {
+        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
+        CertificateFactory cf = CertificateFactory.getInstance("X509");
+        X509Certificate cert = null;
+
+        try {
+            cert = (X509Certificate) cf.generateCertificate(bis);
+        } catch (ClassCastException cce) {
+            throw new CertificateException("Input file is not an X509 Certificate", cce);
+        }
+
+        addToKeyStore(cert, ks);
+
+    }
+
+    /**
+     * Adds an X509Certificate to the KeyStore
+     */
+    public final void addToKeyStore(X509Certificate cert, KeyStore ks) throws KeyStoreException {
+        String alias = null;
+        Random random = new Random();
+        alias = ks.getCertificateAlias(cert);
+        // already in keystore; done
+        if (alias != null) {
+            return;
+        }
+
+        do {
+            alias = new BigInteger(20, random).toString();
+        } while (ks.getCertificate(alias) != null);
+        ks.setCertificateEntry(alias, cert);
+    }
+
         /**
          * Adds a trusted certificate to the user's keystore.
          * @return true if the add was successful, false otherwise.