[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