/* * 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.core; import java.io.File; import java.io.IOException; import java.security.KeyStore; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.motorola.studio.android.common.log.StudioLogger; import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException; import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore; import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode; import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreRootNode; import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView; /** * Provides a common interface to manipulate keystores. * Other plugins need to use it (to avoid knowing {@link KeyStoreRootNode} model and {@link SaveStateManager}). * * The {@link KeystoreManagerView} also need to call its methods to guarantee persistence of its operations. */ public class KeyStoreManager { public static final String KEYSTORE_TYPE_PKCS12 = "PKCS12"; public static final String KEYSTORE_TYPE_JCEKS = "JCEKS"; public static final String KEYSTORE_TYPE_JKS = "JKS"; private static final String ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE = "Error to access keystore mapping persistence"; private static KeyStoreManager _instance; private List<IKeyStore> keyStores = null; /** * This class is a singleton. * @return The unique instance of this class. * */ public synchronized static KeyStoreManager getInstance() { if (_instance == null) { _instance = new KeyStoreManager(); } return _instance; } private KeyStoreManager() { } /** * Add a new keystore to the manager. * @param keystore The keystore to be added. * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped. */ public void addKeyStore(IKeyStore keystore) throws KeyStoreManagerException { SaveStateManager manager = null; try { manager = SaveStateManager.getInstance(); manager.addEntry(keystore.getFile(), keystore.getType()); getKeyStores().add(keystore); } catch (Exception e) { throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e); } } /** * Remove a keystore from the manager. * @param keystore The keystore to be removed. * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped. */ public void removeKeyStore(IKeyStore keystore) throws KeyStoreManagerException { SaveStateManager manager = null; try { manager = SaveStateManager.getInstance(); manager.removeEntry(keystore.getFile()); getKeyStores().remove(keystore); } catch (Exception e) { throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e); } } /** * Set the date which the keystore was added to a backup file. * @param keyStore The keystore to be set. * @param backupDate The date of the backup. * @throws KeyStoreManagerException If there were problems while persisting the information. * */ public void setBackupDate(IKeyStore keyStore, Date backupDate) throws KeyStoreManagerException { if ((keyStore != null) && (backupDate != null)) { try { SaveStateManager manager = SaveStateManager.getInstance(); manager.setBackupDate(keyStore.getFile(), backupDate); } catch (Exception e) { throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e); } } } /** * Update the type of a managed keystore, using solely the information provided by the keystore. * @param keystore The keystore which type needs to be updated. * @throws KeyStoreManagerException If there were problems while persisting the information. * */ public void updateKeyStoreType(IKeyStore keyStore) throws KeyStoreManagerException { SaveStateManager manager; try { manager = SaveStateManager.getInstance(); if (manager.isKeystoreMapped(keyStore.getFile())) { manager.addEntry(keyStore.getFile(), keyStore.getType()); } } catch (IOException e) { throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e); } } /** * @return The list of mapped keystores in the persistence, or empty list if there is no keystore mapped. * @throws KeyStoreManagerException if an error occurs to access persistence file where keystores are mapped. */ public List<IKeyStore> getKeyStores() throws KeyStoreManagerException { if (keyStores == null) { keyStores = new ArrayList<IKeyStore>(); SaveStateManager manager = null; try { manager = SaveStateManager.getInstance(); if (manager.getMappedKeystores() != null) { for (File keystoreFile : manager.getMappedKeystores()) { SaveStateManager.ViewStateEntry stateEntry = manager.getEntry(keystoreFile); if (stateEntry != null) { IKeyStore keyStoreNode = new KeyStoreNode(keystoreFile); keyStoreNode.setType(stateEntry.getKeystoreType()); keyStoreNode.setLastBackupDate(stateEntry.getBackupDate()); keyStores.add(keyStoreNode); } } } } catch (IOException e) { throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e); } } return keyStores; } /** * Check if a keystore file is already mapped. * The input parameter is a File, instead of a String, to ensure that File.getCanonicalPath() will be used in the filenames comparison. * @param keystoreFile A file representing the keystore. * @return True if the file is already mapped, false otherwise. * */ public boolean isKeystoreMapped(File keystoreFile) { boolean result = false; SaveStateManager manager = null; try { manager = SaveStateManager.getInstance(); if (manager.getMappedKeystores() != null) { for (File mappedKeystoreFile : manager.getMappedKeystores()) { if (mappedKeystoreFile.getCanonicalPath().equals( keystoreFile.getCanonicalPath())) { result = true; break; } } } } catch (IOException e) { result = false; StudioLogger .error(getClass(), "IOException while trying to check if a file is mapped on Signing and Keys view."); } return result; } /** * The current available keystore types are: * <ul> * <li>JKS</li> * <li>JCEKS</li> * <li>PKCS12</li> * </ul> * @return The list of available keystore types. * */ public List<String> getAvailableTypes() { List<String> availableKeystoreTypes = new ArrayList<String>(); availableKeystoreTypes.add(KEYSTORE_TYPE_JKS); availableKeystoreTypes.add(KEYSTORE_TYPE_JCEKS); availableKeystoreTypes.add(KEYSTORE_TYPE_PKCS12); if (!availableKeystoreTypes.contains(getDefaultType())) { availableKeystoreTypes.add(getDefaultType()); } return availableKeystoreTypes; } /** * When no store type is specified, the manager define a type that should be used as the default one. * @return The default keystore type used in the Signing and Keys view. * */ public String getDefaultType() { return KeyStore.getDefaultType().toUpperCase(); } /** * Create a new keystore given a file, a store type and a password. */ public static IKeyStore createKeyStore(File keyStoreFile, String keyStoreType, char[] password) throws KeyStoreManagerException { IKeyStore keyStoreNode = null; try { KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, keyStoreType, password); keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore); } catch (InvalidPasswordException e) { StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage()); } return keyStoreNode; } /** * Create a new keystore given a file and a password. * The store type is set to be the default. */ public static IKeyStore createKeyStore(File keyStoreFile, char[] password) throws KeyStoreManagerException { IKeyStore keyStoreNode = null; try { KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, password); keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore); } catch (InvalidPasswordException e) { StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage()); } return keyStoreNode; } }