/***************************************************************************
* Copyright (c) 2012-2015 VMware, Inc. All Rights Reserved.
* Licensed 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.vmware.aurora.security;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.log4j.Logger;
import com.vmware.aurora.exception.CertificateMgmtException;
import com.vmware.aurora.global.Configuration;
import com.vmware.aurora.util.AuAssert;
/*
* CMS key store for storing all sorts of secrets. The file is located in the
* default resource directory.
*
* The Aurora CMS KeyStore was generated by /opt/aurora/etc/postinstall.d/30-cms
*/
public class CmsKeyStore {
private static Logger logger = Logger.getLogger(CmsKeyStore.class);
private static ReadWriteLock lock = new ReentrantReadWriteLock();
static KeyStore keyStore = null;
static private String cmsKeyStorePath;
static private String keyStorePswd;
static private String cmsKeyPswd;
static private String vcExtPswd;
private static String cmsKeyAlias;
private static final String CMS_KEYSTORE = "cms.keystore";
private static final String CMS_KEYSTORE_ALIAS = "cms.keystore_alias";
public static final String CMS_KEYSTORE_PSWD = "cms.keystore_pswd";
static final public String VC_EXT_KEY = "vc_ext";
public static final String CMS_AUTO_KEY = "datacloud";
public static final String CMS_ROOT_CA = "rootCA";
static {
try {
cmsKeyStorePath = Configuration.getString(CMS_KEYSTORE, "/opt/aurora/cms/cms.key");
logger.info("cmsKeyStorePath ========"+cmsKeyStorePath);
keyStorePswd = Configuration.getString(CMS_KEYSTORE_PSWD);
cmsKeyPswd = Configuration.getString(CMS_KEYSTORE_PSWD);
vcExtPswd = Configuration.getString(CMS_KEYSTORE_PSWD);
cmsKeyAlias = Configuration.getString(CMS_KEYSTORE_ALIAS);
logger.info("cmsKeyAlias ========"+cmsKeyAlias);
keyStore = loadKeyStore();
} catch (Exception e) {
logger.info("cannot load cms keystore", e);
}
}
public static String getCmsKeyAlias() {
return cmsKeyAlias;
}
public static Lock getWriteLock() {
logger.debug("Get CMS keystore write lock");
return lock.writeLock();
}
public static Lock getReadLock() {
logger.debug("Get CMS keystore read lock");
return lock.readLock();
}
public static KeyStore loadKeyStore()
throws NoSuchAlgorithmException,
CertificateException,
IOException,
KeyStoreException,
InterruptedException {
KeyStore store = null;
Lock lock = getReadLock();
if (!lock.tryLock(10, TimeUnit.MINUTES)) {
throw CertificateMgmtException.ACQUIRE_TRUST_LOCK_TIMEOUT();
}
try {
store = JksKeyStoreUtil.loadKeyStore(cmsKeyStorePath, keyStorePswd);
} finally {
lock.unlock();
}
return store;
}
public static String getKeyStoreFilePath() {
return cmsKeyStorePath;
}
public static String getKeyStorePassword() {
return keyStorePswd;
}
public static String getCMSKeyPassword() {
return cmsKeyPswd;
}
public static String getVCExtPassword() {
return vcExtPswd;
}
public static KeyStore setCmsKey(String alias,
Key key,
Certificate[] certChain)
throws KeyStoreException,
NoSuchAlgorithmException,
CertificateException,
IOException,
InterruptedException {
KeyStore store = null;
Lock lock = getWriteLock();
if (!lock.tryLock(10, TimeUnit.MINUTES)) {
throw CertificateMgmtException.ACQUIRE_TRUST_LOCK_TIMEOUT();
}
try {
store = JksKeyStoreUtil.loadKeyStore(cmsKeyStorePath, keyStorePswd);
store.setKeyEntry(alias,
key,
CmsKeyStore.getCMSKeyPassword().toCharArray(),
certChain);
JksKeyStoreUtil.serializeKeyStore(cmsKeyStorePath, store, keyStorePswd);
} finally {
lock.unlock();
}
return store;
}
public static KeyStore removeCmsKey(String alias)
throws KeyStoreException,
NoSuchAlgorithmException,
CertificateException,
IOException,
InterruptedException {
KeyStore store = null;
Lock lock = getWriteLock();
if (!lock.tryLock(10, TimeUnit.MINUTES)) {
throw CertificateMgmtException.ACQUIRE_TRUST_LOCK_TIMEOUT();
}
try {
store = JksKeyStoreUtil.loadKeyStore(cmsKeyStorePath, keyStorePswd);
if (store.containsAlias(alias)) {
store.deleteEntry(alias);
JksKeyStoreUtil.serializeKeyStore(cmsKeyStorePath, store, keyStorePswd);
}
} finally {
lock.unlock();
}
return store;
}
static public KeyStore getKeyStore() {
return keyStore;
}
static public Certificate getCertificate(String alias) throws KeyStoreException {
AuAssert.check(keyStore != null);
return keyStore.getCertificate(alias);
}
public static String parseThumbPrint(Certificate cert)
throws NoSuchAlgorithmException, CertificateEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] der = cert.getEncoded();
md.update(der);
byte[] digest = md.digest();
return hexify(digest);
}
private static String hexify (byte bytes[]) {
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
char separator = ':';
StringBuffer buf = new StringBuffer(bytes.length * 2);
int length = bytes.length;
for (int i = 0; i < length; ++i) {
buf.append(hexDigits[(bytes[i] & 0xf0) >> 4]);
buf.append(hexDigits[bytes[i] & 0x0f]);
if (i != length - 1) {
buf.append(separator);
}
}
return buf.toString();
}
}