[icedtea-web] RFC: integrate multiple KeyStore support into CertificateViewer

Andrew Su asu at redhat.com
Mon Nov 8 12:15:07 PST 2010


Hi,

On 11/04/2010 04:15 PM, Omair Majid wrote:
> Hi,
>
> The attached patch starts integrating some of the security certificate 
> configuration into Netx.
>
> It adds a new class KeyStores that is used to access the different 
> types of KeyStore that Netx supports - per user and per system 
> variants of trusted CA KeyStore, trusted certificate store, JSSE CA 
> store, and JSSE certificates store.
>
> It also fixes up the certificate viewer (javaws -viewer) to use these 
> multiple certificate stores.
>
> ChangeLog
> 2010-11-04  Omair Majid <omajid at 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.
>
>
> Any thoughts or comments?
>
> Thanks,
> Omair
> icedtea-web-integrate-configuration-security-files-05.patch
>
>
> diff -r 2405cef22921 netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java
> --- a/netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java	Wed Nov 03 23:06:23 2010 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/DeploymentConfiguration.java	Thu Nov 04 15:57:40 2010 -0400
> @@ -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) },
> diff -r 2405cef22921 netx/net/sourceforge/jnlp/security/KeyStores.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/security/KeyStores.java	Thu Nov 04 15:57:40 2010 -0400
> @@ -0,0 +1,300 @@
> +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()) {
According to mkdirs() some of the parent directories may get created. 
Maybe clean up if attempt failed.
> +                    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;
> +    }
> +
> +}
> diff -r 2405cef22921 netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java
> --- a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Wed Nov 03 23:06:23 2010 +0000
> +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java	Thu Nov 04 15:57:40 2010 -0400
> @@ -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);
> diff -r 2405cef22921 netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java
> --- a/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Wed Nov 03 23:06:23 2010 +0000
> +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Thu Nov 04 15:57:40 2010 -0400
> @@ -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();
> diff -r 2405cef22921 netx/net/sourceforge/jnlp/tools/KeyTool.java
> --- a/netx/net/sourceforge/jnlp/tools/KeyTool.java	Wed Nov 03 23:06:23 2010 +0000
> +++ b/netx/net/sourceforge/jnlp/tools/KeyTool.java	Thu Nov 04 15:57:40 2010 -0400
> @@ -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,47 @@
>                   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;
> +        }
> +
> +        boolean aliasFound = false;
> +        do {
> +            alias = new BigInteger(20, random).toString();
> +            if (ks.getCertificate(alias) == null) {
> +                aliasFound = true;
> +            }
> +        } while (!aliasFound);
> +        ks.setCertificateEntry(alias, cert);
aliasFound is a bit confusing for name.

this can be changed to:

do{
     alias = new BigInteger(20, random).toString();
} while (ks.getCertificate(alias) != null);

to avoid using aliasFound.

> +    }
> +
>           /**
>            * Adds a trusted certificate to the user's keystore.
>            * @return true if the add was successful, false otherwise.
Everything else seems okay to me.

Cheers,
    Andrew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/distro-pkg-dev/attachments/20101108/44bfe812/attachment.html 


More information about the distro-pkg-dev mailing list