org.kse.gui.KeyStoreTableModel.java Source code

Java tutorial

Introduction

Here is the source code for org.kse.gui.KeyStoreTableModel.java

Source

/*
 * Copyright 2004 - 2013 Wayne Grant
 *           2013 - 2019 Kai Kramer
 *
 * This file is part of KeyStore Explorer.
 *
 * KeyStore Explorer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * KeyStore Explorer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with KeyStore Explorer.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kse.gui;

import static org.kse.crypto.KeyType.SYMMETRIC;

import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.TreeMap;

import javax.crypto.SecretKey;
import javax.swing.table.AbstractTableModel;

import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.kse.crypto.CryptoException;
import org.kse.crypto.KeyInfo;
import org.kse.crypto.keypair.KeyPairUtil;
import org.kse.crypto.keystore.KeyStoreType;
import org.kse.crypto.keystore.KeyStoreUtil;
import org.kse.crypto.secretkey.SecretKeyType;
import org.kse.crypto.secretkey.SecretKeyUtil;
import org.kse.crypto.x509.KseX500NameStyle;
import org.kse.crypto.x509.X500NameUtils;
import org.kse.crypto.x509.X509CertUtil;
import org.kse.utilities.history.KeyStoreHistory;
import org.kse.utilities.history.KeyStoreState;
import org.kse.utilities.io.HexUtil;

/**
 * The table model used to display a KeyStore's entries sorted by alias name.
 *
 */
public class KeyStoreTableModel extends AbstractTableModel {
    private static final long serialVersionUID = 1L;
    private static ResourceBundle res = ResourceBundle.getBundle("org/kse/gui/resources");
    private String[] columnNames;
    private Class[] columnTypes;
    private Object[][] data;
    private KeyStoreHistory history;

    /** Type column value for a key pair entry */
    public static final String KEY_PAIR_ENTRY = res.getString("KeyStoreTableModel.KeyPairEntry");

    /** Type column value for a trusted certificate entry */
    public static final String TRUST_CERT_ENTRY = res.getString("KeyStoreTableModel.TrustCertEntry");

    /** Type column value for a key entry */
    public static final String KEY_ENTRY = res.getString("KeyStoreTableModel.KeyEntry");

    private KeyStoreTableColumns keyStoreTableColumns = new KeyStoreTableColumns();
    private int nofColumns = 5;
    private int iColWidth[];
    private static final int ICON_SIZE = 28;
    /** Column for a property */
    private static int expiryWarnDays = 0;
    private static int iNameColumn = -1;
    private static int iAlgorithmColumn = -1;
    private static int iKeySizeColumn = -1;
    private static int iCurveColumn = -1;
    private static int iCertExpiryColumn = -1;
    private static int iLastModifiedColumn = -1;
    private static int iAKIColumn = -1;
    private static int iSKIColumn = -1;
    private static int iIssuerDNColumn = -1;
    private static int iSubjectDNColumn = -1;
    private static int iIssuerCNColumn = -1;
    private static int iSubjectCNColumn = -1;
    private static int iIssuerOColumn = -1;
    private static int iSubjectOColumn = -1;

    /**
     * Construct a new KeyStoreTableModel with a variable layout.
     */
    public KeyStoreTableModel(KeyStoreTableColumns keyStoreTableColumnsParm) {
        this.keyStoreTableColumns = keyStoreTableColumnsParm;
        adjustColumns(keyStoreTableColumnsParm);
        data = new Object[0][0];
    }

    /**
     * Load the KeyStoreTableModel with the entries from a KeyStore.
     *
     * @param history
     *            KeyStore history
     * @throws GeneralSecurityException
     *             If a KeyStore problem occurs while accessing the KeyStore's
     *             entries
     * @throws CryptoException
     *             If a crypto problem occurs while accessing the KeyStore's
     *             entries
     */
    public void load(KeyStoreHistory history) throws GeneralSecurityException, CryptoException {
        this.history = history;
        KeyStoreState currentState = history.getCurrentState();

        KeyStore keyStore = currentState.getKeyStore();
        KeyStoreType type = KeyStoreType.resolveJce(keyStore.getType());

        Enumeration<String> aliases = keyStore.aliases();

        TreeMap<String, String> sortedAliases = new TreeMap<>(new AliasComparator());

        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            if (!KeyStoreUtil.isSupportedEntryType(alias, keyStore)) {
                continue;
            }
            sortedAliases.put(alias, alias);
        }

