// 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 com.cloud.keystore; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.api.SecStorageSetupCommand; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.security.CertificateHelper; @Component @Local(value=KeystoreManager.class) public class KeystoreManagerImpl extends ManagerBase implements KeystoreManager { private static final Logger s_logger = Logger.getLogger(KeystoreManagerImpl.class); @Inject private KeystoreDao _ksDao; @Override public boolean validateCertificate(String certificate, String key, String domainSuffix) { if(certificate == null || certificate.isEmpty() || key == null || key.isEmpty() || domainSuffix == null || domainSuffix.isEmpty()) { s_logger.error("Invalid parameter found in (certificate, key, domainSuffix) tuple for domain: " + domainSuffix); return false; } try { String ksPassword = "passwordForValidation"; byte[] ksBits = CertificateHelper.buildAndSaveKeystore(domainSuffix, certificate, getKeyContent(key), ksPassword); KeyStore ks = CertificateHelper.loadKeystore(ksBits, ksPassword); if(ks != null) return true; s_logger.error("Unabled to construct keystore for domain: " + domainSuffix); } catch(Exception e) { s_logger.error("Certificate validation failed due to exception for domain: " + domainSuffix, e); } return false; } @Override public void saveCertificate(String name, String certificate, String key, String domainSuffix) { if(name == null || name.isEmpty() || certificate == null || certificate.isEmpty() || key == null || key.isEmpty() || domainSuffix == null || domainSuffix.isEmpty()) throw new CloudRuntimeException("invalid parameter in saveCerticate"); _ksDao.save(name, certificate, key, domainSuffix); } @Override public void saveCertificate(String name, String certificate, Integer index, String domainSuffix) { if(name == null || name.isEmpty() || certificate == null || certificate.isEmpty() || index == null || domainSuffix == null || domainSuffix.isEmpty()) throw new CloudRuntimeException("invalid parameter in saveCerticate"); _ksDao.save(name, certificate, index, domainSuffix); } @Override public byte[] getKeystoreBits(String name, String aliasForCertificateInStore, String storePassword) { assert(name != null); assert(aliasForCertificateInStore != null); assert(storePassword != null); KeystoreVO ksVo = _ksDao.findByName(name); if(ksVo == null) throw new CloudRuntimeException("Unable to find keystore " + name); List> certs = new ArrayList>(); List certChains = _ksDao.findCertChain(); for (KeystoreVO ks : certChains) { Ternary cert = new Ternary(ks.getName(), ks.getCertificate(), null); certs.add(cert); } Ternary cert = new Ternary(ksVo.getName(), ksVo.getCertificate(), getKeyContent(ksVo.getKey())); certs.add(cert); try { return CertificateHelper.buildAndSaveKeystore(certs, storePassword); } catch(KeyStoreException e) { s_logger.warn("Unable to build keystore for " + name + " due to KeyStoreException"); } catch(CertificateException e) { s_logger.warn("Unable to build keystore for " + name + " due to CertificateException"); } catch(NoSuchAlgorithmException e) { s_logger.warn("Unable to build keystore for " + name + " due to NoSuchAlgorithmException"); } catch(InvalidKeySpecException e) { s_logger.warn("Unable to build keystore for " + name + " due to InvalidKeySpecException"); } catch(IOException e) { s_logger.warn("Unable to build keystore for " + name + " due to IOException"); } return null; } @Override public SecStorageSetupCommand.Certificates getCertificates(String name) { KeystoreVO ksVo = _ksDao.findByName(name); if (ksVo == null) { return null; } String prvKey = ksVo.getKey(); String prvCert = ksVo.getCertificate(); String certChain = null; List certchains = _ksDao.findCertChain(); if (certchains.size() > 0) { StringBuilder chains = new StringBuilder(); for (KeystoreVO cert : certchains) { chains.append(cert.getCertificate()); chains.append("\n"); } certChain = chains.toString(); } SecStorageSetupCommand.Certificates certs = new SecStorageSetupCommand.Certificates(prvKey, prvCert, certChain); return certs; } private static String getKeyContent(String key) { Pattern regex = Pattern.compile("(^[\\-]+[^\\-]+[\\-]+[\\n]?)([^\\-]+)([\\-]+[^\\-]+[\\-]+$)"); Matcher m = regex.matcher(key); if(m.find()) return m.group(2); return key; } }