// 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.cloudstack.framework.security.keys; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.inject.Inject; import javax.net.ssl.KeyManager; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; /** * To be perfectly honest, I'm not sure why we need this class. This used * to be in ManagementServerImpl. I moved the functionality because it seems * many features will need this. However, the right thing will be for setup * and upgrade to take care of key generation. Here, the methods appear to * mainly be used for dynamic generation. I added this class because after * talking to Kelven, we think there will be other functionalities we need * to centralize to this class. We'll see how that works out. * * There's multiple problems here that we need to fix. * - Multiple servers can be generating keys. This is not atomic. * - The functionality of generating the keys should be moved over to setup/upgrade. * */ public class KeysManagerImpl implements KeysManager, Configurable { private static final Logger s_logger = Logger.getLogger(KeysManagerImpl.class); @Inject ConfigurationDao _configDao; @Inject ConfigDepot _configDepot; @Override public String getHashKey() { String value = HashKey.value(); if (value == null) { _configDao.getValueAndInitIfNotExist(HashKey.key(), HashKey.category(), getBase64EncodedRandomKey(128), HashKey.description()); } return HashKey.value(); } @Override public String getEncryptionKey() { String value = EncryptionKey.value(); if (value == null) { _configDao.getValueAndInitIfNotExist(EncryptionKey.key(), EncryptionKey.category(), getBase64EncodedRandomKey(128), EncryptionKey.description()); } return EncryptionKey.value(); } @Override public String getEncryptionIV() { String value = EncryptionIV.value(); if (value == null) { _configDao.getValueAndInitIfNotExist(EncryptionIV.key(), EncryptionIV.category(), getBase64EncodedRandomKey(128), EncryptionIV.description()); } return EncryptionIV.value(); } private static String getBase64EncodedRandomKey(int nBits) { SecureRandom random; try { random = SecureRandom.getInstance("SHA1PRNG"); byte[] keyBytes = new byte[nBits / 8]; random.nextBytes(keyBytes); return Base64.encodeBase64URLSafeString(keyBytes); } catch (NoSuchAlgorithmException e) { s_logger.error("Unhandled exception: ", e); } return null; } @Override @DB public void resetEncryptionKeyIV() { SearchBuilder<ConfigurationVO> sb = _configDao.createSearchBuilder(); sb.and("name1", sb.entity().getName(), SearchCriteria.Op.EQ); sb.or("name2", sb.entity().getName(), SearchCriteria.Op.EQ); sb.done(); SearchCriteria<ConfigurationVO> sc = sb.create(); sc.setParameters("name1", EncryptionKey.key()); sc.setParameters("name2", EncryptionIV.key()); _configDao.expunge(sc); } @Override public String getConfigComponentName() { return KeyManager.class.getSimpleName(); } @Override public ConfigKey<?>[] getConfigKeys() { return new ConfigKey<?>[] {EncryptionKey, EncryptionIV, HashKey}; } }