        data = new Object[sortedAliases.size()][nofColumns];

        int i = 0;
        for (Iterator<Entry<String, String>> itr = sortedAliases.entrySet().iterator(); itr.hasNext(); i++) {
            String alias = itr.next().getKey();

            String entryType = null;

            // Type column
            if (KeyStoreUtil.isTrustedCertificateEntry(alias, keyStore)) {
                entryType = TRUST_CERT_ENTRY;
            } else if (KeyStoreUtil.isKeyPairEntry(alias, keyStore)) {
                entryType = KEY_PAIR_ENTRY;
            } else {
                entryType = KEY_ENTRY;
            }

            data[i][0] = entryType;

            // Lock column - only applies to KeyStores types that actually support passwords for entries
            if ((entryType.equals(KEY_PAIR_ENTRY) || entryType.equals(KEY_ENTRY)) && type.hasEntryPasswords()) {
                if (currentState.getEntryPassword(alias) != null) {
                    data[i][1] = Boolean.FALSE; // Unlocked
                } else {
                    data[i][1] = Boolean.TRUE; // Locked
                }
            } else {
                data[i][1] = null; // Lock status does not apply
            }

            // Expiry status column
            Date expiry = getCertificateExpiry(alias, keyStore);
            Calendar c = Calendar.getInstance();
            Calendar a = Calendar.getInstance();
            c.setTime(new Date()); // Now use today date.
            a.setTime(new Date()); // Now use today date.
            a.add(Calendar.DATE, expiryWarnDays); // Adding warning interval
            if (expiry == null) {
                data[i][2] = null; // No expiry - must be a key entry
            } else {
                if (expiry.before(c.getTime())) {
                    data[i][2] = 2; // Expired
                } else {
                    if (expiry.before(a.getTime())) {
                        data[i][2] = 1; // Almost expired
                    } else {
                        data[i][2] = 0; // Not expired
                    }
                }
            }

            if (iNameColumn > 0) {
                // Alias column
                data[i][iNameColumn] = alias;
                if (alias.length() > iColWidth[iNameColumn]) {
                    iColWidth[iNameColumn] = alias.length();
                }
            }

            KeyInfo keyInfo = getKeyInfo(alias, keyStore, currentState);

            if (keyInfo != null) {
                // Algorithm column
                if (iAlgorithmColumn > 0) {
                    data[i][iAlgorithmColumn] = getAlgorithmName(keyInfo);
                    if (iColWidth[iAlgorithmColumn] < data[i][iAlgorithmColumn].toString().length()) {
                        iColWidth[iAlgorithmColumn] = data[i][iAlgorithmColumn].toString().length();
                    }
                }

                // Key Size column
                if (iKeySizeColumn > 0) {
                    data[i][iKeySizeColumn] = keyInfo.getSize();
                }
                // Key Size column
                if (keyStoreTableColumns.getEnableCurve()) {
                    data[i][iCurveColumn] = keyInfo.getDetailedAlgorithm();
                    if (iColWidth[iCurveColumn] < data[i][iCurveColumn].toString().length()) {
                        iColWidth[iCurveColumn] = data[i][iCurveColumn].toString().length();
                    }
                }
            }
            if (iCertExpiryColumn > 0) {
                // Expiry date column
                if (expiry != null) {

                    data[i][iCertExpiryColumn] = expiry;
                } else {
                    data[i][iCertExpiryColumn] = null; // No expiry date - must
                    // be a key entry
                }
            }
            if (iLastModifiedColumn > 0) {
                // Modified date column - only applies to non-PKCS #11/#12
                // KeyStores
                if (!keyStore.getType().equals(KeyStoreType.PKCS12.jce())
                        && !keyStore.getType().equals(KeyStoreType.PKCS11.jce())) {
                    data[i][iLastModifiedColumn] = keyStore.getCreationDate(alias);
                } else {
                    data[i][iLastModifiedColumn] = null;
                }
            }
            if (iSubjectDNColumn > 0) {
                if (entryType != KEY_ENTRY) {
                    data[i][iSubjectDNColumn] = getCertificateSubjectDN(alias, keyStore);
                    if (iColWidth[iSubjectDNColumn] < data[i][iSubjectDNColumn].toString().length()) {
                        iColWidth[iSubjectDNColumn] = data[i][iSubjectDNColumn].toString().length();
                    }
                } else {
                    data[i][iSubjectDNColumn] = null;
                }
            }
            if (iIssuerDNColumn > 0) {
                if (entryType != KEY_ENTRY) {
                    data[i][iIssuerDNColumn] = getCertificateIssuerDN(alias, keyStore);
                    if (iColWidth[iIssuerDNColumn] < data[i][iIssuerDNColumn].toString().length()) {
                        iColWidth[iIssuerDNColumn] = data[i][iIssuerDNColumn].toString().length();
                    }
                } else {
                    data[i][iIssuerDNColumn] = null;
                }
            }
            if (iSubjectCNColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iSubjectCNColumn] = getCertificateSubjectCN(alias, keyStore);
                    if (iColWidth[iSubjectCNColumn] < data[i][iSubjectCNColumn].toString().length()) {
                        iColWidth[iSubjectCNColumn] = data[i][iSubjectCNColumn].toString().length();
                    }
                } else {
                    data[i][iSubjectCNColumn] = null;
                }
            }
            if (iIssuerCNColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iIssuerCNColumn] = getCertificateIssuerCN(alias, keyStore);
                    if (iColWidth[iIssuerCNColumn] < data[i][iIssuerCNColumn].toString().length()) {
                        iColWidth[iIssuerCNColumn] = data[i][iIssuerCNColumn].toString().length();
                    }
                } else {
                    data[i][iIssuerCNColumn] = null;
                }
            }
            if (iSubjectOColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iSubjectOColumn] = getCertificateSubjectO(alias, keyStore);
                    if (iColWidth[iSubjectOColumn] < data[i][iSubjectOColumn].toString().length()) {
                        iColWidth[iSubjectOColumn] = data[i][iSubjectOColumn].toString().length();
                    }
                } else {
                    data[i][iSubjectOColumn] = null;
                }
            }
            if (iIssuerOColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iIssuerOColumn] = getCertificateIssuerO(alias, keyStore);
                    if (iColWidth[iIssuerOColumn] < data[i][iIssuerOColumn].toString().length()) {
                        iColWidth[iIssuerOColumn] = data[i][iIssuerOColumn].toString().length();
                    }

                } else {
                    data[i][iIssuerOColumn] = null;
                }
            }
            if (iAKIColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iAKIColumn] = getCertificateAKI(alias, keyStore);
                    if (iColWidth[iAKIColumn] < data[i][iAKIColumn].toString().length()) {
                        iColWidth[iAKIColumn] = data[i][iAKIColumn].toString().length();
                    }

                } else {
                    data[i][iAKIColumn] = null;
                }
            }
            if (iSKIColumn > 0) {
                if (entryType != KEY_ENTRY) { // assume a certificate
                    data[i][iSKIColumn] = getCertificateSKI(alias, keyStore);
                    if (iColWidth[iSKIColumn] < data[i][iSKIColumn].toString().length()) {
                        iColWidth[iSKIColumn] = data[i][iSKIColumn].toString().length();
                    }
                } else {
                    data[i][iSKIColumn] = null;
                }
            }
        }

        fireTableDataChanged();
    }

    private Date getCertificateExpiry(String alias, KeyStore keyStore) throws CryptoException, KeyStoreException {
        if (KeyStoreUtil.isTrustedCertificateEntry(alias, keyStore)) {
            return X509CertUtil.convertCertificate(keyStore.getCertificate(alias)).getNotAfter();
        } else {
            Certificate[] chain = keyStore.getCertificateChain(alias);

            if (chain == null) {
                // Key entry - no expiry date
                return null;
            }

            // Key pair - first certificate in chain will be for the private key
            X509Certificate[] x509Chain = X509CertUtil.orderX509CertChain(X509CertUtil.convertCertificates(chain));
            if (expiryWarnDays < 1) {
                return x509Chain[0].getNotAfter();
            } else {
                Calendar cal = Calendar.getInstance();
                cal.set(9999, 1, 1);
                Date earliest = cal.getTime();
                for (int i = 0; i < x509Chain.length; i++) {
                    if (x509Chain[i].getNotAfter().before(earliest)) {
                        earliest = x509Chain[i].getNotAfter();
                    }
                }
                return earliest;
            }
        }
    }

    private KeyInfo getKeyInfo(String alias, KeyStore keyStore, KeyStoreState currentState)
            throws CryptoException, GeneralSecurityException {
        if (KeyStoreUtil.isTrustedCertificateEntry(alias, keyStore)) {
            // Get key info from certificate
            X509Certificate cert = X509CertUtil.convertCertificate(keyStore.getCertificate(alias));
            return KeyPairUtil.getKeyInfo(cert.getPublicKey());
        } else {
            Certificate[] chain = keyStore.getCertificateChain(alias);

            if (chain != null) {
                // Key pair - first certificate in chain will be for the private key
                X509Certificate[] x509Chain = X509CertUtil
                        .orderX509CertChain(X509CertUtil.convertCertificates(chain));

                return KeyPairUtil.getKeyInfo(x509Chain[0].getPublicKey());
            } else {
                // Key entry - get key info if entry is unlocked
                if (currentState.getEntryPassword(alias) != null) {
                    char[] keyPassword = null;

                    keyPassword = currentState.getEntryPassword(alias).toCharArray();

                    Key key = keyStore.getKey(alias, keyPassword);
                    if (key instanceof SecretKey) {
                        return SecretKeyUtil.getKeyInfo((SecretKey) key);
                    } else if (key instanceof PrivateKey) {
                        return KeyPairUtil.getKeyInfo((PrivateKey) key);
                    } else if (key instanceof PublicKey) {
                        return KeyPairUtil.getKeyInfo((PublicKey) key);
                    }
                }
            }
        }

        return null;
    }

    private String getAlgorithmName(KeyInfo keyInfo) {
        String algorithm = keyInfo.getAlgorithm();

        if (keyInfo.getKeyType() == SYMMETRIC) {
            // Try and get friendly algorithm name for secret key
            SecretKeyType secretKeyType = SecretKeyType.resolveJce(algorithm);

            if (secretKeyType != null) {
                algorithm = secretKeyType.friendly();
            }
        }

        return algorithm;
    }

    private String getCertificateSubjectDN(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        return X500NameUtils.x500PrincipalToX500Name(x509Cert.getSubjectX500Principal()).toString();
    }

    private String getCertificateIssuerDN(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        return X500NameUtils.x500PrincipalToX500Name(x509Cert.getIssuerX500Principal()).toString();
    }

    private String getCertificateSubjectCN(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        return X500NameUtils.extractCN(x509Cert.getSubjectX500Principal());
    }

    private String getCertificateIssuerCN(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        return X500NameUtils.extractCN(x509Cert.getIssuerX500Principal());
    }

    private String getCertificateSKI(String alias, KeyStore keyStore) throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        try {
            byte[] skiValue = x509Cert.getExtensionValue(Extension.subjectKeyIdentifier.getId());
            byte[] octets = DEROctetString.getInstance(skiValue).getOctets();
            byte[] skiBytes = SubjectKeyIdentifier.getInstance(octets).getKeyIdentifier();
            return HexUtil.getHexString(skiBytes);
        } catch (Exception e) {
            return "-";
        }
    }

    private String getCertificateAKI(String alias, KeyStore keyStore) throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        try {
            byte[] akiValue = x509Cert.getExtensionValue(Extension.authorityKeyIdentifier.getId());
            byte[] octets = DEROctetString.getInstance(akiValue).getOctets();
            byte[] akiBytes = AuthorityKeyIdentifier.getInstance(octets).getKeyIdentifier();
            return HexUtil.getHexString(akiBytes);
        } catch (Exception e) {
            return "-";
        }
    }

    private String getCertificateSubjectO(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        X500Name subject = X500NameUtils.x500PrincipalToX500Name(x509Cert.getSubjectX500Principal());
        return X500NameUtils.getRdn(subject, KseX500NameStyle.O);
    }

    private String getCertificateIssuerO(String alias, KeyStore keyStore)
            throws CryptoException, KeyStoreException {
        X509Certificate x509Cert = getCertificate(alias, keyStore);
        X500Name issuer = X500NameUtils.x500PrincipalToX500Name(x509Cert.getIssuerX500Principal());
        return X500NameUtils.getRdn(issuer, KseX500NameStyle.O);
    }

    private X509Certificate getCertificate(String alias, KeyStore keyStore)
            throws KeyStoreException, CryptoException {
        X509Certificate x509Cert = null;
        if (KeyStoreUtil.isTrustedCertificateEntry(alias, keyStore)) {
            x509Cert = X509CertUtil.convertCertificate(keyStore.getCertificate(alias));
        } else {
            Certificate[] chain = keyStore.getCertificateChain(alias);
            if (chain == null) {
                return null;
            }
            // Key pair - first certificate in chain will be for the private key
            X509Certificate[] x509Chain = X509CertUtil.orderX509CertChain(X509CertUtil.convertCertificates(chain));
            x509Cert = x509Chain[0];
        }
        return x509Cert;
    }

    private void adjustColumns(KeyStoreTableColumns keyStoreTableColumnsParm) {
        keyStoreTableColumns = keyStoreTableColumnsParm;
        nofColumns = 3 + keyStoreTableColumns.getNofColumns();
        expiryWarnDays = keyStoreTableColumns.getExpiryWarnDays();
        iColWidth = new int[nofColumns];
        int col = 2;
        iNameColumn = -1; // remove all columns before possibly enabling them
        iAlgorithmColumn = -1;
        iKeySizeColumn = -1;
        iCurveColumn = -1;
        iCertExpiryColumn = -1;
        iLastModifiedColumn = -1;
        iAKIColumn = -1;
        iSKIColumn = -1;
        iIssuerDNColumn = -1;
        iSubjectDNColumn = -1;
        iIssuerCNColumn = -1;
        iSubjectCNColumn = -1;
        iIssuerOColumn = -1;
        iSubjectOColumn = -1;
        columnNames = new String[nofColumns];
        columnTypes = new Class[nofColumns];
        columnNames[0] = res.getString("KeyStoreTableModel.TypeColumn");
        columnTypes[0] = String.class;
        iColWidth[0] = ICON_SIZE;
        columnNames[1] = res.getString("KeyStoreTableModel.LockStatusColumn");
        columnTypes[1] = Boolean.class;
        iColWidth[1] = ICON_SIZE;
        columnNames[2] = res.getString("KeyStoreTableModel.CertExpiryStatusColumn");
        columnTypes[2] = Integer.class;
        iColWidth[2] = ICON_SIZE;
        for (col = 3; col < nofColumns; col++) {
            if (col == keyStoreTableColumns.colEntryName()) {
                columnNames[col] = res.getString("KeyStoreTableModel.NameColumn");
                columnTypes[col] = String.class;
                iNameColumn = col;
            }
            if (col == keyStoreTableColumns.colAlgorithm()) {
                columnNames[col] = res.getString("KeyStoreTableModel.AlgorithmColumn");
                columnTypes[col] = String.class;
                iAlgorithmColumn = col;
            }
            if (col == keyStoreTableColumns.colKeySize()) {
                columnNames[col] = res.getString("KeyStoreTableModel.KeySizeColumn");
                columnTypes[col] = Integer.class;
                iKeySizeColumn = col;
            }
            if (col == keyStoreTableColumns.colCurve()) {
                columnNames[col] = res.getString("KeyStoreTableModel.CurveColumn");
                columnTypes[col] = String.class;
                iCurveColumn = col;
            }
            if (col == keyStoreTableColumns.colCertificateExpiry()) {
                columnNames[col] = res.getString("KeyStoreTableModel.CertExpiryColumn");
                columnTypes[col] = Date.class;
                iCertExpiryColumn = col;
                iColWidth[col] = " 20.00.2000 00:00:00 MESZ ".length();
            }
            if (col == keyStoreTableColumns.colLastModified()) {
                columnNames[col] = res.getString("KeyStoreTableModel.LastModifiedColumn");
                columnTypes[col] = Date.class;
                iLastModifiedColumn = col;
                iColWidth[col] = " 20.00.2000 00:00:00 MESZ ".length();
            }
            if (col == keyStoreTableColumns.colAKI()) {
                columnNames[col] = res.getString("KeyStoreTableModel.AKIColumn");
                columnTypes[col] = String.class;
                iAKIColumn = col;
            }
            if (col == keyStoreTableColumns.colSKI()) {
                columnNames[col] = res.getString("KeyStoreTableModel.SKIColumn");
                columnTypes[col] = String.class;
                iSKIColumn = col;
            }
            if (col == keyStoreTableColumns.colIssuerDN()) {
                columnNames[col] = res.getString("KeyStoreTableModel.IssuerDNColumn");
                columnTypes[col] = String.class;
                iIssuerDNColumn = col;
            }
            if (col == keyStoreTableColumns.colSubjectDN()) {
                columnNames[col] = res.getString("KeyStoreTableModel.SubjectDNColumn");
                columnTypes[col] = String.class;
                iSubjectDNColumn = col;
            }
            if (col == keyStoreTableColumns.colIssuerCN()) {
                columnNames[col] = res.getString("KeyStoreTableModel.IssuerCNColumn");
                columnTypes[col] = String.class;
                iIssuerCNColumn = col;
            }
            if (col == keyStoreTableColumns.colSubjectCN()) {
                columnNames[col] = res.getString("KeyStoreTableModel.SubjectCNColumn");
                columnTypes[col] = String.class;
                iSubjectCNColumn = col;
            }
            if (col == keyStoreTableColumns.colIssuerO()) {
                columnNames[col] = res.getString("KeyStoreTableModel.IssuerOColumn");
                columnTypes[col] = String.class;
                iIssuerOColumn = col;
            }
            if (col == keyStoreTableColumns.colSubjectO()) {
                columnNames[col] = res.getString("KeyStoreTableModel.SubjectOColumn");
                columnTypes[col] = String.class;
                iSubjectOColumn = col;
            }
            if (iColWidth[col] < 1) {
                iColWidth[col] = columnNames[col].length();
            }
        }
    }

    /**
     * Get the number of columns in the table.
     *
     * @return The number of columns
     */
    @Override
    public int getColumnCount() {
        return columnNames.length;
    }

    /**
     * Get the number of rows in the table.
     *
     * @return The number of rows
     */
    @Override
    public int getRowCount() {
        return data.length;
    }

    /**
     * Get the name of the column at the given position.
     *
     * @param col
     *            The column position
     * @return The column name
     */
    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    /**
     * Get the cell value at the given row and column position.
     *
     * @param row
     *            The row position
     * @param col
     *            The column position
     * @return The cell value
     */
    @Override
    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

    /**
     * Get the class of the values at the provided column.
     *
     * @param col
     *            The column position
     * @return The column cells' class
     */
    @Override
    public Class<?> getColumnClass(int col) {
        return columnTypes[col];
    }

    /**
     * Is the cell at the given row and column position editable?
     *
     * @param row
     *            The row position
     * @param col
     *            The column position
     * @return True if the cell is editable, false otherwise
     */
    @Override
    public boolean isCellEditable(int row, int col) {
        return false;
    }

    public KeyStoreTableColumns getKeyStoreTableColumns() {
        return keyStoreTableColumns;
    }

    public void setKeyStoreTableColumns(KeyStoreTableColumns keyStoreTableColumns) {
        this.keyStoreTableColumns = keyStoreTableColumns;
        adjustColumns(keyStoreTableColumns);
    }

    /**
     * Maximum width of a column
     *
     * @param col
     *            The column
     *
     * @return Maximum length of the contents (or title) in characters
     * @
     */
    public int getColumnWidth(int col) {
        if ((col < nofColumns) && (col >= 0)) {
            return iColWidth[col];
        } else {
            return 0;
        }
    }

    public KeyStoreHistory getHistory() {
        return history;
    }

    private class AliasComparator implements Comparator<String> {
        @Override
        public int compare(String name1, String name2) {
            return name1.compareToIgnoreCase(name2);
        }
    }
}