/* * Copyright(c) 2002 Center for E-Commerce Infrastructure Development, The * University of Hong Kong (HKU). All Rights Reserved. * * This software is licensed under the Academic Free License Version 1.0 * * Academic Free License * Version 1.0 * * This Academic Free License applies to any software and associated * documentation (the "Software") whose owner (the "Licensor") has placed the * statement "Licensed under the Academic Free License Version 1.0" immediately * after the copyright notice that applies to the Software. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of the Software (1) to use, copy, modify, merge, publish, perform, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, and (2) under patent * claims owned or controlled by the Licensor that are embodied in the Software * as furnished by the Licensor, to make, use, sell and offer for sale the * Software and derivative works thereof, subject to the following conditions: * * - Redistributions of the Software in source code form must retain all * copyright notices in the Software as furnished by the Licensor, this list * of conditions, and the following disclaimers. * - Redistributions of the Software in executable form must reproduce all * copyright notices in the Software as furnished by the Licensor, this list * of conditions, and the following disclaimers in the documentation and/or * other materials provided with the distribution. * - Neither the names of Licensor, nor the names of any contributors to the * Software, nor any of their trademarks or service marks, may be used to * endorse or promote products derived from this Software without express * prior written permission of the Licensor. * * DISCLAIMERS: LICENSOR WARRANTS THAT THE COPYRIGHT IN AND TO THE SOFTWARE IS * OWNED BY THE LICENSOR OR THAT THE SOFTWARE IS DISTRIBUTED BY LICENSOR UNDER * A VALID CURRENT LICENSE. EXCEPT AS EXPRESSLY STATED IN THE IMMEDIATELY * PRECEDING SENTENCE, THE SOFTWARE IS PROVIDED BY THE LICENSOR, CONTRIBUTORS * AND COPYRIGHT OWNERS "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE * LICENSOR, CONTRIBUTORS OR COPYRIGHT OWNERS BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE. * * This license is Copyright (C) 2002 Lawrence E. Rosen. All rights reserved. * Permission is hereby granted to copy and distribute this license without * modification. This license may not be modified without the express written * permission of its copyright owner. */ /* ===== * * $Header: /home/cvsroot/ebxml-pkg/src/hk/hku/cecid/ebms/pkg/pki/CompositeKeyStore.java,v 1.1 2005/07/28 09:36:24 dcmsze Exp $ * * Code authored by: * * kcyee [2002-05-02] * * Code reviewed by: * * username [YYYY-MM-DD] * * Remarks: * * ===== */ package hk.hku.cecid.ebms.pkg.pki; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; /** * Composite keystore which manages keystores of different types. A typical * Java keystore supports only one keystore type per file. That will be * inconvenient for applications to manage several types of keystore. Also, * this composite keystore supports managing multiple keystore files. This * can be viewed as a keystore registry, that is, this object manages a pool * of keystore files. * * @author kcyee * @version $Revision: 1.1 $ */ public class CompositeKeyStore { /** * Internal storage of the keystore file information */ protected Hashtable storage; /** * Internal storage of the aliases inside the keystore file */ protected Hashtable cache; /** * Internal storage of the keystore object */ protected Vector keystores; /** * Default constructor. The internal variables are being initialized. */ public CompositeKeyStore() { storage = new Hashtable(); cache = null; keystores = new Vector(); } /** * Adds a keystore file to the keystore management pool. * * @param keyFile the name of the keystore file * @param type the type of the keystore * @param password the password for accessing the keystore */ public void addKeyStoreFile(String keyFile, String type, char[] password) { if (keyFile != null) { File f = new File(keyFile); if (f != null && f.exists()) { addKeyStoreFile(f, type, password); } } } /** * Adds a keystore file to the keystore management pool. * * @param keyFile the keystore file * @param type the type of the keystore * @param password the password for accessing the keystore */ protected void addKeyStoreFile(File keyFile, String type, char[] password) { KeyStoreFileProp ksp = new KeyStoreFileProp(type, password); try { storage.put(keyFile.getCanonicalPath(), ksp); } catch (IOException e) {} } /** * Gets the first KeyStore object from the keystore management pool. * * @return the first KeyStore object from the keystore management pool */ public KeyStore getKeyStore() { if (cache == null) { loadCache(); } if (keystores.size() > 0) { return (KeyStore) keystores.get(0); } else { return null; } } /** * Removes a keystore file from the keystore management pool. * * @param keyFile the name of the keystore file */ public void removeKeyStoreFile(String keyFile) { removeKeyStoreFile(new File(keyFile)); } /** * Removes a keystore file from the keystore management pool. * * @param keyFile the keystore file */ protected void removeKeyStoreFile(File keyFile) { try { storage.remove(keyFile.getCanonicalPath()); } catch (IOException e) {} } /** * Gets an instance of the keystore of correct type. This function * will consider the Java version and determine whether to use * JSSE or not. For Java version 1.4 or above, JSSE is built in. * So, no need to call an external provider to create an instance * of PKCS#12 formatted keystore. Otherwise, JSSE should be used, and * we make use of dynamic binding to load the JSSE library. * * @param fileName the keystore file name to load * @param ksp other keystore parameters for loading * @return keystore instance of the correct type */ protected KeyStore loadKeyStore(String fileName, KeyStoreFileProp ksp) { KeyStore ks = null; if (ksp.getType() == null) { KeyStoreFileProp ksp_new = new KeyStoreFileProp("JKS", ksp.getPassword()); ks = loadKeyStore(fileName, ksp_new); if (ks == null) { ksp_new = new KeyStoreFileProp("PKCS12", ksp.getPassword()); ks = loadKeyStore(fileName, ksp_new); } return ks; } else if (ksp.getType().toUpperCase().equals("JKS")) { try { ks = KeyStore.getInstance("JKS"); } catch (KeyStoreException e) {} } else if (ksp.getType().toUpperCase().equals("PKCS12")) { /* if (isUsingJSSE()) { try { Class clsProv = Class.forName( "com.sun.net.ssl.internal.ssl.Provider"); Constructor c = clsProv.getConstructor(null); Provider provider = (Provider) c.newInstance(null); if (Security.getProvider(provider.getName()) == null) { Security.addProvider(provider); } } catch (ClassNotFoundException e) {} catch (NoSuchMethodException e) {} catch (InstantiationException e) {} catch (IllegalAccessException e) {} catch (InvocationTargetException e) {} try { ks = KeyStore.getInstance("PKCS12", "SunJSSE"); } catch (NoSuchProviderException e) {} catch (KeyStoreException e) {} } else { try { ks = KeyStore.getInstance("PKCS12"); } catch (KeyStoreException e) {} } */ try { Class clsProv = Class.forName( "org.bouncycastle.jce.provider.BouncyCastleProvider"); Constructor c = clsProv.getConstructor(); Provider provider = (Provider) c.newInstance(); if (Security.getProvider(provider.getName()) == null) { Security.addProvider(provider); } } catch (ClassNotFoundException e) {} catch (NoSuchMethodException e) {} catch (InstantiationException e) {} catch (IllegalAccessException e) {} catch (InvocationTargetException e) {} try { ks = KeyStore.getInstance("PKCS12", "BC"); } catch (NoSuchProviderException e) {} catch (KeyStoreException e) {} } if (ks != null) { try { ks.load(new FileInputStream(fileName), ksp.getPassword()); return ks; } catch (IOException e) {} catch (NoSuchAlgorithmException e) {} catch (CertificateException e) {} } return null; } /** * Loads the keystores pointed by this composite keystore into memory * and create a caching of aliases. */ protected void loadCache() { cache = new Hashtable(); Enumeration fileNames = storage.keys(); while (fileNames.hasMoreElements()) { String fileName = (String) fileNames.nextElement(); KeyStoreFileProp ksp = (KeyStoreFileProp) storage.get(fileName); KeyStore ks = loadKeyStore(fileName, ksp); keystores.add(ks); if (ks != null) { try { Enumeration ks_alias = ks.aliases(); while (ks_alias.hasMoreElements()) { cache.put(ks_alias.nextElement(), ks); } } catch (KeyStoreException e) {} } } } /** * Gets all the aliases of the keystores pointed by this composite * keystore. * * @return an enumeration of string, holding the aliases of the keys */ public Enumeration aliases() { if (cache == null) { loadCache(); } return cache.keys(); } /** * Determines whether a given alias exists in one of the keystores * pointed by this composite keystore or not. * * @param alias the alias of the key/certificate * @return true if the alias exists in one of the keystores, false & otherwise */ public boolean containsAlias(String alias) { if (cache == null) { loadCache(); } return (cache.get(alias) != null); } /** * Gets the certificate named by the given alias, from the collection * of keystores pointed by this composite keystore. * * @param alias the alias of the key/certificate * @return the certificate named by the given alias, null if not found * @throws KeyStoreException the keystore is corrupted */ public Certificate getCertificate(String alias) throws KeyStoreException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.getCertificate(alias); } return null; } /** * Gets the alias of the specified certificate. * * @param cert the certificate * @return the alias of the certificate, if the certificate can be found * in the collection of keystores pointed by this composite * keystore. Otherwise, null will be returned */ public String getCertificateAlias(Certificate cert) { if (cache == null) { loadCache(); } Enumeration keyStores = cache.elements(); while (keyStores.hasMoreElements()) { KeyStore ks = (KeyStore) keyStores.nextElement(); try { String alias = ks.getCertificateAlias(cert); if (alias != null) { return alias; } } catch (KeyStoreException e) {} } return null; } /** * Gets the certificate chain by the specified alias. * * @param alias the alias of the key/certificate * @return the certificate chain by the specified alias, null if not found * @throws KeyStoreException the keystore is corrupted */ public Certificate[] getCertificateChain(String alias) throws KeyStoreException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.getCertificateChain(alias); } return null; } /** * Gets the creation date of the key/certificate by the specified alias. * * @param alias the alias of the key/certificate * @return the creation date of the key/certificate by the specified alias, * null if not found * @throws KeyStoreException the keystore is corrupted */ public Date getCreationDate(String alias) throws KeyStoreException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.getCreationDate(alias); } return null; } /** * Gets the key by the specified alias. A password should be given also * to retrieve the key. * * @param alias the alias of the key/certificate * @param password the password to retrieve the key * @return the key specified by the alias, null if not found * @throws KeyStoreException the keystore is corrupted * @throws NoSuchAlgorithmException the keystore cannot be read * @throws UnrecoverableKeyException the keystore cannot be read */ public Key getKey(String alias, char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.getKey(alias, password); } return null; } /** * Determines whether the specified alias is specifying a certificate * or not. * * @param alias the alias of the key/certificate * @throws KeyStoreException the keystore is corrupted */ public boolean isCertificateEntry(String alias) throws KeyStoreException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.isCertificateEntry(alias); } return false; } /** * Determines whether the specified alias is specifying a key * or not. * * @param alias the alias of the key/certificate * @throws KeyStoreException the keystore is corrupted */ public boolean isKeyEntry(String alias) throws KeyStoreException { if (cache == null) { loadCache(); } KeyStore ks = (KeyStore) cache.get(alias); if (ks != null) { return ks.isKeyEntry(alias); } return false; } /** * Gets the total number of keys/certificates in all the keystores * pointed by this composite keystore. * * @return the total number of keys/certificates */ public int size() { if (cache == null) { loadCache(); } return cache.size(); } /** * Loads the composite keystore from a persistent file in the file * system. * * @param storeFileName the name of the composite keystore persistent file * @throws InitializationException the persistent file is corrupted */ public void load(String storeFileName) throws InitializationException { load(new File(storeFileName)); } /** * Loads the composite keystore from a persistent file in the file * system. * * @param storeFile the composite keystore persistent file * @throws InitializationException the persistent file is corrupted */ public void load(File storeFile) throws InitializationException { try { ObjectInputStream ois = new ObjectInputStream( new FileInputStream(storeFile)); storage = (Hashtable) ois.readObject(); ois.close(); } catch (FileNotFoundException e) { storage = null; throw new InitializationException("FileNotFound Exception\n" + e.getMessage()); } catch (IOException e) { storage = null; throw new InitializationException("IO Exception\n" + e.getMessage()); } catch (ClassNotFoundException e) { storage = null; throw new InitializationException("ClassNotFound Exception\n" + e.getMessage()); } } /** * Stores the composite keystore to a persistent file in the file * system. * * @param storeFileName the name of the composite keystore persistent file * @throws StoreException the composite keystore is not successfully stored */ public void store(String storeFileName) throws StoreException { store(new File(storeFileName)); } /** * Stores the composite keystore to a persistent file in the file * system. * * @param storeFile the composite keystore persistent file * @throws StoreException the composite keystore is not successfully stored */ public void store(File storeFile) throws StoreException { try { ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(storeFile)); oos.writeObject(storage); oos.close(); } catch (FileNotFoundException e) { throw new StoreException("FileNotFound Exception\n" + e.getMessage()); } catch (IOException e) { throw new StoreException("IO Exception\n" + e.getMessage()); } } }