summaryrefslogtreecommitdiff
path: root/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java')
-rw-r--r--src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java546
1 files changed, 546 insertions, 0 deletions
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java
new file mode 100644
index 0000000..1cf9d66
--- /dev/null
+++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Represents one keystore element in {@link KeystoreManagerView}. It can be
+ * {@link Certificate} or {@link Key}.
+ */
+public class EntryNode extends AbstractTreeNode implements IKeyStoreEntry
+{
+ /**
+ * The constant contains the key pair DER object identifier.
+ */
+ public static final String KEY_PAIR_DER_OBJ_ID = "2.16.840.1.113793.23"; //$NON-NLS-1$
+
+ public static final int KEY_PASSWORD_MIN_SIZE = 6;
+
+ protected String alias;
+
+ private final String KEY_NONSAVED_PASSWORD_ICON_PATH = "icons/key.png"; //$NON-NLS-1$
+
+ private final String KEY_SAVED_PASSWORD_ICON_PATH = "icons/key_saved_password.png"; //$NON-NLS-1$
+
+ protected EntryNode()
+ {
+
+ }
+
+ /**
+ *
+ * @param keyStoreModel
+ * @param alias
+ * @throws KeyStoreManagerException
+ * if the alias is already listed in the tree
+ */
+ public EntryNode(ITreeNode keyStoreModel, String alias) throws KeyStoreManagerException
+ {
+ this.alias = alias.toLowerCase();
+ setParent(keyStoreModel);
+ if (!isKeyPairEntry())
+ {
+ keyStoreModel.addChild(this);
+ }
+
+ // notify key entry addition
+ // KeyStoreModelEventManager.getInstance().fireEvent(this, KeyStoreModelEvent.EventType.ADD);
+
+ // Obtaining certificate to get tooltip information
+ X509Certificate cert = getX509Certificate();
+ if (cert != null)
+ {
+ X500Name x500name;
+ try
+ {
+ x500name = new JcaX509CertificateHolder(cert).getSubject();
+
+ RDN commonName =
+ x500name.getRDNs(BCStyle.CN).length >= 1 ? x500name.getRDNs(BCStyle.CN)[0]
+ : null;
+ RDN organization =
+ x500name.getRDNs(BCStyle.O).length >= 1 ? x500name.getRDNs(BCStyle.O)[0]
+ : null;
+
+ // Adding tooltip information
+ String org =
+ organization != null ? organization.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ String name =
+ commonName != null ? commonName.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ this.setTooltip(NLS.bind(CertificateManagerNLS.CertificateBlock_KeyTooltip, org,
+ name));
+ }
+ catch (CertificateEncodingException e)
+ {
+ String errorMsg = "Error getting data from certificate";
+ StudioLogger.error(EntryNode.class, errorMsg, e);
+ throw new KeyStoreManagerException(errorMsg, e);
+ }
+ }
+ }
+
+ /*(non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKeyStoreNode()
+ */
+ @Override
+ public IKeyStore getKeyStoreNode()
+ {
+ return (KeyStoreNode) getParent();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getAlias()
+ */
+ @Override
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isCertificateEntry()
+ */
+ @Override
+ public boolean isCertificateEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isCertificateEntry(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isKeyEntry()
+ */
+ @Override
+ public boolean isKeyEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isKeyEntry(alias);
+ }
+
+ @Override
+ public boolean isKeyPairEntry()
+ {
+ X509Certificate certificate = getX509Certificate();
+ Set<String> criticalOIDs = certificate.getCriticalExtensionOIDs();
+ return (criticalOIDs != null) && criticalOIDs.contains(KEY_PAIR_DER_OBJ_ID);
+ }
+
+ /**
+ * @return {@link Certificate} if alias represents a certificate or null if
+ * the alias was not found (or if the type is not Certificate for
+ * the alias)
+ * @throws KeyStoreException
+ * if keystore not loaded yet
+ * @throws KeyStoreManagerException
+ */
+ private Certificate getCertificate() throws KeyStoreException, KeyStoreManagerException
+ {
+ Certificate certificate = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isCertificateEntry(alias))
+ {
+ certificate = keyStore.getCertificate(alias);
+ }
+ else
+ {
+ // unknown type
+ StudioLogger.error(CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_NotFoundOrTypeWrong, alias));
+ }
+ return certificate;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKey(java.lang.String)
+ */
+ @Override
+ public Key getKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException
+ {
+ Key key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getKey(alias, password.toCharArray());
+ }
+
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getPrivateKey(java.lang.String)
+ */
+ @Override
+ public PrivateKey getPrivateKey(String password) throws UnrecoverableKeyException,
+ KeyStoreException, NoSuchAlgorithmException, KeyStoreManagerException,
+ InvalidKeyException
+ {
+ Key key = this.getKey(password);
+
+ if (!(key instanceof PrivateKey))
+ {
+ throw new InvalidKeyException("This is not a private key");
+ }
+
+ return (PrivateKey) key;
+ }
+
+ public Entry getKeyEntry(String password) throws KeyStoreException, NoSuchAlgorithmException,
+ KeyStoreManagerException, UnrecoverableEntryException
+ {
+ Entry key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getEntry(alias, new KeyStore.PasswordProtection(password.toCharArray()));
+ }
+ return key;
+ }
+
+ /**
+ * Get all the certificates associated to this entry
+ *
+ * @return an Array of {@link Certificate}
+ * @throws KeyStoreException
+ * @throws KeyStoreManagerException
+ */
+ private Certificate[] getCertificateChain() throws KeyStoreException, KeyStoreManagerException
+ {
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ return keyStore.getCertificateChain(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((alias == null) ? 0 : alias.hashCode());
+ result =
+ (prime * result) + ((getKeyStoreNode() == null) ? 0 : getKeyStoreNode().hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof EntryNode))
+ {
+ return false;
+ }
+ EntryNode other = (EntryNode) obj;
+ if (alias == null)
+ {
+ if (other.alias != null)
+ {
+ return false;
+ }
+ }
+ else if (!alias.equals(other.alias))
+ {
+ return false;
+ }
+ if (getKeyStoreNode() == null)
+ {
+ if (other.getKeyStoreNode() != null)
+ {
+ return false;
+ }
+ }
+ else if (!getKeyStoreNode().equals(other.getKeyStoreNode()))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "KeyStoreEntry [alias=" + alias + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void refresh()
+ {
+ // keys does not need to be refreshed
+ }
+
+ @Override
+ public String getId()
+ {
+ return alias;
+ }
+
+ @Override
+ public String getName()
+ {
+ return alias;
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ //decision: we will not support key-pair, so we will have just key items below keystore node.
+ ImageDescriptor descr = null;
+ if (isPasswordSaved())
+ {
+ //saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_SAVED_PASSWORD_ICON_PATH);
+ }
+ else
+ {
+ //non saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_NONSAVED_PASSWORD_ICON_PATH);
+ }
+ return descr;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return true;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return new ArrayList<ITreeNode>(0); // it is the leaf of the tree
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String keyStorePass,
+ String alias, CertificateDetailsInfo certificateDetailsInfo)
+ throws KeyStoreManagerException
+ {
+ KeyPair keyPair = null;
+
+ try
+ {
+ keyPair = KeyStoreUtils.genKeyPair();
+ X509Certificate x509Certificate =
+ KeyStoreUtils.createX509Certificate(keyPair, certificateDetailsInfo);
+
+ if (keyStorePass == null)
+ {
+ PasswordProvider provider = new PasswordProvider(keystore.getFile());
+ keyStorePass = provider.getKeyStorePassword(true);
+ }
+
+ PrivateKeyEntry privateKeyEntry =
+ KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate);
+ KeyStoreUtils.addEntry(keystore.getKeyStore(), keyStorePass.toCharArray(), keystore
+ .getFile(), alias, privateKeyEntry, certificateDetailsInfo.getEntryPassword()
+ .toCharArray());
+
+ //force reload - because keystore cache can be old due to key entries additions/removals
+ keystore.forceReload(keyStorePass.toCharArray(), false);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(e.getMessage(), e);
+ }
+
+ return new EntryNode((ITreeNode) keystore, alias);
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String alias,
+ CertificateDetailsInfo certificateDetailsInfo) throws KeyStoreManagerException
+ {
+ return createSelfSignedNode(keystore, null, alias, certificateDetailsInfo);
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = super.testAttribute(target, name, value);
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_WARNING))
+ {
+ X509Certificate x509Certificate = getX509Certificate();
+ try
+ {
+ // check validity concerning the current date
+ x509Certificate.checkValidity();
+
+ // now check validity related to magic date provided by
+ // Google
+ Calendar date = GregorianCalendar.getInstance();
+ date.clear();
+ date.set(2033, Calendar.OCTOBER, 22);
+ x509Certificate.checkValidity(date.getTime());
+ }
+ catch (CertificateExpiredException e)
+ {
+ // certificate has expired in the current date; or
+ // certificate has expired before 22 Oct 2033
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodExpired_Issue,
+ x509Certificate.getNotAfter()));
+ result = true; // decorate node
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ // certificate is not yet valid in the current date; or
+ // certificate is not yet valid in 2033 => it must not
+ // happen but we need to deal with this case
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodNotYeatValid_Issue,
+ x509Certificate.getNotBefore()));
+ result = true; // decorate node
+ }
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Get the first X509Certificate available in the entry
+ *
+ * @return
+ */
+ @Override
+ public X509Certificate getX509Certificate()
+ {
+ X509Certificate x509Certificate = null;
+ try
+ {
+ if (isCertificateEntry())
+ {
+ Certificate cert = getCertificate();
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ else if (isKeyEntry())
+ {
+ Certificate[] chain = getCertificateChain();
+ for (int i = 0; i < chain.length; i++)
+ {
+ Certificate cert = chain[i];
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(EntryNode.class, CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_ErrorGettingCertificateFromEntry, getAlias()),
+ e);
+ }
+ return x509Certificate;
+ }
+
+ @Override
+ protected boolean isPasswordSaved()
+ {
+ PasswordProvider pp = new PasswordProvider(getKeyStoreNode().getFile());
+ return pp.isPasswordSaved(alias);
+ }
+}