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

Omair Majid omajid at redhat.com
Mon Nov 8 13:39:37 PST 2010


On 11/08/2010 04:19 PM, Andrew Su wrote:
>
> ----- "Deepak Bhole"<dbhole at redhat.com>  wrote:
>
>> From: "Deepak Bhole"<dbhole at redhat.com>
>> To: "Omair Majid"<omajid at redhat.com>
>> Cc: "Andrew Su"<asu at redhat.com>, "IcedTea"<distro-pkg-dev at openjdk.java.net>
>> Sent: Monday, November 8, 2010 3:57:58 PM GMT -05:00 US/Canada Eastern
>> Subject: Re: [icedtea-web] RFC: integrate multiple KeyStore support into CertificateViewer
>>
>> * Omair Majid<omajid at redhat.com>  [2010-11-08 15:36]:
>>> Hi Andrew,
>>>
>>> On 11/08/2010 03:15 PM, Andrew Su wrote:
>>>> 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.
>>>
>>> The problem is that we dont know which directories were created. We
>>> could keep track of all the parent directories which did not exist
>>> and try deleting them, but IMHO the cleanup is unnecessary.
>>>
>>>>> +                    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.
>>>>
>>>
>>> Fixed.
>>>
>>>>> +    }
>>>>> +
>>>>>           /**
>>>>>            * Adds a trusted certificate to the user's keystore.
>>>>>            * @return true if the add was successful, false
>> otherwise.
>>>> Everything else seems okay to me.
>>>>
>>>
>>> Thanks for reviewing the patch. Ok to commit?
>>>
>>
>> Speaking only for myself and not Andrew, OK from me for HEAD.
> Okay for me too.
>

Thanks for the review!

Cheers,
Omair



More information about the distro-pkg-dev mailing list