/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.karaf.jaas.config.impl; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.net.URL; import java.net.URI; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import org.apache.karaf.jaas.config.KeystoreInstance; import org.apache.karaf.jaas.config.KeystoreIsLocked; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResourceKeystoreInstance implements KeystoreInstance { private final Logger logger = LoggerFactory.getLogger(ResourceKeystoreInstance.class); private static final String JKS = "JKS"; private String name; private int rank; private URL path; private String keystorePassword; private Map keyPasswords = new HashMap(); private File keystoreFile; // Only valid after startup and if the resource points to a file // The following variables are the state of the keystore, which should be chucked if the file on disk changes private List privateKeys = new ArrayList(); private List trustCerts = new ArrayList(); private KeyStore keystore; private long keystoreReadDate = Long.MIN_VALUE; /** * @return the keystoreName */ public String getName() { return name; } /** * @param keystoreName the keystoreName to set */ public void setName(String keystoreName) { this.name = keystoreName; } /** * @return the rank */ public int getRank() { return rank; } /** * @param rank the rank to set */ public void setRank(int rank) { this.rank = rank; } /** * @return the keystorePath */ public URL getPath() { return path; } /** * @param keystorePath the keystorePath to set. * @throws IOException in case of failure while setting the path. */ public void setPath(URL keystorePath) throws IOException { this.path = keystorePath; if (keystorePath.getProtocol().equals("file")) { URI uri = URI.create(keystorePath.toString().replace(" ", "%20")); this.keystoreFile = new File(uri.getSchemeSpecificPart()); } } /** * @param keystorePassword the keystorePassword to set */ public void setKeystorePassword(String keystorePassword) { this.keystorePassword = keystorePassword; } /** * @param keyPasswords the keyPasswords to set */ public void setKeyPasswords(String keyPasswords) { if (keyPasswords != null) { String[] keys = keyPasswords.split("\\]\\!\\["); for (int i = 0; i < keys.length; i++) { String key = keys[i]; int pos = key.indexOf('='); if (pos > 0) { this.keyPasswords.put(key.substring(0, pos), key.substring(pos + 1).toCharArray()); } } } } public Certificate getCertificate(String alias) { if (!loadKeystoreData()) { return null; } try { return keystore.getCertificate(alias); } catch (KeyStoreException e) { logger.error("Unable to read certificate from keystore", e); } return null; } public String getCertificateAlias(Certificate cert) { if (!loadKeystoreData()) { return null; } try { return keystore.getCertificateAlias(cert); } catch (KeyStoreException e) { logger.error("Unable to read retrieve alias for given certificate from keystore", e); } return null; } public Certificate[] getCertificateChain(String alias) { if (!loadKeystoreData()) { return null; } try { return keystore.getCertificateChain(alias); } catch (KeyStoreException e) { logger.error("Unable to read certificate chain from keystore", e); } return null; } public KeyManager[] getKeyManager(String algorithm, String keyAlias) throws KeystoreIsLocked, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException { if (isKeystoreLocked()) { throw new KeystoreIsLocked("Keystore '" + name + "' is locked."); } if (!loadKeystoreData()) { return null; } KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm); keyFactory.init(keystore, (char[]) keyPasswords.get(keyAlias)); return keyFactory.getKeyManagers(); } public PrivateKey getPrivateKey(String alias) { if (!loadKeystoreData()) { return null; } try { if (isKeyLocked(alias)) { return null; } Key key = keystore.getKey(alias, (char[]) keyPasswords.get(alias)); if (key instanceof PrivateKey) { return (PrivateKey) key; } } catch (KeyStoreException e) { logger.error("Unable to read private key from keystore", e); } catch (NoSuchAlgorithmException e) { logger.error("Unable to read private key from keystore", e); } catch (UnrecoverableKeyException e) { logger.error("Unable to read private key from keystore", e); } return null; } public TrustManager[] getTrustManager(String algorithm) throws KeyStoreException, NoSuchAlgorithmException, KeystoreIsLocked { if (isKeystoreLocked()) { throw new KeystoreIsLocked("Keystore '" + name + "' is locked."); } if (!loadKeystoreData()) { return null; } TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm); trustFactory.init(keystore); return trustFactory.getTrustManagers(); } public boolean isKeyLocked(String keyAlias) { return keyPasswords.get(keyAlias) == null; } public boolean isKeystoreLocked() { return keystorePassword == null; } public String[] listPrivateKeys() { if (!loadKeystoreData()) { return null; } return (String[]) privateKeys.toArray(new String[privateKeys.size()]); } public String[] listTrustCertificates() { if (!loadKeystoreData()) { return null; } return (String[]) trustCerts.toArray(new String[trustCerts.size()]); } // ==================== Internals ===================== private boolean loadKeystoreData() { // Check to reload the data if needed if (keystoreFile != null && keystoreReadDate >= keystoreFile.lastModified()) { return true; } // If not a file, just not reload the data if it has already been loaded if (keystoreFile == null && keystore != null) { return true; } // Check if the file is invalid if (keystoreFile != null && (!keystoreFile.exists() || !keystoreFile.canRead())) { throw new IllegalArgumentException("Invalid keystore file (" + path + " = " + keystoreFile.getAbsolutePath() + ")"); } // Load the keystore data try { keystoreReadDate = System.currentTimeMillis(); privateKeys.clear(); trustCerts.clear(); if (keystore == null) { keystore = KeyStore.getInstance(JKS); } InputStream in = new BufferedInputStream(path.openStream()); keystore.load(in, keystorePassword == null ? new char[0] : keystorePassword.toCharArray()); in.close(); Enumeration aliases = keystore.aliases(); while (aliases.hasMoreElements()) { String alias = (String) aliases.nextElement(); if (keystore.isKeyEntry(alias)) { privateKeys.add(alias); } else if (keystore.isCertificateEntry(alias)) { trustCerts.add(alias); } } return true; } catch (KeyStoreException e) { logger.error("Unable to open keystore with provided password", e); } catch (IOException e) { logger.error("Unable to open keystore with provided password", e); } catch (NoSuchAlgorithmException e) { logger.error("Unable to open keystore with provided password", e); } catch (CertificateException e) { logger.error("Unable to open keystore with provided password", e); } return false; } }