001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.servicemix.jbi.security.keystore.impl;
018:
019: import java.io.BufferedInputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.security.Key;
025: import java.security.KeyStore;
026: import java.security.KeyStoreException;
027: import java.security.NoSuchAlgorithmException;
028: import java.security.PrivateKey;
029: import java.security.UnrecoverableKeyException;
030: import java.security.cert.Certificate;
031: import java.security.cert.CertificateException;
032: import java.util.ArrayList;
033: import java.util.Enumeration;
034: import java.util.HashMap;
035: import java.util.List;
036: import java.util.Map;
037:
038: import javax.net.ssl.KeyManager;
039: import javax.net.ssl.KeyManagerFactory;
040: import javax.net.ssl.TrustManager;
041: import javax.net.ssl.TrustManagerFactory;
042:
043: import org.apache.commons.logging.Log;
044: import org.apache.commons.logging.LogFactory;
045: import org.apache.servicemix.jbi.security.keystore.KeystoreInstance;
046: import org.apache.servicemix.jbi.security.keystore.KeystoreIsLocked;
047: import org.springframework.core.io.Resource;
048:
049: /**
050: *
051: * @org.apache.xbean.XBean element="keystore"
052: */
053: public class FileKeystoreInstance implements KeystoreInstance {
054:
055: private static final Log LOG = LogFactory
056: .getLog(FileKeystoreInstance.class);
057: private static final String JKS = "JKS";
058:
059: private Resource path;
060: private String name;
061: private String keystorePassword;
062: private Map keyPasswords = new HashMap();
063: private File keystoreFile; // Only valid after startup
064:
065: // The following variables are the state of the keystore, which should be chucked if the file on disk changes
066: private List privateKeys = new ArrayList();
067: private List trustCerts = new ArrayList();
068: private KeyStore keystore;
069: private long keystoreReadDate = Long.MIN_VALUE;
070:
071: /**
072: * @param keyPasswords the keyPasswords to set
073: */
074: public void setKeyPasswords(String keyPasswords) {
075: if (keyPasswords != null) {
076: String[] keys = keyPasswords.split("\\]\\!\\[");
077: for (int i = 0; i < keys.length; i++) {
078: String key = keys[i];
079: int pos = key.indexOf('=');
080: this .keyPasswords.put(key.substring(0, pos), key
081: .substring(pos + 1).toCharArray());
082: }
083: }
084: }
085:
086: /**
087: * @return the keystoreName
088: */
089: public String getName() {
090: return name;
091: }
092:
093: /**
094: * @param keystoreName the keystoreName to set
095: */
096: public void setName(String keystoreName) {
097: this .name = keystoreName;
098: }
099:
100: /**
101: * @param keystorePassword the keystorePassword to set
102: */
103: public void setKeystorePassword(String keystorePassword) {
104: this .keystorePassword = keystorePassword;
105: }
106:
107: /**
108: * @return the keystorePath
109: */
110: public Resource getPath() {
111: return path;
112: }
113:
114: /**
115: * @param keystorePath the keystorePath to set
116: */
117: public void setPath(Resource keystorePath) throws IOException {
118: this .path = keystorePath;
119: this .keystoreFile = keystorePath.getFile();
120: }
121:
122: public Certificate getCertificate(String alias) {
123: if (!loadKeystoreData()) {
124: return null;
125: }
126: try {
127: return keystore.getCertificate(alias);
128: } catch (KeyStoreException e) {
129: LOG.error("Unable to read certificate from keystore", e);
130: }
131: return null;
132: }
133:
134: public String getCertificateAlias(Certificate cert) {
135: if (!loadKeystoreData()) {
136: return null;
137: }
138: try {
139: return keystore.getCertificateAlias(cert);
140: } catch (KeyStoreException e) {
141: LOG
142: .error(
143: "Unable to read retrieve alias for given certificate from keystore",
144: e);
145: }
146: return null;
147: }
148:
149: public Certificate[] getCertificateChain(String alias) {
150: if (!loadKeystoreData()) {
151: return null;
152: }
153: try {
154: return keystore.getCertificateChain(alias);
155: } catch (KeyStoreException e) {
156: LOG.error("Unable to read certificate chain from keystore",
157: e);
158: }
159: return null;
160: }
161:
162: public KeyManager[] getKeyManager(String algorithm, String keyAlias)
163: throws KeystoreIsLocked, NoSuchAlgorithmException,
164: KeyStoreException, UnrecoverableKeyException {
165: if (isKeystoreLocked()) {
166: throw new KeystoreIsLocked("Keystore '" + name
167: + "' is locked; please unlock it in the console.");
168: }
169: if (keystore == null
170: || keystoreReadDate < keystoreFile.lastModified()) {
171: loadKeystoreData();
172: }
173: KeyManagerFactory keyFactory = KeyManagerFactory
174: .getInstance(algorithm);
175: keyFactory.init(keystore, (char[]) keyPasswords.get(keyAlias));
176: return keyFactory.getKeyManagers();
177: }
178:
179: public PrivateKey getPrivateKey(String alias) {
180: if (!loadKeystoreData()) {
181: return null;
182: }
183: try {
184: if (isKeyLocked(alias)) {
185: return null;
186: }
187: Key key = keystore.getKey(alias, (char[]) keyPasswords
188: .get(alias));
189: if (key instanceof PrivateKey) {
190: return (PrivateKey) key;
191: }
192: } catch (KeyStoreException e) {
193: LOG.error("Unable to read private key from keystore", e);
194: } catch (NoSuchAlgorithmException e) {
195: LOG.error("Unable to read private key from keystore", e);
196: } catch (UnrecoverableKeyException e) {
197: LOG.error("Unable to read private key from keystore", e);
198: }
199: return null;
200: }
201:
202: public TrustManager[] getTrustManager(String algorithm)
203: throws KeyStoreException, NoSuchAlgorithmException,
204: KeystoreIsLocked {
205: if (isKeystoreLocked()) {
206: throw new KeystoreIsLocked("Keystore '" + name
207: + "' is locked; please unlock it in the console.");
208: }
209: if (!loadKeystoreData()) {
210: return null;
211: }
212: TrustManagerFactory trustFactory = TrustManagerFactory
213: .getInstance(algorithm);
214: trustFactory.init(keystore);
215: return trustFactory.getTrustManagers();
216: }
217:
218: public boolean isKeyLocked(String keyAlias) {
219: return keyPasswords.get(keyAlias) == null;
220: }
221:
222: public boolean isKeystoreLocked() {
223: return keystorePassword == null;
224: }
225:
226: public String[] listPrivateKeys() {
227: if (!loadKeystoreData()) {
228: return null;
229: }
230: return (String[]) privateKeys.toArray(new String[privateKeys
231: .size()]);
232: }
233:
234: public String[] listTrustCertificates() {
235: if (!loadKeystoreData()) {
236: return null;
237: }
238: return (String[]) trustCerts.toArray(new String[trustCerts
239: .size()]);
240: }
241:
242: // ==================== Internals =====================
243:
244: private boolean loadKeystoreData() {
245: if (keystoreFile == null) {
246: throw new IllegalArgumentException("keystorePath not set");
247: }
248: if (keystoreReadDate >= keystoreFile.lastModified()) {
249: return true;
250: }
251: if (!keystoreFile.exists() || !keystoreFile.canRead()) {
252: throw new IllegalArgumentException(
253: "Invalid keystore file (" + path + " = "
254: + keystoreFile.getAbsolutePath() + ")");
255: }
256: try {
257: keystoreReadDate = System.currentTimeMillis();
258: privateKeys.clear();
259: trustCerts.clear();
260: if (keystore == null) {
261: keystore = KeyStore.getInstance(JKS);
262: }
263: InputStream in = new BufferedInputStream(
264: new FileInputStream(keystoreFile));
265: keystore.load(in, keystorePassword == null ? new char[0]
266: : keystorePassword.toCharArray());
267: in.close();
268: Enumeration aliases = keystore.aliases();
269: while (aliases.hasMoreElements()) {
270: String alias = (String) aliases.nextElement();
271: if (keystore.isKeyEntry(alias)) {
272: privateKeys.add(alias);
273: } else if (keystore.isCertificateEntry(alias)) {
274: trustCerts.add(alias);
275: }
276: }
277: return true;
278: } catch (KeyStoreException e) {
279: LOG.error("Unable to open keystore with provided password",
280: e);
281: } catch (IOException e) {
282: LOG.error("Unable to open keystore with provided password",
283: e);
284: } catch (NoSuchAlgorithmException e) {
285: LOG.error("Unable to open keystore with provided password",
286: e);
287: } catch (CertificateException e) {
288: LOG.error("Unable to open keystore with provided password",
289: e);
290: }
291: return false;
292: }
293:
294: }
|