diff --git a/core/org.wso2.carbon.core/pom.xml b/core/org.wso2.carbon.core/pom.xml
index 90cb6e262e1..81c94aaf025 100644
--- a/core/org.wso2.carbon.core/pom.xml
+++ b/core/org.wso2.carbon.core/pom.xml
@@ -94,6 +94,10 @@
org.wso2.carbon
org.wso2.carbon.utils
+
+ org.wso2.carbon.utils
+ org.wso2.carbon.database.utils
+
org.wso2.carbon.crypto
org.wso2.carbon.crypto.api
@@ -248,6 +252,7 @@
org.wso2.carbon.registry.core.service,
org.wso2.carbon.user.core.*; version=0.0.0,
org.bouncycastle.*; version="${imp.pkg.version.bcp}",
+ org.wso2.carbon.database.utils.*;version="${org.wso2.carbon.database.utils.version.range}",
*;resolution:=optional
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtComponent.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtComponent.java
new file mode 100644
index 00000000000..0eaffecce2c
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtComponent.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.internal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.wso2.carbon.base.ServerConfiguration;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.KeyStoreManagementService;
+import org.wso2.carbon.core.keystore.KeyStoreManagementServiceImpl;
+import org.wso2.carbon.user.core.service.RealmService;
+import org.wso2.carbon.utils.ConfigurationContextService;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.KEYSTORE_DATASOURCE;
+
+@Component(
+ name = "keystore.mgt.service.component",
+ immediate = true
+)
+public class KeyStoreMgtComponent {
+
+ private static final Log log = LogFactory.getLog(KeyStoreMgtComponent.class);
+
+ @Activate
+ protected void activate(ComponentContext ctxt) {
+
+ try {
+ initDataSource();
+ BundleContext bundleCtx = ctxt.getBundleContext();
+ bundleCtx.registerService(KeyStoreManagementService.class.getName(), new KeyStoreManagementServiceImpl(),
+ null);
+ log.debug("Security Mgt bundle is activated");
+ } catch (KeyStoreManagementException e) {
+ log.error("Failed to activate SecurityMgtServiceComponent", e);
+ }
+ }
+
+ @Deactivate
+ protected void deactivate(ComponentContext ctxt) {
+
+ log.debug("Security Mgt bundle is deactivated");
+ }
+
+ @Reference(
+ name = "config.context.service",
+ service = ConfigurationContextService.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetConfigurationContextService"
+ )
+ protected void setConfigurationContextService(ConfigurationContextService contextService) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Setting the ConfigurationContext");
+ }
+ KeyStoreMgtDataHolder.setConfigurationContextService(contextService);
+ }
+
+ @Reference(
+ name = "user.realmservice.default",
+ service = RealmService.class,
+ cardinality = ReferenceCardinality.MANDATORY,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetRealmService"
+ )
+ protected void setRealmService(RealmService realmService) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Setting the RealmService");
+ }
+ KeyStoreMgtDataHolder.setRealmService(realmService);
+ }
+
+ protected void unsetRealmService(RealmService realmService) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Unsetting the RealmService");
+ }
+ KeyStoreMgtDataHolder.setRealmService(null);
+ }
+
+ protected void unsetConfigurationContextService(ConfigurationContextService contextService) {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Unsetting the ConfigurationContext");
+ }
+ KeyStoreMgtDataHolder.setConfigurationContextService(null);
+ }
+
+ private void initDataSource() throws KeyStoreManagementException {
+
+ String dataSourceName = ServerConfiguration.getInstance()
+ .getFirstProperty(KEYSTORE_DATASOURCE);
+ Context ctx = null;
+ try {
+ ctx = new InitialContext();
+ DataSource dataSource = (DataSource) ctx.lookup(dataSourceName);
+ KeyStoreMgtDataHolder.setDataSource(dataSource);
+ } catch (NamingException e) {
+ throw new KeyStoreManagementException(e.getMessage());
+ }
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtDataHolder.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtDataHolder.java
new file mode 100644
index 00000000000..b6948659c39
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/internal/KeyStoreMgtDataHolder.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.internal;
+
+import org.apache.axis2.context.ConfigurationContext;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.registry.core.Resource;
+import org.wso2.carbon.user.core.service.RealmService;
+import org.wso2.carbon.utils.ConfigurationContextService;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+public class KeyStoreMgtDataHolder {
+
+ private static RealmService realmService;
+ private static ConfigurationContextService ccService;
+ private static DataSource dataSource;
+ private static Map policyResourceMap = new HashMap<>();
+
+ private KeyStoreMgtDataHolder() {
+
+ }
+
+ public static RealmService getRealmService() throws KeyStoreManagementException {
+
+ if (realmService == null) {
+ throw new KeyStoreManagementException("The main user realm is null");
+ }
+ return realmService;
+ }
+
+ public static void setRealmService(RealmService realmService) {
+
+ KeyStoreMgtDataHolder.realmService = realmService;
+ }
+
+ public static ConfigurationContext getConfigurationContext() throws Exception {
+
+ if (ccService == null) {
+ throw new KeyStoreManagementException("CC service is null");
+ }
+ return ccService.getClientConfigContext();
+ }
+
+ public static void setConfigurationContextService(ConfigurationContextService ccService) {
+
+ KeyStoreMgtDataHolder.ccService = ccService;
+ }
+
+ public static void addPolicyResource(String location, Resource resource) {
+
+ policyResourceMap.put(location, resource);
+ }
+
+ public static DataSource getDataSource() {
+
+ return dataSource;
+ }
+
+ public static void setDataSource(DataSource dataSource) {
+
+ KeyStoreMgtDataHolder.dataSource = dataSource;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreAdmin.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreAdmin.java
new file mode 100644
index 00000000000..e05db86dc4e
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreAdmin.java
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+import org.apache.axiom.om.util.Base64;
+import org.apache.axis2.context.MessageContext;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.base.ServerConfiguration;
+import org.wso2.carbon.core.RegistryResources;
+import org.wso2.carbon.core.keystore.util.KeyStoreMgtUtil;
+import org.wso2.carbon.core.util.CryptoException;
+import org.wso2.carbon.core.util.CryptoUtil;
+import org.wso2.carbon.core.util.KeyStoreManager;
+import org.wso2.carbon.core.util.KeyStoreUtil;
+import org.wso2.carbon.core.keystore.dao.KeyStoreDAO;
+import org.wso2.carbon.core.keystore.dao.PubCertDAO;
+import org.wso2.carbon.core.keystore.dao.impl.KeyStoreDAOImpl;
+import org.wso2.carbon.core.keystore.dao.impl.PubCertDAOImpl;
+import org.wso2.carbon.core.keystore.model.KeyStoreModel;
+import org.wso2.carbon.core.keystore.service.CertData;
+import org.wso2.carbon.core.keystore.service.CertDataDetail;
+import org.wso2.carbon.core.keystore.service.KeyStoreData;
+import org.wso2.carbon.core.keystore.service.PaginatedCertData;
+import org.wso2.carbon.core.keystore.service.PaginatedKeyStoreData;
+import org.wso2.carbon.user.api.UserStoreException;
+import org.wso2.carbon.utils.CarbonUtils;
+import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+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.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.CACHING_PAGE_SIZE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_MESSAGE_RETRIEVE_KEYSTORE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_MESSAGE_RETRIEVE_PUBLIC_CERT;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ITEMS_PER_PAGE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.KEY_STORES;
+
+/**
+ * Key Store Admin class.
+ */
+public class KeyStoreAdmin {
+
+ // todo: add public method comments
+
+ //trust store
+ public static final String SERVER_TRUSTSTORE_FILE = "Security.TrustStore.Location";
+ public static final String SERVER_TRUSTSTORE_PASSWORD = "Security.TrustStore.Password";
+ public static final String SERVER_TRUSTSTORE_TYPE = "Security.TrustStore.Type";
+
+ private static final String PATH_SEPARATOR = "/";
+
+ // This is used as the alternative for RegistryResources.SecurityManagement.PRIMARY_KEYSTORE_PHANTOM_RESOURCE.
+ private static final String ALTERNATE_PRIMARY_KEYSTORE_PHANTOM_RESOURCE = "carbon-primary-ks";
+
+ private static final Log log = LogFactory.getLog(KeyStoreAdmin.class);
+ private static final String PROP_TRUST_STORE_UPDATE_REQUIRED =
+ "org.wso2.carbon.identity.core.util.TRUST_STORE_UPDATE_REQUIRED";
+ private int tenantId;
+ private String tenantUUID;
+ private boolean includeCert = false;
+ private KeyStoreDAO keyStoreDAO;
+ private PubCertDAO pubCertDAO;
+ private final String trustStoreLocation;
+ private final String trustStorePassword;
+
+ public KeyStoreAdmin(int tenantId) {
+
+ ServerConfiguration config = ServerConfiguration.getInstance();
+ trustStoreLocation = config.getFirstProperty(SERVER_TRUSTSTORE_FILE);
+ trustStorePassword = config.getFirstProperty(SERVER_TRUSTSTORE_PASSWORD);
+ this.tenantId = tenantId;
+ try {
+ tenantUUID = KeyStoreMgtUtil.getTenantUUID(tenantId);
+ keyStoreDAO = new KeyStoreDAOImpl();
+ pubCertDAO = new PubCertDAOImpl();
+ } catch (KeyStoreManagementException e) {
+ log.error("Error while retrieving the tenant ID.", e);
+ } catch (UserStoreException e) {
+ log.error("Error while retrieving the tenant UUID.", e);
+ }
+ }
+
+ public boolean isIncludeCert() {
+
+ return includeCert;
+ }
+
+ public void setIncludeCert(boolean includeCert) {
+
+ this.includeCert = includeCert;
+ }
+
+ /**
+ * Method to retrieve keystore data.
+ *
+ * @param isSuperTenant Indication whether the querying super tenant data.
+ * @return A key store data array.
+ * @throws KeyStoreManagementException Throws if an error occurred while getting the key stores.
+ */
+ public KeyStoreData[] getKeyStores(boolean isSuperTenant) throws KeyStoreManagementException {
+
+ CarbonUtils.checkSecurity();
+ KeyStoreData[] names = new KeyStoreData[0];
+
+ try {
+ List keyStores = keyStoreDAO.getKeyStores(tenantUUID);
+ List keyStoreDataList = new ArrayList<>();
+ if (!CollectionUtils.isEmpty(keyStores)) {
+ for (KeyStoreModel keyStoreModel : keyStores) {
+ if (ALTERNATE_PRIMARY_KEYSTORE_PHANTOM_RESOURCE.equals(keyStoreModel.getFileName())) {
+ continue;
+ }
+
+ KeyStoreData data = new KeyStoreData();
+ data.setKeyStoreName(keyStoreModel.getFileName());
+ data.setKeyStoreType(keyStoreModel.getType());
+ data.setProvider(keyStoreModel.getProvider());
+
+ String alias = keyStoreModel.getPrivateKeyAlias();
+ if (alias != null) {
+ data.setPrivateStore(true);
+ } else {
+ data.setPrivateStore(false);
+ }
+
+ if (!isSuperTenant) {
+ Optional pubCertId =
+ keyStoreDAO.getPubCertIdFromKeyStore(tenantUUID, keyStoreModel.getFileName());
+
+ pubCertId.flatMap(id -> {
+ try {
+ return pubCertDAO.getPubCert(id);
+ } catch (KeyStoreManagementException e) {
+ log.error(ERROR_MESSAGE_RETRIEVE_PUBLIC_CERT.getMessage(), e);
+ return Optional.empty();
+ }
+ })
+ .ifPresent(pubCert -> {
+ String fileName = generatePubCertFileName(KEY_STORES + PATH_SEPARATOR +
+ keyStoreModel.getFileName(), pubCert.getFileNameAppender());
+ if (MessageContext.getCurrentMessageContext() != null) {
+ String pubKeyFilePath = KeyStoreMgtUtil.dumpCert(
+ MessageContext.getCurrentMessageContext().getConfigurationContext(),
+ pubCert.getContent(), fileName);
+ data.setPubKeyFilePath(pubKeyFilePath);
+ }
+ });
+ }
+ keyStoreDataList.add(data);
+ }
+ }
+
+ // Prepare the next position for the super tenant keystore data.
+ names = new KeyStoreData[keyStoreDataList.size() + 1];
+ Iterator keyStoreDataIterator = keyStoreDataList.iterator();
+ int count = 0;
+ while (keyStoreDataIterator.hasNext()) {
+ names[count] = keyStoreDataIterator.next();
+ count++;
+ }
+
+ if (isSuperTenant) {
+ KeyStoreData data = new KeyStoreData();
+ ServerConfiguration config = ServerConfiguration.getInstance();
+ String fileName = config
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_FILE);
+ String type = config
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_TYPE);
+ String name = KeyStoreUtil.getKeyStoreFileName(fileName);
+ data.setKeyStoreName(name);
+ data.setKeyStoreType(type);
+ data.setProvider(" ");
+ data.setPrivateStore(true);
+
+ names[count] = data;
+ }
+ return names;
+ } catch (KeyStoreManagementException e) {
+ log.error(ERROR_MESSAGE_RETRIEVE_KEYSTORE.getMessage(), e);
+ throw new KeyStoreManagementException(ERROR_MESSAGE_RETRIEVE_KEYSTORE.getMessage(), e);
+ }
+ }
+
+ /**
+ * Method to add keystore when a file path is given instead of file data.
+ *
+ * @param filePath File path of the keystore data.
+ * @param filename Name of the keystore.
+ * @param password Password of the keystore.
+ * @param provider Provider of the keystore.
+ * @param type Type of the keystore.
+ * @param pvtKeyPass Password of the private key.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the keystore.
+ */
+ public void addKeyStoreWithFilePath(String filePath, String filename, String password,
+ String provider, String type, String pvtKeyPass)
+ throws KeyStoreManagementException {
+
+ try {
+ addKeyStore(readBytesFromFile(filePath), filename, password, provider, type, pvtKeyPass);
+ } catch (IOException e) {
+ throw new KeyStoreManagementException("Error while loading keystore from file " + filePath, e);
+ }
+
+ }
+
+ /**
+ * Method to add keystore when a file data is given.
+ *
+ * @param fileData File data of the keystore.
+ * @param filename Name of the keystore.
+ * @param password Password of the keystore.
+ * @param provider Provider of the keystore.
+ * @param type Type of the keystore.
+ * @param pvtKeyPass Password of the private key.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the keystore.
+ */
+ public void addKeyStore(String fileData, String filename, String password, String provider,
+ String type, String pvtKeyPass) throws KeyStoreManagementException {
+
+ byte[] content = Base64.decode(fileData);
+ addKeyStore(content, filename, password, provider, type, pvtKeyPass);
+ }
+
+ /**
+ * Method to add keystore when a byte array is given for the file data.
+ *
+ * @param content Byte array of the keystore data.
+ * @param filename Name of the keystore.
+ * @param password Password of the keystore.
+ * @param provider Provider of the keystore.
+ * @param type Type of the keystore.
+ * @param pvtKeyPass Password of the private key.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the keystore.
+ */
+ public void addKeyStore(byte[] content, String filename, String password, String provider,
+ String type, String pvtKeyPass) throws KeyStoreManagementException {
+
+ if (filename == null) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+ try {
+ if (KeyStoreUtil.isPrimaryStore(filename)) {
+ throw new KeyStoreManagementException("Key store " + filename + " already available");
+ }
+ if (isTrustStore(filename)) {
+ throw new KeyStoreManagementException("Key store " + filename + " already available");
+ }
+ if (isExistKeyStore(filename)) {
+ throw new KeyStoreManagementException("Key store " + filename + " already available");
+ }
+
+ KeyStore keyStore = KeyStore.getInstance(type);
+ keyStore.load(new ByteArrayInputStream(content), password.toCharArray());
+
+ // check for more private keys
+ Enumeration enumeration = keyStore.aliases();
+ String pvtKeyAlias = null;
+ while (enumeration.hasMoreElements()) {
+ String alias = (String) enumeration.nextElement();
+ if (keyStore.isKeyEntry(alias)) {
+ pvtKeyAlias = alias;
+ }
+ }
+
+ // just to test weather pvt key password is correct.
+ keyStore.getKey(pvtKeyAlias, pvtKeyPass.toCharArray());
+
+ CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
+
+ KeyStoreModel data;
+
+ if (pvtKeyAlias == null) {
+ data = new KeyStoreModel.KeyStoreModelBuilder()
+ .fileName(filename)
+ .type(type)
+ .provider(provider)
+ .password(cryptoUtil.encryptAndBase64Encode(password.getBytes()).toCharArray())
+ .content(content)
+ .build();
+ } else {
+ data = new KeyStoreModel.KeyStoreModelBuilder()
+ .fileName(filename)
+ .type(type)
+ .provider(provider)
+ .password(cryptoUtil.encryptAndBase64Encode(password.getBytes()).toCharArray())
+ .privateKeyAlias(pvtKeyAlias)
+ .privateKeyPass(cryptoUtil.encryptAndBase64Encode(pvtKeyPass.getBytes()).toCharArray())
+ .content(content)
+ .build();
+ }
+
+ keyStoreDAO.addKeyStore(tenantUUID, data);
+ } catch (KeyStoreManagementException | CryptoException | IOException | NoSuchAlgorithmException |
+ CertificateException | UnrecoverableKeyException | KeyStoreException e) {
+ String msg = "Error when adding a keyStore";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg, e);
+ }
+ }
+
+ /**
+ * Method to add trust store when trust store file data is given.
+ *
+ * @param fileData File data of the trust store.
+ * @param filename Name of the trust store.
+ * @param password Password of the trust store.
+ * @param provider Provider of the trust store.
+ * @param type Type of the trust store.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the trust store.
+ */
+ public void addTrustStore(String fileData, String filename, String password, String provider,
+ String type) throws KeyStoreManagementException {
+
+ byte[] content = Base64.decode(fileData);
+ addTrustStore(content, filename, password, provider, type);
+ }
+
+ /**
+ * Method to add trust store when trust store file path is given for the file data.
+ *
+ * @param content Byte array of the trust store data.
+ * @param filename Name of the trust store.
+ * @param password Password of the trust store.
+ * @param provider Provider of the trust store.
+ * @param type Type of the trust store.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the trust store.
+ */
+ public void addTrustStore(byte[] content, String filename, String password, String provider, String type)
+ throws KeyStoreManagementException {
+
+ if (filename == null) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+ try {
+ if (KeyStoreUtil.isPrimaryStore(filename)) {
+ throw new KeyStoreManagementException("Key store " + filename + " already available");
+ }
+
+ if (isExistKeyStore(filename)) {
+ throw new KeyStoreManagementException("Key store " + filename + " already available");
+ }
+
+ KeyStore keyStore = KeyStore.getInstance(type);
+ keyStore.load(new ByteArrayInputStream(content), password.toCharArray());
+ CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
+
+ KeyStoreModel data = new KeyStoreModel.KeyStoreModelBuilder()
+ .fileName(filename)
+ .type(type)
+ .provider(provider)
+ .password(cryptoUtil.encryptAndBase64Encode(password.getBytes()).toCharArray())
+ .content(content)
+ .build();
+ keyStoreDAO.addKeyStore(tenantUUID, data);
+ } catch (KeyStoreManagementException e) {
+ throw e;
+ } catch (Exception e) {
+ String msg = "Error when adding a trustStore";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg, e);
+ }
+ }
+
+ /**
+ * Method to delete a key store when a store data file name is given.
+ *
+ * @param keyStoreName Name of the key store.
+ * @throws KeyStoreManagementException Throws if an error occurred while adding the trust store.
+ */
+ public void deleteStore(String keyStoreName) throws KeyStoreManagementException {
+
+ try {
+
+ if (StringUtils.isBlank(keyStoreName)) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+
+ if (KeyStoreUtil.isPrimaryStore(keyStoreName)) {
+ throw new KeyStoreManagementException("Not allowed to delete the primary key store : "
+ + keyStoreName);
+ }
+ if (isTrustStore(keyStoreName)) {
+ throw new KeyStoreManagementException("Not allowed to delete the trust store : "
+ + keyStoreName);
+ }
+
+ // TODO: verify that this behaves as expected
+ if (keyStoreDAO.getPubCertIdFromKeyStore(tenantUUID, keyStoreName).isPresent()) {
+ throw new KeyStoreManagementException("Key store : " + keyStoreName +
+ " is already in use and can't be deleted");
+ }
+
+ keyStoreDAO.deleteKeyStore(tenantUUID, keyStoreName);
+ } catch (KeyStoreManagementException e) {
+ // Catch KeyStoreManagementException and throw the expected KeyStoreManagementException.
+ String msg = "Error when deleting a keyStore";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg, e);
+ }
+ }
+
+ /**
+ * Method to import a public certificate to the keystore.
+ *
+ * @param fileName Name of the certificate.
+ * @param certData Certificate data.
+ * @param keyStoreName Name of the keystore.
+ * @throws KeyStoreManagementException Throws if an error occurred while importing the public certificate to the
+ * trust store.
+ */
+ public void importCertToStore(String fileName, String certData, String keyStoreName)
+ throws KeyStoreManagementException {
+
+ try {
+ if (keyStoreName == null) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+
+ KeyStore ks = getKeyStore(keyStoreName);
+ X509Certificate cert = extractCertificate(certData);
+
+ if (ks.getCertificateAlias(cert) != null) {
+ // We already have this certificate in the key store - ignore
+ // adding it twice
+ return;
+ }
+
+ ks.setCertificateEntry(fileName, cert);
+
+ updateKeyStore(keyStoreName, ks);
+
+ if (isTrustStore(keyStoreName)) {
+ System.setProperty(PROP_TRUST_STORE_UPDATE_REQUIRED, "true");
+ }
+
+ } catch (KeyStoreManagementException e) {
+ throw e;
+ } catch (Exception e) {
+ String msg = "Error when importing cert to the keyStore";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg, e);
+ }
+
+ }
+
+ /**
+ * Method to import a public certificate to the keystore when a public certificate filename is not given.
+ *
+ * @param certData Certificate data.
+ * @param keyStoreName Name of the keystore.
+ * @return Returns the alias or the filename of the certificate.
+ * @throws KeyStoreManagementException Throws if an error occurred while importing the public certificate to the
+ * trust store.
+ */
+ public String importCertToStore(String certData, String keyStoreName)
+ throws KeyStoreManagementException {
+
+ String alias = null;
+
+ try {
+ if (keyStoreName == null) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+
+ KeyStore ks = getKeyStore(keyStoreName);
+ X509Certificate cert = extractCertificate(certData);
+
+ if (ks.getCertificateAlias(cert) != null) {
+ // We already have this certificate in the key store - ignore
+ // adding it twice
+ return null;
+ }
+ alias = cert.getSubjectDN().getName();
+ ks.setCertificateEntry(alias, cert);
+
+ updateKeyStore(keyStoreName, ks);
+
+ if (isTrustStore(keyStoreName)) {
+ System.setProperty(PROP_TRUST_STORE_UPDATE_REQUIRED, "true");
+ }
+
+ return alias;
+
+ } catch (KeyStoreManagementException e) {
+ throw e;
+ } catch (Exception e) {
+ String msg = "Error when importing cert to keyStore";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg);
+ }
+ }
+
+ /**
+ * Remove public certificate from store.
+ *
+ * @param alias Alias of the certificate.
+ * @param keyStoreName Name of the keystore.
+ * @throws KeyStoreManagementException Throws if an error occurred while removing the public certificate from the
+ * trust store.
+ */
+ public void removeCertFromStore(String alias, String keyStoreName)
+ throws KeyStoreManagementException {
+
+ try {
+ if (keyStoreName == null) {
+ throw new KeyStoreManagementException("Key Store name can't be null");
+ }
+
+ KeyStore ks = getKeyStore(keyStoreName);
+
+ if (ks.getCertificate(alias) == null) {
+ return;
+ }
+
+ ks.deleteEntry(alias);
+ updateKeyStore(keyStoreName, ks);
+
+ if (isTrustStore(keyStoreName)) {
+ System.setProperty(PROP_TRUST_STORE_UPDATE_REQUIRED, Boolean.TRUE.toString());
+ }
+ } catch (KeyStoreManagementException e) {
+ throw e;
+ } catch (Exception e) {
+ String msg = "Error when removing cert from store";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg);
+ }
+ }
+
+ /**
+ * Retrieve list of alias entries of a given keystore.
+ *
+ * @param keyStoreName Name of the keystore.
+ * @return Returns the list of alias entries of a given keystore.
+ * @throws KeyStoreManagementException Throws if an error occurred while getting the store entries.
+ */
+ public String[] getStoreEntries(String keyStoreName) throws KeyStoreManagementException {
+
+ String[] names;
+ try {
+ if (keyStoreName == null) {
+ throw new Exception("keystore name cannot be null");
+ }
+
+ //KeyStoreManager keyMan = KeyStoreManager.getInstance(tenantId);
+ KeyStore ks = getKeyStore(keyStoreName);
+
+ Enumeration enm = ks.aliases();
+ List lst = new ArrayList<>();
+ while (enm.hasMoreElements()) {
+ lst.add(enm.nextElement());
+ }
+
+ names = lst.toArray(new String[lst.size()]);
+ } catch (KeyStoreManagementException e) {
+ throw e;
+ } catch (Exception e) {
+ String msg = "Error when getting store entries";
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg);
+ }
+
+ return names;
+ }
+
+ /**
+ * This method will list 1. Certificate aliases 2. Private key alise 3. Private key value to a
+ * given keystore.
+ *
+ * @param keyStoreName The name of the keystore
+ * @return Instance of KeyStoreData.
+ * @throws KeyStoreManagementException will be thrown if an error occurs while getting the keystore.
+ */
+ public KeyStoreData getKeystoreInfo(String keyStoreName) throws KeyStoreManagementException {
+
+ try {
+
+ if (keyStoreName == null) {
+ throw new Exception("keystore name cannot be null");
+ }
+
+ KeyStore keyStore;
+ String keyStoreType;
+ String privateKeyPassword = null;
+ if (KeyStoreUtil.isPrimaryStore(keyStoreName)) {
+ KeyStoreManager keyMan = KeyStoreManager.getInstance(tenantId);
+ keyStore = keyMan.getPrimaryKeyStore();
+ ServerConfiguration serverConfig = ServerConfiguration.getInstance();
+ keyStoreType = serverConfig
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_TYPE);
+ privateKeyPassword = serverConfig
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIVATE_KEY_PASSWORD);
+ } else if (isTrustStore(keyStoreName)) {
+ keyStore = getTrustStore();
+ ServerConfiguration serverConfig = ServerConfiguration.getInstance();
+ keyStoreType = serverConfig.getFirstProperty(SERVER_TRUSTSTORE_TYPE);
+ privateKeyPassword = serverConfig.getFirstProperty(SERVER_TRUSTSTORE_PASSWORD);
+ } else {
+ if (!isExistKeyStore(keyStoreName)) {
+ throw new KeyStoreManagementException("Key Store not found");
+ }
+ KeyStoreModel resource = keyStoreDAO.getKeyStore(tenantUUID, keyStoreName).get();
+ keyStore = getKeyStore(keyStoreName);
+ keyStoreType = resource.getType();
+
+ String encryptionPassphrase = String.valueOf(resource.getPrivateKeyPass());
+ // todo: check the actual value is empty or null
+ if (encryptionPassphrase != null || encryptionPassphrase.isEmpty()) {
+ CryptoUtil util = CryptoUtil.getDefaultCryptoUtil();
+ privateKeyPassword = new String(util.base64DecodeAndDecrypt(encryptionPassphrase));
+ }
+ }
+ // Fill the information about the certificates
+ Enumeration aliases = keyStore.aliases();
+ List certDataList = new ArrayList<>();
+ Format formatter = new SimpleDateFormat("dd/MM/yyyy");
+
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ if (keyStore.isCertificateEntry(alias)) {
+ X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
+ certDataList.add(fillCertData(cert, alias, formatter));
+ }
+ }
+
+ // Create a cert array
+ CertData[] certs = certDataList.toArray(new CertData[certDataList.size()]);
+
+ // Create a KeyStoreData bean, set the name and fill in the cert information
+ KeyStoreData keyStoreData = new KeyStoreData();
+ keyStoreData.setKeyStoreName(keyStoreName);
+ keyStoreData.setCerts(certs);
+ keyStoreData.setKeyStoreType(keyStoreType);
+
+ aliases = keyStore.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ // There be only one entry in WSAS related keystores
+ if (keyStore.isKeyEntry(alias)) {
+ X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
+ keyStoreData.setKey(fillCertData(cert, alias, formatter));
+ PrivateKey key = (PrivateKey) keyStore.getKey(alias, privateKeyPassword
+ .toCharArray());
+ String pemKey;
+ pemKey = "-----BEGIN PRIVATE KEY-----\n";
+ pemKey += Base64.encode(key.getEncoded());
+ pemKey += "\n-----END PRIVATE KEY-----";
+ keyStoreData.setKeyValue(pemKey);
+ break;
+
+ }
+ }
+ return keyStoreData;
+ } catch (Exception e) {
+ String msg = "Error has encounted while loading the keystore to the given keystore name "
+ + keyStoreName;
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg);
+ }
+
+ }
+
+ /**
+ * Retrieve private key of a given alias.
+ *
+ * @param alias Alias of the key.
+ * @param isSuperTenant Indication whether the querying super tenant data.
+ * @return Returns the private key of a given alias.
+ * @throws KeyStoreManagementException Throws if an error occurred while getting the private key.
+ */
+ public Key getPrivateKey(String alias, boolean isSuperTenant) throws KeyStoreManagementException {
+
+ KeyStoreData[] keystores = getKeyStores(isSuperTenant);
+ KeyStore keyStore = null;
+ String privateKeyPassowrd = null;
+
+ try {
+
+ for (int i = 0; i < keystores.length; i++) {
+ if (KeyStoreUtil.isPrimaryStore(keystores[i].getKeyStoreName())) {
+ KeyStoreManager keyMan = KeyStoreManager.getInstance(tenantId);
+ keyStore = keyMan.getPrimaryKeyStore();
+ ServerConfiguration serverConfig = ServerConfiguration.getInstance();
+ privateKeyPassowrd = serverConfig
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIVATE_KEY_PASSWORD);
+ return keyStore.getKey(alias, privateKeyPassowrd.toCharArray());
+ }
+ }
+ } catch (Exception e) {
+ String msg = "Error has encounted while loading the key for the given alias " + alias;
+ log.error(msg, e);
+ throw new KeyStoreManagementException(msg);
+ }
+ return null;
+ }
+
+ /**
+ * Fill certificate data.
+ *
+ * @param cert Certificate.
+ * @param alise Certificate alias.
+ * @param formatter Formatter.
+ * @return Filled certificate data.
+ * @throws CertificateEncodingException Certificate encoding exception.
+ */
+ private CertData fillCertData(X509Certificate cert, String alise, Format formatter)
+ throws CertificateEncodingException {
+
+ CertData certData = null;
+
+ if (includeCert) {
+ certData = new CertDataDetail();
+ } else {
+ certData = new CertData();
+ }
+ certData.setAlias(alise);
+ certData.setSubjectDN(cert.getSubjectDN().getName());
+ certData.setIssuerDN(cert.getIssuerDN().getName());
+ certData.setSerialNumber(cert.getSerialNumber());
+ certData.setVersion(cert.getVersion());
+ certData.setNotAfter(formatter.format(cert.getNotAfter()));
+ certData.setNotBefore(formatter.format(cert.getNotBefore()));
+ certData.setPublicKey(Base64.encode(cert.getPublicKey().getEncoded()));
+
+ if (includeCert) {
+ ((CertDataDetail) certData).setCertificate(cert);
+ }
+
+ return certData;
+ }
+
+ /**
+ * Read store data using the given store name.
+ *
+ * @param filePath File path of the keystore.
+ * @return Returns the keystore data as bytes stream.
+ * @throws IOException Throws if an error occurred while reading the keystore.
+ */
+ private byte[] readBytesFromFile(String filePath) throws IOException {
+
+ InputStream inputStream = null;
+ File file = new File(filePath);
+ long length;
+ byte[] bytes;
+ int offset = 0;
+ int numRead = 0;
+
+ try {
+ inputStream = new FileInputStream(file);
+ length = file.length();
+ bytes = new byte[(int) length];
+
+ while (offset < bytes.length
+ && (numRead = inputStream.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+
+ return bytes;
+ }
+
+ /**
+ * This method is used to generate the file name of the pub. cert of a tenant.
+ *
+ * @param ksLocation keystore location in the registry.
+ * @param uuid UUID appender
+ * @return file name of the pub. cert
+ */
+ private String generatePubCertFileName(String ksLocation, String uuid) {
+
+ String tenantName = ksLocation.substring(ksLocation.lastIndexOf("/"));
+ if (tenantName.endsWith(".jks")) {
+ tenantName = tenantName.replace(".jks", "");
+ }
+ return tenantName + "-" + uuid + ".cert";
+ }
+
+ /**
+ * This method is used internally to do the pagination purposes.
+ *
+ * @param pageNumber Page Number.
+ * @param certDataSet Set of keyStoreData.
+ * @return PaginatedPolicySetDTO object containing the number of pages and the set of policies
+ * that reside in the given page.
+ */
+ private PaginatedCertData doPaging(int pageNumber, CertData[] certDataSet) {
+
+ PaginatedCertData paginatedCertData = new PaginatedCertData();
+ if (certDataSet.length == 0) {
+ paginatedCertData.setCertDataSet(new CertData[0]);
+ return paginatedCertData;
+ }
+ int itemsPerPageInt = ITEMS_PER_PAGE;
+ int numberOfPages = (int) Math.ceil((double) certDataSet.length / itemsPerPageInt);
+ if (pageNumber > numberOfPages - 1) {
+ pageNumber = numberOfPages - 1;
+ }
+ int startIndex = pageNumber * itemsPerPageInt;
+ int endIndex = certDataSet.length;
+ if (numberOfPages > CACHING_PAGE_SIZE) {
+ endIndex = (pageNumber + CACHING_PAGE_SIZE) * itemsPerPageInt;
+ }
+ CertData[] returnedCertDataSet = new CertData[endIndex];
+
+ for (int i = startIndex, j = 0; i < endIndex && i < certDataSet.length; i++, j++) {
+ returnedCertDataSet[j] = certDataSet[i];
+ }
+
+ paginatedCertData.setCertDataSet(returnedCertDataSet);
+ paginatedCertData.setNumberOfPages(numberOfPages);
+
+ return paginatedCertData;
+ }
+
+ /**
+ * This method is used internally for the filtering purposes.
+ *
+ * @param filter Filter string.
+ * @param certDataSet Certificate or key array.
+ * @return Cert Data array after filtering.
+ */
+ private static CertData[] doFilter(String filter, CertData[] certDataSet) {
+
+ if (certDataSet != null && certDataSet.length != 0) {
+ String regPattern = filter.replace("*", ".*");
+ List certDataList = new ArrayList();
+
+ for (CertData cert : certDataSet) {
+ if (cert != null && cert.getAlias().toLowerCase().matches(regPattern.toLowerCase())) {
+ certDataList.add(cert);
+ }
+ }
+
+ return (CertData[]) certDataList.toArray(new CertData[0]);
+ } else {
+ return new CertData[0];
+ }
+ }
+
+ /**
+ * Gets the keystore info by keystore name with its certificates and key certificates.
+ *
+ * @param keyStoreName The name of the keystore.
+ * @param pageNumber Page number.
+ * @return Instance of KeyStoreData.
+ * @throws KeyStoreManagementException If an error occurs while getting the keystore this exception will be thrown.
+ */
+ public PaginatedKeyStoreData getPaginatedKeystoreInfo(String keyStoreName, int pageNumber)
+ throws KeyStoreManagementException {
+
+ if (StringUtils.isEmpty(keyStoreName)) {
+ throw new KeyStoreManagementException("Keystore name cannot be empty or null.");
+ }
+
+ try {
+ // Get keystore.
+ KeyStore keyStore = getKeyStore(tenantId, keyStoreName);
+ // Get keystore type.
+ String keyStoreType = getKeyStoreType(keyStoreName);
+
+ // Extract certificates from aliases as list.
+ List certDataList = getCertificates(keyStore);
+ List keyCertDataList = getKeyCertificates(keyStore);
+
+ // Create a certificate array.
+ CertData[] certs = certDataList.toArray(new CertData[certDataList.size()]);
+ // Get paginated certificates.
+ PaginatedCertData paginatedCerts = doPaging(pageNumber, certs);
+
+ // Create a key certificate array.
+ CertData[] keyCerts = keyCertDataList.toArray(new CertData[keyCertDataList.size()]);
+ // Get paginated key certificates.
+ PaginatedCertData paginatedKeyCerts = doPaging(pageNumber, keyCerts);
+
+ // Fill information about the keystore to PaginatedKeyStoreData.
+ PaginatedKeyStoreData keyStoreData = fillPaginatedKeyStoreData(keyStoreName, keyStoreType,
+ paginatedCerts, paginatedKeyCerts);
+
+ return keyStoreData;
+ } catch (Exception e) {
+ throw new KeyStoreManagementException(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Gets the keystore info by keystore name and filters its certificates and key certificates
+ * by applying the filter for certificate aliases.
+ *
+ * @param keyStoreName The name of the keystore.
+ * @param pageNumber Page number.
+ * @param filter Filter for certificate alias.
+ * @return Instance of KeyStoreData.
+ * @throws KeyStoreManagementException will be thrown.
+ */
+ public PaginatedKeyStoreData getFilteredPaginatedKeyStoreInfo(String keyStoreName, int pageNumber,
+ String filter) throws KeyStoreManagementException {
+
+ if (StringUtils.isEmpty(keyStoreName)) {
+ throw new KeyStoreManagementException("Keystore name cannot be empty or null.");
+ }
+
+ try {
+ // Get keystore.
+ KeyStore keyStore = getKeyStore(tenantId, keyStoreName);
+ // Get keystore type.
+ String keyStoreType = getKeyStoreType(keyStoreName);
+
+ // Extract certificates from aliases as list.
+ List certDataList = getCertificates(keyStore);
+ List keyCertDataList = getKeyCertificates(keyStore);
+ // Filter and paginate certs and keyCerts.
+ PaginatedCertData paginatedCerts = filterAndPaginateCerts(certDataList, filter, pageNumber);
+ PaginatedCertData paginatedKeyCerts = filterAndPaginateCerts(keyCertDataList, filter, pageNumber);
+ // Fill information about the keystore to PaginatedKeyStoreData.
+ PaginatedKeyStoreData keyStoreData = fillPaginatedKeyStoreData(keyStoreName, keyStoreType,
+ paginatedCerts, paginatedKeyCerts);
+
+ return keyStoreData;
+ } catch (Exception e) {
+ throw new KeyStoreManagementException(e.getMessage());
+ }
+ }
+
+ /**
+ * Retrieves key store for a given keystore name of a tenant.
+ *
+ * @param tenantId Tenant Id.
+ * @param keyStoreName Keystore Name.
+ * @return KeyStore.
+ * @throws Exception This will be thrown if an error occurs while retrieving the keystore.
+ */
+ private KeyStore getKeyStore(int tenantId, String keyStoreName) throws Exception {
+
+ KeyStore keyStore;
+ if (KeyStoreUtil.isPrimaryStore(keyStoreName)) {
+ KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(tenantId);
+ keyStore = keyStoreManager.getPrimaryKeyStore();
+ } else if (isTrustStore(keyStoreName)) {
+ keyStore = getTrustStore();
+ } else {
+ keyStore = getKeyStore(keyStoreName);
+ }
+ return keyStore;
+ }
+
+ /**
+ * Get keystore type.
+ *
+ * @param keyStoreName Keystore name.
+ * @return Keystore type.
+ * @throws KeyStoreManagementException If an error occurs while retrieving the keystore.
+ */
+ private String getKeyStoreType(String keyStoreName) throws KeyStoreManagementException {
+
+ String keyStoreType;
+ if (KeyStoreUtil.isPrimaryStore(keyStoreName)) {
+ ServerConfiguration serverConfig = ServerConfiguration.getInstance();
+ keyStoreType = serverConfig
+ .getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_TYPE);
+ } else if (isTrustStore(keyStoreName)) {
+ ServerConfiguration serverConfig = ServerConfiguration.getInstance();
+ keyStoreType = serverConfig.getFirstProperty(SERVER_TRUSTSTORE_TYPE);
+ } else {
+ if (!isExistKeyStore(keyStoreName)) {
+ throw new KeyStoreManagementException("Keystore " + keyStoreName + " not found.");
+ }
+ KeyStoreModel keyStoreModel = keyStoreDAO.getKeyStore(tenantUUID, keyStoreName).get();
+ keyStoreType = keyStoreModel.getType();
+ }
+ return keyStoreType;
+ }
+
+ /**
+ * Fill PaginatedKeyStoreData with keystore details.
+ *
+ * @param keyStoreName Name of the keystore.
+ * @param keyStoreType Type of the keystore.
+ * @param certs Paginated certificates.
+ * @param keyCerts Paginated key certificates.
+ * @return Paginated KeyStore Data.
+ */
+ private PaginatedKeyStoreData fillPaginatedKeyStoreData(String keyStoreName, String keyStoreType,
+ PaginatedCertData certs, PaginatedCertData keyCerts) {
+
+ // Create a KeyStoreData bean, set the name, type and fill in the cert information.
+ PaginatedKeyStoreData keyStoreData = new PaginatedKeyStoreData();
+ keyStoreData.setKeyStoreName(keyStoreName);
+ keyStoreData.setKeyStoreType(keyStoreType);
+ keyStoreData.setPaginatedCertData(certs);
+ keyStoreData.setPaginatedKeyData(keyCerts);
+ return keyStoreData;
+ }
+
+ /**
+ * Get certificates related to alias from the keystore.
+ *
+ * @param keyStore Keystore
+ * @return List of certificate data.
+ * @throws KeyStoreException If an error occurs while retrieving the keystore.
+ * @throws CertificateEncodingException If an error occurs while encoding the certificate.
+ */
+ private List getCertificates(KeyStore keyStore)
+ throws KeyStoreException, CertificateEncodingException {
+
+ Enumeration aliases = keyStore.aliases();
+ // Create lists for cert and key lists.
+ List certDataList = new ArrayList<>();
+ Format formatter = new SimpleDateFormat("dd/MM/yyyy");
+
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
+ if (keyStore.isCertificateEntry(alias)) {
+ certDataList.add(fillCertData(cert, alias, formatter));
+ }
+ }
+ return certDataList;
+ }
+
+ /**
+ * Get key certificates related to alias from the keystore.
+ *
+ * @param keyStore Keystore
+ * @return List of certificate data.
+ * @throws KeyStoreException If an error occurs while retrieving the keystore.
+ * @throws CertificateEncodingException If an error occurs while encoding the certificate.
+ */
+ private List getKeyCertificates(KeyStore keyStore)
+ throws KeyStoreException, CertificateEncodingException {
+
+ Enumeration aliases = keyStore.aliases();
+ // Create lists for cert and key lists.
+ List certDataList = new ArrayList<>();
+ Format formatter = new SimpleDateFormat("dd/MM/yyyy");
+
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
+ if (keyStore.isKeyEntry(alias)) {
+ certDataList.add(fillCertData(cert, alias, formatter));
+ }
+ }
+ return certDataList;
+ }
+
+ /**
+ * Filter and paginate certificate list.
+ *
+ * @param certDataList Certificate list.
+ * @param filterString Filter text.
+ * @param pageNumber Page number.
+ * @return Paginated and Filtered Certificate Data.
+ */
+ private PaginatedCertData filterAndPaginateCerts(List certDataList, String filterString, int pageNumber) {
+
+ PaginatedCertData paginatedCerts;
+ CertData[] certs = certDataList.toArray(new CertData[0]);
+ certs = (doFilter(filterString, certs));
+ paginatedCerts = doPaging(pageNumber, certs);
+ return paginatedCerts;
+ }
+
+ /**
+ * Load the default trust store (allowed only for super tenant).
+ *
+ * @return trust store object
+ * @throws KeyStoreManagementException if retrieving the truststore fails.
+ */
+ public KeyStore getTrustStore() throws KeyStoreManagementException {
+
+ //Allow only the super tenant to access the default trust store.
+ if (tenantId != MultitenantConstants.SUPER_TENANT_ID) {
+ throw new KeyStoreManagementException("Permission denied for accessing trust store");
+ }
+
+ KeyStore trustStore;
+ ServerConfiguration serverConfiguration = ServerConfiguration.getInstance();
+ String file = new File(serverConfiguration.getFirstProperty(SERVER_TRUSTSTORE_FILE)).getAbsolutePath();
+
+ KeyStore store;
+ try {
+ store = KeyStore.getInstance(serverConfiguration.getFirstProperty(SERVER_TRUSTSTORE_TYPE));
+ } catch (KeyStoreException e) {
+ throw new KeyStoreManagementException("Error occurred while loading keystore.", e);
+ }
+
+ String password = serverConfiguration.getFirstProperty(SERVER_TRUSTSTORE_PASSWORD);
+
+ try (FileInputStream in = new FileInputStream(file)) {
+ store.load(in, password.toCharArray());
+ trustStore = store;
+ } catch (CertificateException | NoSuchAlgorithmException | IOException e) {
+ throw new KeyStoreManagementException("Error occurred while loading trust store", e);
+ }
+ return trustStore;
+ }
+
+ /**
+ * Check if the supplied id is the system configured trust store
+ *
+ * @param id id (file name) of the keystore
+ * @return boolean true if supplied id is the configured trust store
+ */
+ private boolean isTrustStore(String id) {
+
+ ServerConfiguration serverConfiguration = ServerConfiguration.getInstance();
+ String fileName = serverConfiguration.getFirstProperty(SERVER_TRUSTSTORE_FILE);
+ int index = fileName.lastIndexOf('/');
+ if (index != -1) {
+ String name = fileName.substring(index + 1);
+ if (name.equals(id)) {
+ return true;
+ }
+ } else {
+ index = fileName.lastIndexOf(File.separatorChar);
+ String name;
+ if (index != -1) {
+ name = fileName.substring(fileName.lastIndexOf(File.separatorChar));
+ } else {
+ name = fileName;
+ }
+
+ if (name.equals(id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the {@link KeyStore} object of the given keystore name.
+ *
+ * @param keyStoreName name of the keystore.
+ * @return {@link KeyStore} object.
+ * @throws Exception if retrieving the keystore fails.
+ */
+ public KeyStore getKeyStore(String keyStoreName) throws Exception {
+
+ if (isTrustStore(keyStoreName)) {
+ return getTrustStore();
+ } else {
+ KeyStoreManager keyMan = KeyStoreManager.getInstance(tenantId);
+ return keyMan.getKeyStore(keyStoreName);
+ }
+ }
+
+ /**
+ * Updates the key store.
+ *
+ * @param name Name of the key store.
+ * @param keyStore KeyStore object.
+ * @throws Exception If an error occurred while updating the key store.
+ */
+ private void updateKeyStore(String name, KeyStore keyStore) throws Exception {
+
+ FileOutputStream resource1;
+ String outputStream1;
+ String path;
+ if (isTrustStore(name)) {
+ path = (new File(trustStoreLocation)).getAbsolutePath();
+ resource1 = null;
+
+ try {
+ resource1 = new FileOutputStream(path);
+ outputStream1 = trustStorePassword;
+ keyStore.store(resource1, outputStream1.toCharArray());
+ } finally {
+ if (resource1 != null) {
+ resource1.close();
+ }
+ }
+ } else {
+ KeyStoreManager keyStoreManager = KeyStoreManager.getInstance(tenantId);
+ keyStoreManager.updateKeyStore(name, keyStore);
+ }
+ }
+
+ /**
+ * Extract the encoded certificate into {@link X509Certificate}.
+ *
+ * @param certData encoded certificate.
+ * @return {@link X509Certificate} object.
+ * @throws KeyStoreManagementException if extracting the certificate fails.
+ */
+ public X509Certificate extractCertificate(String certData) throws KeyStoreManagementException {
+
+ byte[] bytes = Base64.decode(certData);
+ X509Certificate cert;
+ try {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ cert = (X509Certificate) factory
+ .generateCertificate(new ByteArrayInputStream(bytes));
+ } catch (CertificateException e) {
+ if (log.isDebugEnabled()) {
+ log.debug(e.getMessage(), e);
+ }
+ throw new KeyStoreManagementException("Invalid format of the provided certificate file");
+ }
+ return cert;
+ }
+
+ /**
+ * Returns whether the key store exists or not.
+ *
+ * @param fileName Name of the key store.
+ * @return True if the key store exists.
+ * @throws KeyStoreManagementException If an error occurred while checking the existence of the key store.
+ */
+ private boolean isExistKeyStore(String fileName) throws KeyStoreManagementException {
+
+ return keyStoreDAO.getKeyStore(tenantUUID, fileName).isPresent();
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementClientException.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementClientException.java
new file mode 100755
index 00000000000..c1a0f479822
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementClientException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+/**
+ * Handles the Keystore Management client level errors.
+ */
+public class KeyStoreManagementClientException extends KeyStoreManagementException {
+
+ public KeyStoreManagementClientException(String errorCode, String message) {
+ super(errorCode, message);
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementException.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementException.java
new file mode 100755
index 00000000000..0ccb9f011fc
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+import org.wso2.carbon.core.keystore.constants.KeyStoreConstants;
+
+/**
+ * Handles the Keystore Management errors.
+ */
+public class KeyStoreManagementException extends Exception {
+
+ private String errorCode = null;
+
+ public String getErrorCode() {
+
+ return this.errorCode;
+ }
+
+ public KeyStoreManagementException(String message) {
+ super(message);
+ }
+
+ public KeyStoreManagementException(String errorCode, String message) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public KeyStoreManagementException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public KeyStoreManagementException(String errorCode, String message, Throwable cause) {
+ super(message, cause);
+ this.errorCode = errorCode;
+ }
+
+ public KeyStoreManagementException(KeyStoreConstants.ErrorMessage message,
+ KeyStoreManagementException e) {
+
+
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServerException.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServerException.java
new file mode 100755
index 00000000000..c52bac36342
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServerException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+/**
+ * Handles the Keystore Management server level errors.
+ */
+public class KeyStoreManagementServerException extends KeyStoreManagementException {
+
+ public KeyStoreManagementServerException(String errorCode, String message) {
+ super(errorCode, message);
+ }
+
+ public KeyStoreManagementServerException(String errorCode, String message, Throwable cause) {
+ super(errorCode, message, cause);
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementService.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementService.java
new file mode 100755
index 00000000000..02e8e49f625
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementService.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This service contains the methods to manage certificates of the keystore and client truststore.
+ */
+public interface KeyStoreManagementService {
+
+ /**
+ * Retrieves the list of certificate aliases from the keystore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param filter used to filter the result. Supports sw, ew, eq & co. eg:filter=alias+sw+wso2.
+ * @return the {@link List} of alias.
+ * @throws KeyStoreManagementException when retrieving the certificate aliases failed.
+ */
+ List getKeyStoreCertificateAliases(String tenantDomain, String filter) throws KeyStoreManagementException;
+
+ /**
+ * Retrieves the public certificate from the keystore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @return a {@link Map} with public key alias and {@link X509Certificate}.
+ * @throws KeyStoreManagementException when retrieving the public certificate.
+ */
+ Map getPublicCertificate(String tenantDomain) throws KeyStoreManagementException;
+
+ /**
+ * Retrieves the certificate of the given alias from the keystore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param alias of the certificate.
+ * @return the {@link X509Certificate}
+ * @throws KeyStoreManagementException when retrieving the certificate failed.
+ */
+ X509Certificate getKeyStoreCertificate(String tenantDomain, String alias) throws KeyStoreManagementException;
+
+ /**
+ * Retrieves the list of certificate aliases from the client truststore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param filter used to filter the result. Supports sw, ew, eq & co. eg:filter=alias+sw+wso2.
+ * @return the {@link List} of alias
+ * @throws KeyStoreManagementException when retrieving the certificate aliases failed.
+ */
+ List getClientCertificateAliases(String tenantDomain, String filter) throws KeyStoreManagementException;
+
+ /**
+ * Retrieves the certificate of the given alias from the client truststore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param alias of the certificate.
+ * @return the {@link X509Certificate}
+ * @throws KeyStoreManagementException when retrieving the certificate failed.
+ */
+ X509Certificate getClientCertificate(String tenantDomain, String alias) throws KeyStoreManagementException;
+
+ /**
+ * Imports the certificate to the keystore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param alias of the certificate.
+ * @param certificate the certificate to be imported.
+ * @throws KeyStoreManagementException when importing the certificate failed.
+ */
+ void addCertificate(String tenantDomain, String alias, String certificate) throws KeyStoreManagementException;
+
+ /**
+ * Deletes the certificate from the keystore.
+ *
+ * @param tenantDomain tenant domain of the keystore.
+ * @param alias of the certificate.
+ * @throws KeyStoreManagementException when importing the certificate failed.
+ */
+ void deleteCertificate(String tenantDomain, String alias) throws KeyStoreManagementException;
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServiceImpl.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServiceImpl.java
new file mode 100755
index 00000000000..4a67a607632
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/KeyStoreManagementServiceImpl.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2019, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore;
+
+import org.apache.commons.lang.StringUtils;
+import org.wso2.carbon.base.MultitenantConstants;
+import org.wso2.carbon.base.ServerConfiguration;
+import org.wso2.carbon.core.internal.KeyStoreMgtDataHolder;
+import org.wso2.carbon.core.keystore.constants.KeyStoreConstants;
+import org.wso2.carbon.core.util.KeyStoreUtil;
+import org.wso2.carbon.core.keystore.service.CertData;
+import org.wso2.carbon.core.keystore.service.CertDataDetail;
+import org.wso2.carbon.core.keystore.service.KeyStoreData;
+import org.wso2.carbon.user.api.TenantManager;
+import org.wso2.carbon.user.api.UserRealmService;
+import org.wso2.carbon.user.api.UserStoreException;
+
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_ALIAS_EXISTS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_BAD_VALUE_FOR_FILTER;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_CANNOT_DELETE_TENANT_CERT;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_CERTIFICATE_EXISTS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_DELETE_CERTIFICATE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_EMPTY_ALIAS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_INITIALIZE_REGISTRY;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE_CERTIFICATE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_RETRIEVE_KEYSTORE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_RETRIEVE_KEYSTORE_INFORMATION;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_UNSUPPORTED_FILTER_OPERATION;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.ErrorMessage.ERROR_CODE_VALIDATE_CERTIFICATE;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.FILTER_FIELD_ALIAS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.FILTER_OPERATION_CONTAINS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.FILTER_OPERATION_ENDS_WITH;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.FILTER_OPERATION_EQUALS;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.FILTER_OPERATION_STARTS_WITH;
+import static org.wso2.carbon.core.keystore.constants.KeyStoreConstants.SERVER_TRUSTSTORE_FILE;
+
+/**
+ * This class is used to manage the keystore certificates.
+ */
+public class KeyStoreManagementServiceImpl implements KeyStoreManagementService {
+
+ @Override
+ public List getKeyStoreCertificateAliases(String tenantDomain, String filter)
+ throws KeyStoreManagementException {
+
+ KeyStoreData keyStoreInfo = getKeystoreData(tenantDomain, getKeyStoreName(tenantDomain));
+ return filterAlias(getAliasList(keyStoreInfo), filter);
+ }
+
+ @Override
+ public Map getPublicCertificate(String tenantDomain) throws KeyStoreManagementException {
+
+ Map certData = new HashMap<>();
+ KeyStoreData keyStoreInfo = getKeystoreData(tenantDomain, getKeyStoreName(tenantDomain));
+ CertData key = keyStoreInfo.getKey();
+ certData.put(key.getAlias(), ((CertDataDetail) key).getCertificate());
+ return certData;
+ }
+
+ @Override
+ public X509Certificate getKeyStoreCertificate(String tenantDomain, String alias)
+ throws KeyStoreManagementException {
+
+ if (StringUtils.isEmpty(alias)) {
+ throw handleClientException(ERROR_CODE_EMPTY_ALIAS, null);
+ }
+
+ KeyStoreData keyStoreInfo = getKeystoreData(tenantDomain, getKeyStoreName(tenantDomain));
+ CertData key = keyStoreInfo.getKey();
+ if (key != null && StringUtils.equals(key.getAlias(), alias)) {
+ return ((CertDataDetail) key).getCertificate();
+ }
+
+ CertData[] certDataArray = keyStoreInfo.getCerts();
+ for (CertData certData : certDataArray) {
+ String aliasFromKeyStore = certData.getAlias();
+ if (StringUtils.equals(aliasFromKeyStore, alias)) {
+ return ((CertDataDetail) certData).getCertificate();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public List getClientCertificateAliases(String tenantDomain, String filter)
+ throws KeyStoreManagementException {
+
+ KeyStoreData truststoreInfo = getKeystoreData(tenantDomain, getTrustStoreName());
+ return filterAlias(getAliasList(truststoreInfo), filter);
+ }
+
+ @Override
+ public X509Certificate getClientCertificate(String tenantDomain, String alias) throws KeyStoreManagementException {
+
+ if (StringUtils.isEmpty(alias)) {
+ throw handleClientException(ERROR_CODE_EMPTY_ALIAS, null);
+ }
+
+ KeyStore trustStore = null;
+ try {
+ trustStore = getKeyStoreAdmin(tenantDomain).getTrustStore();
+ } catch (KeyStoreManagementException e) {
+ throw handleServerException(ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE, tenantDomain, e);
+ }
+
+ if (trustStore != null) {
+ try {
+ if (trustStore.containsAlias(alias)) {
+ return (X509Certificate) trustStore.getCertificate(alias);
+ }
+ } catch (KeyStoreException e) {
+ throw handleServerException(ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE_CERTIFICATE, alias, e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void addCertificate(String tenantDomain, String alias, String certificate)
+ throws KeyStoreManagementException {
+
+ KeyStoreAdmin keyStoreAdmin = getKeyStoreAdmin(tenantDomain);
+ String keyStoreName = getKeyStoreName(tenantDomain);
+ X509Certificate cert;
+ cert = keyStoreAdmin.extractCertificate(certificate);
+ KeyStore keyStore;
+ String certAlias;
+ boolean isAliasExists;
+ try {
+ keyStore = keyStoreAdmin.getKeyStore(keyStoreName);
+ isAliasExists = keyStore.containsAlias(alias);
+ certAlias = keyStore.getCertificateAlias(cert);
+ } catch (Exception e) {
+ throw handleServerException(ERROR_CODE_VALIDATE_CERTIFICATE, null, e);
+ }
+ if (isAliasExists) {
+ throw handleClientException(ERROR_CODE_ALIAS_EXISTS, alias);
+ }
+ if (certAlias != null) {
+ throw handleClientException(ERROR_CODE_CERTIFICATE_EXISTS, certAlias);
+ }
+ keyStoreAdmin.importCertToStore(alias, certificate, keyStoreName);
+ }
+
+ @Override
+ public void deleteCertificate(String tenantDomain, String alias) throws KeyStoreManagementException {
+
+ try {
+ Map publicCertificate = getPublicCertificate(tenantDomain);
+ if (publicCertificate.keySet().contains(alias)) {
+ throw handleClientException(ERROR_CODE_CANNOT_DELETE_TENANT_CERT, alias);
+ }
+ getKeyStoreAdmin(tenantDomain).removeCertFromStore(alias, getKeyStoreName(tenantDomain));
+ } catch (KeyStoreManagementException e) {
+ throw handleServerException(ERROR_CODE_DELETE_CERTIFICATE, alias, e);
+ }
+ }
+
+ private String getKeyStoreName(String tenantDomain) throws KeyStoreManagementException {
+
+ KeyStoreData[] keyStoreDataArray = getKeyStoreAdmin(tenantDomain).getKeyStores(isSuperTenant(tenantDomain));
+
+ for (KeyStoreData keyStoreData : keyStoreDataArray) {
+ if (keyStoreData == null) {
+ break;
+ }
+ String keyStoreName = keyStoreData.getKeyStoreName();
+ if (isSuperTenant(tenantDomain)) {
+ if (KeyStoreUtil.isPrimaryStore(keyStoreName)) {
+ return keyStoreName;
+ }
+ } else {
+ String tenantKeyStoreName = tenantDomain.trim().replace(".", "-") + ".jks";
+ if (StringUtils.equals(keyStoreName, tenantKeyStoreName)) {
+ return keyStoreName;
+ }
+ }
+ }
+ throw handleServerException(ERROR_CODE_RETRIEVE_KEYSTORE, tenantDomain);
+ }
+
+ private KeyStoreData getKeystoreData(String tenantDomain, String keyStoreName) throws KeyStoreManagementException {
+
+ KeyStoreAdmin keyStoreAdmin = getKeyStoreAdmin(tenantDomain);
+ KeyStoreData keyStoreData = null;
+ keyStoreAdmin.setIncludeCert(true);
+ try {
+ keyStoreData = keyStoreAdmin.getKeystoreInfo(keyStoreName);
+ } catch (KeyStoreManagementException e) {
+ throw handleServerException(ERROR_CODE_RETRIEVE_KEYSTORE_INFORMATION, keyStoreName, e);
+ }
+ return keyStoreData;
+ }
+
+ private List getAliasList(KeyStoreData keyStoreData) {
+
+ List aliasList = new ArrayList<>();
+ CertData key = keyStoreData.getKey();
+ if (key != null && key.getAlias() != null) {
+ aliasList.add(key.getAlias());
+ }
+
+ CertData[] certDataArray = keyStoreData.getCerts();
+ for (CertData certData : certDataArray) {
+ String alias = certData.getAlias();
+ if (alias != null) {
+ aliasList.add(alias);
+ }
+ }
+ return aliasList;
+ }
+
+ private List filterAlias(List aliases, String filter) throws KeyStoreManagementException {
+
+ if (filter != null) {
+ filter = filter.replace(" ", "+");
+ String[] extractedFilter = filter.split("[+]");
+ if (extractedFilter.length == 3) {
+ if (StringUtils.equals(extractedFilter[0], FILTER_FIELD_ALIAS)) {
+ String operation = extractedFilter[1];
+ String value = extractedFilter[2];
+ if (StringUtils.equals(operation, FILTER_OPERATION_EQUALS)) {
+ aliases = aliases.stream().filter(alias -> alias.matches(value))
+ .collect(Collectors.toList());
+ } else if (StringUtils.equals(operation, FILTER_OPERATION_STARTS_WITH)) {
+ aliases = aliases.stream().filter(alias -> alias.startsWith(value))
+ .collect(Collectors.toList());
+ } else if (StringUtils.equals(operation, FILTER_OPERATION_ENDS_WITH)) {
+ aliases = aliases.stream().filter(alias -> alias.endsWith(value))
+ .collect(Collectors.toList());
+ } else if (StringUtils.equals(operation, FILTER_OPERATION_CONTAINS)) {
+ aliases = aliases.stream().filter(alias -> alias.contains(value))
+ .collect(Collectors.toList());
+ } else {
+ throw handleClientException(ERROR_CODE_UNSUPPORTED_FILTER_OPERATION, operation);
+ }
+ }
+ } else {
+ throw handleClientException(ERROR_CODE_BAD_VALUE_FOR_FILTER, filter);
+ }
+ }
+ return aliases;
+ }
+
+ private int getTenantId(String tenantDomain) throws KeyStoreManagementServerException {
+
+ try {
+ UserRealmService userRealmService = KeyStoreMgtDataHolder.getRealmService();
+ TenantManager tenantManager = userRealmService.getTenantManager();
+ return tenantManager.getTenantId(tenantDomain);
+ } catch (KeyStoreManagementException | UserStoreException e) {
+ throw handleServerException(ERROR_CODE_INITIALIZE_REGISTRY, tenantDomain, e);
+ }
+ }
+
+ private KeyStoreAdmin getKeyStoreAdmin(String tenantDomain) throws KeyStoreManagementServerException {
+
+ return new KeyStoreAdmin(getTenantId(tenantDomain));
+ }
+
+ private boolean isSuperTenant(String tenantDomain) throws KeyStoreManagementServerException {
+
+ return getTenantId(tenantDomain) == MultitenantConstants.SUPER_TENANT_ID;
+ }
+
+ private String getTrustStoreName() {
+
+ ServerConfiguration serverConfiguration = ServerConfiguration.getInstance();
+ String filePath = serverConfiguration.getFirstProperty(SERVER_TRUSTSTORE_FILE);
+ return Paths.get(filePath).getFileName().toString();
+ }
+
+ private KeyStoreManagementServerException handleServerException(
+ KeyStoreConstants.ErrorMessage error, String data) {
+
+ String message = includeData(error, data);
+ return new KeyStoreManagementServerException(error.getCode(), message);
+ }
+
+ private KeyStoreManagementServerException handleServerException(
+ KeyStoreConstants.ErrorMessage error, String data,
+ Throwable e) {
+
+ String message = includeData(error, data);
+ return new KeyStoreManagementServerException(error.getCode(), message, e);
+ }
+
+ private KeyStoreManagementClientException handleClientException(
+ KeyStoreConstants.ErrorMessage error, String data) {
+
+ String message = includeData(error, data);
+ return new KeyStoreManagementClientException(error.getCode(), message);
+ }
+
+ private static String includeData(KeyStoreConstants.ErrorMessage error, String data) {
+
+ String message;
+ if (StringUtils.isNotBlank(data)) {
+ message = String.format(error.getMessage(), data);
+ } else {
+ message = error.getMessage();
+ }
+ return message;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/constants/KeyStoreConstants.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/constants/KeyStoreConstants.java
new file mode 100644
index 00000000000..bc38e3c51da
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/constants/KeyStoreConstants.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.constants;
+
+import org.wso2.carbon.core.RegistryResources;
+
+/**
+ * Constants related to the KeyStore Management.
+ */
+public class KeyStoreConstants {
+
+ public static final String FILTER_FIELD_ALIAS = "alias";
+ public static final String FILTER_OPERATION_EQUALS = "eq";
+ public static final String FILTER_OPERATION_STARTS_WITH = "sw";
+ public static final String FILTER_OPERATION_ENDS_WITH = "ew";
+ public static final String FILTER_OPERATION_CONTAINS = "co";
+ public static final int ITEMS_PER_PAGE = 10;
+ public static final int CACHING_PAGE_SIZE = 5;
+ public static final String KEY_STORES = RegistryResources.SecurityManagement.KEY_STORES;
+ public static final String SERVER_TRUSTSTORE_FILE = "Security.TrustStore.Location";
+ public static final String KEYSTORE_DATASOURCE = "KeyStoreDataPersistenceManager.DataSource.Name";
+
+ /**
+ * Enum for Keystore management service related errors.
+ */
+ public enum ErrorMessage {
+
+ /**
+ * Server errors.
+ */
+ ERROR_CODE_RETRIEVE_KEYSTORE("KSS-65001",
+ "Unable to retrieve the keystore for tenant: %s."),
+ ERROR_CODE_RETRIEVE_KEYSTORE_INFORMATION("KSS-65002",
+ "Unable to retrieve keystore information for keystore: %s"),
+ ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE("KSS-65003",
+ "Unable to retrieve client truststore for tenant: %s"),
+ ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE_ALIASES("KSS-65004",
+ "Unable to retrieve the client truststore aliases for tenant: %s."),
+ ERROR_CODE_RETRIEVE_CLIENT_TRUSTSTORE_CERTIFICATE("KSS-65005",
+ "Unable to retrieve the client truststore certificate for alias: %s."),
+ ERROR_CODE_ADD_CERTIFICATE("KSS-65006",
+ "Unable to add certificate with alias: %s"),
+ ERROR_CODE_DELETE_CERTIFICATE("KSS-65007",
+ "Unable to delete certificate with alias: %s"),
+ ERROR_CODE_VALIDATE_CERTIFICATE("KSS-65008", "Error occurred while validating the " +
+ "certificate."),
+ ERROR_CODE_INITIALIZE_REGISTRY("KSS-65009",
+ "Unable to initialize the registry for the tenant: %s."),
+ /**
+ * Client error.
+ */
+ ERROR_CODE_CERTIFICATE_EXISTS("KSS-60001",
+ "Provided certificate already exists with the alias: %s"),
+ ERROR_CODE_ALIAS_EXISTS("KSS-60002",
+ "Provided alias '%s' is already available in the keystore."),
+ ERROR_CODE_BAD_VALUE_FOR_FILTER("KSS-60003",
+ "Unsupported filter: %s."),
+ ERROR_CODE_UNSUPPORTED_FILTER_OPERATION("KSS-60004",
+ "Unsupported filter operation %s."),
+ ERROR_CODE_EMPTY_ALIAS("KSS-60005", "Alias value can not be null."),
+ ERROR_CODE_INVALID_CERTIFICATE("KSS-60006", "Provided certificate is invalid."),
+ ERROR_CODE_CANNOT_DELETE_TENANT_CERT("KSS-60007", "Not allowed to delete the tenant certificate %s."),
+
+ /**
+ * Common Error messages without a code.
+ */
+ ERROR_MESSAGE_RETRIEVE_KEYSTORE("KSS-62501", "Error when getting keyStore data."),
+ ERROR_MESSAGE_RETRIEVE_PUBLIC_CERT("KSS-62502", "Error when getting public certificate data.");
+ private final String code;
+ private final String message;
+
+ ErrorMessage(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return code + " : " + message;
+ }
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/KeyStoreDAO.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/KeyStoreDAO.java
new file mode 100755
index 00000000000..356e86e78a1
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/KeyStoreDAO.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao;
+
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.model.KeyStoreModel;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Data Access Object for KeyStore.
+ */
+public interface KeyStoreDAO {
+
+ /**
+ * Add a new KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param keyStoreModel KeyStore model where the keystore data is maintained.
+ * @throws KeyStoreManagementException If an error occurs while adding the KeyStore.
+ */
+ void addKeyStore(String tenantUUID, KeyStoreModel keyStoreModel) throws
+ KeyStoreManagementException;
+
+ /**
+ * Get all KeyStores.
+ *
+ * @param tenantUUID tenant UUID
+ * @return List of KeyStoreModels.
+ * @throws KeyStoreManagementException If an error occurs while retrieving the KeyStores.
+ */
+ List getKeyStores(String tenantUUID) throws KeyStoreManagementException;
+
+ /**
+ * Get a KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param fileName Name of the KeyStore file.
+ * @return KeyStoreModel.
+ * @throws KeyStoreManagementException If an error occurs while retrieving the KeyStore.
+ */
+ Optional getKeyStore(String tenantUUID, String fileName) throws KeyStoreManagementException;
+
+ /**
+ * Delete a KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param fileName Name of the KeyStore file.
+ * @throws KeyStoreManagementException If an error occurs while deleting the KeyStore.
+ */
+ void deleteKeyStore(String tenantUUID, String fileName) throws KeyStoreManagementException;
+
+ /**
+ * Update a KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param keyStoreModel KeyStore model where the keystore data is maintained.
+ * @throws KeyStoreManagementException If an error occurs while updating the KeyStore.
+ */
+ void updateKeyStore(String tenantUUID, KeyStoreModel keyStoreModel) throws KeyStoreManagementException;
+
+ /**
+ * Add a public certificate to a KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param fileName Name of the KeyStore file.
+ * @param pubCertId Public certificate ID.
+ * @throws KeyStoreManagementException If an error occurs while adding the public certificate.
+ */
+ void addPubCertIdToKeyStore(String tenantUUID, String fileName, String pubCertId)
+ throws KeyStoreManagementException;
+
+ /**
+ * Get the public certificate ID of a KeyStore.
+ *
+ * @param tenantUUID Tenant UUID.
+ * @param fileName Name of the KeyStore file.
+ * @return Public certificate ID.
+ * @throws KeyStoreManagementException If an error occurs while retrieving the public certificate ID.
+ */
+ Optional getPubCertIdFromKeyStore(String tenantUUID, String fileName) throws KeyStoreManagementException;
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/PubCertDAO.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/PubCertDAO.java
new file mode 100755
index 00000000000..d9ca212591f
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/PubCertDAO.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao;
+
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.model.PubCertModel;
+
+import java.util.Optional;
+
+/**
+ * Data Access Object for PubCert.
+ */
+public interface PubCertDAO {
+
+ /**
+ * Add a new Public Certificate.
+ *
+ * @param pubCertModel PubCert model where the PubCert data is maintained.
+ * @throws KeyStoreManagementException If an error occurs while adding the PubCert.
+ */
+ String addPubCert(PubCertModel pubCertModel) throws KeyStoreManagementException;
+
+ /**
+ * Get a Public Certificate.
+ *
+ * @param uuid UUID of the PubCert.
+ * @return PubCertModel.
+ * @throws KeyStoreManagementException If an error occurs while retrieving the PubCert.
+ */
+ Optional getPubCert(String uuid) throws KeyStoreManagementException;
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/KeyStoreDAOConstants.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/KeyStoreDAOConstants.java
new file mode 100755
index 00000000000..f70b195f18d
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/KeyStoreDAOConstants.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao.constants;
+
+/**
+ * Constants related to the KeyStoreDAO.
+ */
+public class KeyStoreDAOConstants {
+
+ private KeyStoreDAOConstants() {
+
+ }
+
+ public static class KeyStoreTableColumns {
+
+ private KeyStoreTableColumns() {
+
+ }
+
+ public static final String ID = "ID";
+ public static final String FILE_NAME = "FILE_NAME";
+ public static final String TYPE = "TYPE";
+ public static final String PROVIDER = "PROVIDER";
+ public static final String PASSWORD = "PASSWORD";
+ public static final String PRIVATE_KEY_ALIAS = "PRIVATE_KEY_ALIAS";
+ public static final String PRIVATE_KEY_PASS = "PRIVATE_KEY_PASS";
+ public static final String TENANT_UUID = "TENANT_UUID";
+ public static final String PUB_CERT_ID = "PUB_CERT_ID";
+ public static final String LAST_UPDATED = "LAST_UPDATED";
+ public static final String CONTENT = "CONTENT";
+ }
+
+ public static class SqlQueries {
+
+ private SqlQueries() {
+
+ }
+
+ public static final String ADD_KEY_STORE = "INSERT INTO IDN_KEY_STORE " +
+ "(ID, FILE_NAME, TYPE, PROVIDER, PASSWORD, PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASS, TENANT_UUID, " +
+ "LAST_UPDATED, CONTENT) VALUES (:ID;, :FILE_NAME;, :TYPE;, :PROVIDER;, :PASSWORD;, " +
+ ":PRIVATE_KEY_ALIAS;, :PRIVATE_KEY_PASS;, :TENANT_UUID;, :LAST_UPDATED;, ?)";
+
+ public static final String UPDATE_KEY_STORE_BY_FILE_NAME = "UPDATE IDN_KEY_STORE SET TYPE = :TYPE;, " +
+ "PROVIDER = :PROVIDER;, PASSWORD = :PASSWORD;, PRIVATE_KEY_ALIAS = :PRIVATE_KEY_ALIAS;, " +
+ "PRIVATE_KEY_PASS = :PRIVATE_KEY_PASS;, LAST_UPDATED = :LAST_UPDATED;, CONTENT = ? " +
+ "WHERE FILE_NAME = :FILE_NAME; AND TENANT_UUID = :TENANT_UUID;";
+
+ public static final String GET_KEY_STORE_BY_ID =
+ "SELECT * FROM IDN_KEY_STORE WHERE ID = :ID;";
+
+ public static final String GET_KEY_STORE_BY_FILE_NAME =
+ "SELECT * FROM IDN_KEY_STORE WHERE FILE_NAME = :FILE_NAME; AND TENANT_UUID = :TENANT_UUID;";
+
+ public static final String GET_KEY_STORES =
+ "SELECT * FROM IDN_KEY_STORE WHERE TENANT_UUID = :TENANT_UUID;";
+
+ public static final String DELETE_KEY_STORE_BY_ID =
+ "DELETE FROM IDN_KEY_STORE WHERE ID = :ID; AND TENANT_UUID = :TENANT_UUID;";
+
+ public static final String DELETE_KEY_STORE_BY_FILE_NAME =
+ "DELETE FROM IDN_KEY_STORE WHERE FILE_NAME = :FILE_NAME; AND TENANT_UUID = :TENANT_UUID;";
+
+ // TODO: refactor to use named prep statement after adding a method to set named bytes in named prep statement.
+
+ public static final String GET_PUB_CERT_ID_OF_KEY_STORE =
+ "SELECT PUB_CERT_ID FROM IDN_KEY_STORE WHERE FILE_NAME = :FILE_NAME; AND TENANT_UUID = :TENANT_UUID;";
+
+ public static final String ADD_PUB_CERT_ID_TO_KEY_STORE =
+ "UPDATE IDN_KEY_STORE SET PUB_CERT_ID = :PUB_CERT_ID;, LAST_UPDATED = :LAST_UPDATED; " +
+ "WHERE FILE_NAME = :FILE_NAME; AND TENANT_UUID = :TENANT_UUID;";
+ }
+
+ public static class ErrorMessages {
+
+ private ErrorMessages() {
+
+ }
+
+ public static final String ERROR_ADD_KEY_STORE = "Error while adding key store.";
+ public static final String ERROR_UPDATE_KEY_STORE = "Error while updating key store.";
+ public static final String ERROR_GET_KEY_STORES = "Error while retrieving key stores.";
+ public static final String ERROR_GET_KEY_STORE = "Error while retrieving the key store.";
+ public static final String ERROR_DELETE_KEY_STORE_BY_FILE_NAME = "Error while deleting key store by file name.";
+ public static final String ERROR_LINK_PUB_CERT_TO_KEY_STORE = "Error while linking public certificate to key " +
+ "store.";
+ public static final String ERROR_GET_PUB_CERT_OF_KEY_STORE = "Error while retrieving public certificate of " +
+ "key store.";
+ public static final String ERROR_CANNOT_RETRIEVE_DB_CONN = "Error while retrieving database connection.";
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/PubCertDAOConstants.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/PubCertDAOConstants.java
new file mode 100755
index 00000000000..405bb7a2bc2
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/constants/PubCertDAOConstants.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao.constants;
+
+/**
+ * Constants related to the PubCertDAOConstants
+ */
+public class PubCertDAOConstants {
+
+ private PubCertDAOConstants() {}
+
+ public static class PubCertTableColumns {
+
+ private PubCertTableColumns() {}
+ public static final String ID = "ID";
+ public static final String FILE_NAME_APPENDER = "FILE_NAME_APPENDER";
+ public static final String TENANT_UUID = "TENANT_UUID";
+ public static final String CONTENT = "CONTENT";
+ }
+
+ public static class SQLQueries {
+
+ private SQLQueries() {}
+
+ public static final String ADD_PUB_CERT = "INSERT INTO IDN_PUB_CERT (ID, FILE_NAME_APPENDER, CONTENT) " +
+ "VALUES (:ID;, :FILE_NAME_APPENDER;, ?)";
+
+ public static final String GET_PUB_CERT =
+ "SELECT * FROM IDN_PUB_CERT WHERE ID = :ID;";
+ }
+
+ public static class ErrorMessages {
+
+ private ErrorMessages() {}
+
+ public static final String ERROR_MESSAGE_ADDING_PUB_CERT = "Error while adding public certificate.";
+ public static final String ERROR_MESSAGE_RETRIEVING_PUB_CERT = "Error while retrieving public certificate.";
+ public static final String DB_CONN_RETRIEVAL_ERROR_MSG = "Error while getting the DB connection.";
+ }
+
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/KeyStoreDAOImpl.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/KeyStoreDAOImpl.java
new file mode 100755
index 00000000000..27be4b6cca4
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/KeyStoreDAOImpl.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao.impl;
+
+import org.wso2.carbon.core.internal.KeyStoreMgtDataHolder;
+import org.wso2.carbon.database.utils.jdbc.NamedPreparedStatement;
+import org.wso2.carbon.user.core.util.DatabaseUtil;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.dao.KeyStoreDAO;
+import org.wso2.carbon.core.keystore.dao.constants.KeyStoreDAOConstants;
+import org.wso2.carbon.core.keystore.dao.constants.KeyStoreDAOConstants.KeyStoreTableColumns;
+import org.wso2.carbon.core.keystore.model.KeyStoreModel;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.TimeZone;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import static java.time.ZoneOffset.UTC;
+
+/**
+ * This class provides the implementation of the KeyStoreDAO interface.
+ */
+public class KeyStoreDAOImpl implements KeyStoreDAO {
+
+ private final Calendar CALENDAR = Calendar.getInstance(TimeZone.getTimeZone(UTC));
+ private final DataSource dataSource;
+
+ public KeyStoreDAOImpl() {
+
+ this.dataSource = KeyStoreMgtDataHolder.getDataSource();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addKeyStore(String tenantUUID, KeyStoreModel keyStoreModel) throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try {
+ processAddKeyStore(connection, keyStoreModel, tenantUUID);
+ connection.commit();
+ } catch (SQLException e) {
+ connection.rollback();
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_ADD_KEY_STORE, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List getKeyStores(String tenantUUID) throws KeyStoreManagementException {
+
+ List keyStores = new ArrayList<>();
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.GET_KEY_STORES)) {
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ try (ResultSet resultSet = statement.executeQuery()) {
+ while (resultSet.next()) {
+ keyStores.add(mapResultToKeyStoreModel(resultSet));
+ }
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_GET_KEY_STORES, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+
+ return keyStores;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getKeyStore(String tenantUUID, String fileName) throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.GET_KEY_STORE_BY_FILE_NAME)) {
+ statement.setString(KeyStoreTableColumns.FILE_NAME, fileName);
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ try (ResultSet resultSet = statement.executeQuery()) {
+ if (resultSet.next()) {
+ return Optional.of(mapResultToKeyStoreModel(resultSet));
+ }
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_GET_KEY_STORE, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deleteKeyStore(String tenantUUID, String fileName) throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.DELETE_KEY_STORE_BY_FILE_NAME)) {
+ statement.setString(KeyStoreTableColumns.FILE_NAME, fileName);
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ statement.executeUpdate();
+
+ connection.commit();
+ } catch (SQLException e) {
+ connection.rollback();
+ throw new KeyStoreManagementException(
+ KeyStoreDAOConstants.ErrorMessages.ERROR_DELETE_KEY_STORE_BY_FILE_NAME, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void updateKeyStore(String tenantUUID, KeyStoreModel keyStoreModel) throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try {
+ processUpdateKeyStore(connection, keyStoreModel, tenantUUID);
+ connection.commit();
+ } catch (SQLException e) {
+ connection.rollback();
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_UPDATE_KEY_STORE, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addPubCertIdToKeyStore(String tenantUUID, String fileName, String pubCertId)
+ throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.ADD_PUB_CERT_ID_TO_KEY_STORE)) {
+ statement.setString(KeyStoreTableColumns.PUB_CERT_ID, pubCertId);
+ statement.setTimeStamp(KeyStoreTableColumns.LAST_UPDATED, new Timestamp(new Date().getTime()),
+ CALENDAR);
+ statement.setString(KeyStoreTableColumns.FILE_NAME, fileName);
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ statement.executeUpdate();
+
+ connection.commit();
+ } catch (SQLException e) {
+ connection.rollback();
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages
+ .ERROR_LINK_PUB_CERT_TO_KEY_STORE, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getPubCertIdFromKeyStore(String tenantUUID, String fileName)
+ throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.GET_PUB_CERT_ID_OF_KEY_STORE)) {
+ statement.setString(KeyStoreTableColumns.FILE_NAME, fileName);
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ try (ResultSet resultSet = statement.executeQuery()) {
+ if (resultSet.next()) {
+ return Optional.ofNullable(resultSet.getString(KeyStoreTableColumns.PUB_CERT_ID));
+ }
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages
+ .ERROR_GET_PUB_CERT_OF_KEY_STORE, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(KeyStoreDAOConstants.ErrorMessages.ERROR_CANNOT_RETRIEVE_DB_CONN, e);
+ }
+ return Optional.empty();
+ }
+
+ private KeyStoreModel mapResultToKeyStoreModel(ResultSet resultSet) throws SQLException {
+
+ return new KeyStoreModel.KeyStoreModelBuilder()
+ .type(resultSet.getString(KeyStoreTableColumns.TYPE))
+ .provider(resultSet.getString(KeyStoreTableColumns.PROVIDER))
+ .fileName(resultSet.getString(KeyStoreTableColumns.FILE_NAME))
+ .password(resultSet.getString(KeyStoreTableColumns.PASSWORD).toCharArray())
+ .privateKeyAlias(resultSet.getString(KeyStoreTableColumns.PRIVATE_KEY_ALIAS))
+ .privateKeyPass(resultSet.getString(KeyStoreTableColumns.PRIVATE_KEY_PASS).toCharArray())
+ .content(resultSet.getBytes(KeyStoreTableColumns.CONTENT))
+ .lastUpdated(resultSet.getTimestamp(KeyStoreTableColumns.LAST_UPDATED))
+ .build();
+ }
+
+ private void processAddKeyStore(Connection connection, KeyStoreModel keyStoreModel, String tenantUUID)
+ throws SQLException {
+
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.ADD_KEY_STORE)) {
+ statement.setString(KeyStoreTableColumns.ID, UUID.randomUUID().toString());
+ statement.setString(KeyStoreTableColumns.FILE_NAME, keyStoreModel.getFileName());
+ statement.setString(KeyStoreTableColumns.TYPE, keyStoreModel.getType());
+ statement.setString(KeyStoreTableColumns.PROVIDER, keyStoreModel.getProvider());
+ statement.setString(KeyStoreTableColumns.PASSWORD, String.valueOf(keyStoreModel.getPassword()));
+ // todo: check whether are we storing a null or an empty string when the field is not set?
+ statement.setString(KeyStoreTableColumns.PRIVATE_KEY_ALIAS, keyStoreModel.getPrivateKeyAlias());
+ statement.setString(KeyStoreTableColumns.PRIVATE_KEY_PASS,
+ String.valueOf(keyStoreModel.getPrivateKeyPass()));
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ statement.setTimeStamp(KeyStoreTableColumns.LAST_UPDATED, new Timestamp(new Date().getTime()), CALENDAR);
+ statement.setBytes(10, keyStoreModel.getContent());
+ statement.executeUpdate();
+ }
+ }
+
+ private void processUpdateKeyStore(Connection connection, KeyStoreModel keyStoreModel, String tenantUUID)
+ throws SQLException {
+
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ KeyStoreDAOConstants.SqlQueries.UPDATE_KEY_STORE_BY_FILE_NAME)) {
+ statement.setString(KeyStoreTableColumns.TYPE, keyStoreModel.getType());
+ statement.setString(KeyStoreTableColumns.PROVIDER, keyStoreModel.getProvider());
+ statement.setString(KeyStoreTableColumns.PASSWORD, String.valueOf(keyStoreModel.getPassword()));
+ statement.setString(KeyStoreTableColumns.PRIVATE_KEY_ALIAS, keyStoreModel.getPrivateKeyAlias());
+ statement.setString(KeyStoreTableColumns.PRIVATE_KEY_PASS,
+ String.valueOf(keyStoreModel.getPrivateKeyPass()));
+ statement.setTimeStamp(KeyStoreTableColumns.LAST_UPDATED, new Timestamp(new Date().getTime()), CALENDAR);
+ statement.setBytes(7, keyStoreModel.getContent());
+ statement.setString(KeyStoreTableColumns.FILE_NAME, keyStoreModel.getFileName());
+ statement.setString(KeyStoreTableColumns.TENANT_UUID, tenantUUID);
+ statement.executeUpdate();
+ }
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/PubCertDAOImpl.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/PubCertDAOImpl.java
new file mode 100755
index 00000000000..f16f4e644c1
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/dao/impl/PubCertDAOImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.dao.impl;
+
+import org.wso2.carbon.core.internal.KeyStoreMgtDataHolder;
+import org.wso2.carbon.database.utils.jdbc.NamedPreparedStatement;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.dao.PubCertDAO;
+import org.wso2.carbon.core.keystore.dao.constants.PubCertDAOConstants;
+import org.wso2.carbon.core.keystore.dao.constants.PubCertDAOConstants.PubCertTableColumns;
+import org.wso2.carbon.core.keystore.model.PubCertModel;
+import org.wso2.carbon.user.core.util.DatabaseUtil;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+/**
+ * This class provides the implementation of the PubCertDAO interface.
+ */
+public class PubCertDAOImpl implements PubCertDAO {
+
+ private final DataSource dataSource;
+
+ public PubCertDAOImpl() {
+
+ this.dataSource = KeyStoreMgtDataHolder.getDataSource();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String addPubCert(PubCertModel pubCertModel) throws KeyStoreManagementException {
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try {
+ String uuid = processAddPubCert(connection, pubCertModel);
+ connection.commit();
+ return uuid;
+ } catch (SQLException e) {
+ connection.rollback();
+ throw new KeyStoreManagementException(PubCertDAOConstants.ErrorMessages.ERROR_MESSAGE_ADDING_PUB_CERT,
+ e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(PubCertDAOConstants.ErrorMessages.DB_CONN_RETRIEVAL_ERROR_MSG, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getPubCert(String uuid) throws KeyStoreManagementException {
+
+ PubCertModel pubCertModel = null;
+
+ try (Connection connection = DatabaseUtil.getDBConnection(this.dataSource)) {
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ PubCertDAOConstants.SQLQueries.GET_PUB_CERT)) {
+ statement.setString(PubCertTableColumns.ID, uuid);
+ statement.setMaxRows(1);
+ try (ResultSet resultSet = statement.executeQuery()) {
+ if (resultSet.next()) {
+ pubCertModel = new PubCertModel();
+ pubCertModel.setFileNameAppender(resultSet.getString(PubCertTableColumns.FILE_NAME_APPENDER));
+ pubCertModel.setContent(resultSet.getBytes(PubCertTableColumns.CONTENT));
+ }
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(PubCertDAOConstants.ErrorMessages
+ .ERROR_MESSAGE_RETRIEVING_PUB_CERT, e);
+ }
+ } catch (SQLException e) {
+ throw new KeyStoreManagementException(PubCertDAOConstants.ErrorMessages.DB_CONN_RETRIEVAL_ERROR_MSG, e);
+ }
+ return Optional.ofNullable(pubCertModel);
+ }
+
+ private String processAddPubCert(Connection connection, PubCertModel pubCertModel)
+ throws SQLException {
+
+ String id = UUID.randomUUID().toString();
+
+ try (NamedPreparedStatement statement = new NamedPreparedStatement(connection,
+ PubCertDAOConstants.SQLQueries.ADD_PUB_CERT)) {
+ statement.setString(PubCertTableColumns.ID, id);
+ statement.setString(PubCertTableColumns.FILE_NAME_APPENDER, pubCertModel.getFileNameAppender());
+ statement.setBytes(3, pubCertModel.getContent());
+ statement.executeUpdate();
+ }
+ return id;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/KeyStoreModel.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/KeyStoreModel.java
new file mode 100755
index 00000000000..ffd0c018152
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/KeyStoreModel.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.model;
+
+import java.util.Date;
+
+/**
+ * Model class for KeyStore.
+ */
+public class KeyStoreModel {
+
+ // TODO: check whether we need the uuid.
+ private final String id;
+ private final String fileName;
+ private final String type;
+ private final String provider;
+ private final char[] password;
+ private final String privateKeyAlias;
+ private final char[] privateKeyPass;
+ private final Date lastUpdated;
+ private final byte[] content;
+
+ public KeyStoreModel(KeyStoreModelBuilder builder) {
+
+ this.id = builder.id;
+ this.fileName = builder.fileName;
+ this.type = builder.type;
+ this.provider = builder.provider;
+ this.password = builder.password;
+ this.privateKeyAlias = builder.privateKeyAlias;
+ this.privateKeyPass = builder.privateKeyPass;
+ this.lastUpdated = builder.lastUpdated;
+ this.content = builder.content;
+ }
+
+ public String getId() {
+
+ return id;
+ }
+
+ public String getFileName() {
+
+ return fileName;
+ }
+
+ public String getType() {
+
+ return type;
+ }
+
+ public String getProvider() {
+
+ return provider;
+ }
+
+ public char[] getPassword() {
+
+ return password;
+ }
+
+ public String getPrivateKeyAlias() {
+
+ return privateKeyAlias;
+ }
+
+ public char[] getPrivateKeyPass() {
+
+ return privateKeyPass;
+ }
+
+ public byte[] getContent() {
+
+ return content;
+ }
+
+ public Date getLastUpdated() {
+
+ return lastUpdated;
+ }
+
+ public static class KeyStoreModelBuilder {
+
+ private String id;
+ private String fileName;
+ private String type;
+ private String provider;
+ private char[] password;
+ private String privateKeyAlias;
+ private char[] privateKeyPass;
+ private Date lastUpdated;
+ private byte[] content;
+
+ public KeyStoreModelBuilder() {
+ // Default constructor.
+ }
+
+ public KeyStoreModelBuilder id(String id) {
+
+ this.id = id;
+ return this;
+ }
+
+ public KeyStoreModelBuilder fileName(String fileName) {
+
+ this.fileName = fileName;
+ return this;
+ }
+
+ public KeyStoreModelBuilder type(String type) {
+
+ this.type = type;
+ return this;
+ }
+
+ public KeyStoreModelBuilder provider(String provider) {
+
+ this.provider = provider;
+ return this;
+ }
+
+ public KeyStoreModelBuilder password(char[] password) {
+
+ this.password = password;
+ return this;
+ }
+
+ public KeyStoreModelBuilder privateKeyAlias(String privateKeyAlias) {
+
+ this.privateKeyAlias = privateKeyAlias;
+ return this;
+ }
+
+ public KeyStoreModelBuilder privateKeyPass(char[] privateKeyPass) {
+
+ this.privateKeyPass = privateKeyPass;
+ return this;
+ }
+
+ public KeyStoreModelBuilder lastUpdated(Date lastUpdated) {
+
+ this.lastUpdated = lastUpdated;
+ return this;
+ }
+
+ public KeyStoreModelBuilder content(byte[] content) {
+
+ this.content = content;
+ return this;
+ }
+
+ public KeyStoreModel build() {
+
+ return new KeyStoreModel(this);
+ }
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/PubCertModel.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/PubCertModel.java
new file mode 100755
index 00000000000..ce69dd25945
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/model/PubCertModel.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.model;
+
+/**
+ * Model class for Public Certificate.
+ */
+public class PubCertModel {
+
+ private String fileNameAppender;
+
+ private byte[] content;
+
+ public PubCertModel() {
+ // Empty constructor for default initialization
+ }
+
+ public String getFileNameAppender() {
+
+ return fileNameAppender;
+ }
+
+ public void setFileNameAppender(String fileNameAppender) {
+
+ this.fileNameAppender = fileNameAppender;
+ }
+
+ public byte[] getContent() {
+
+ return content;
+ }
+
+ public void setContent(byte[] content) {
+
+ this.content = content;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertData.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertData.java
new file mode 100755
index 00000000000..a18429aaea3
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertData.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2005, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.service;
+
+import java.math.BigInteger;
+
+/**
+ * Model class for certificate data.
+ */
+public class CertData {
+
+ private String alias;
+ private String subjectDN;
+ private String issuerDN;
+ private BigInteger serialNumber;
+ private int version;
+ private String notBefore;
+ private String notAfter;
+ private String publicKey;
+
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getSubjectDN() {
+ return subjectDN;
+ }
+
+ public void setSubjectDN(String subjectDN) {
+ this.subjectDN = subjectDN;
+ }
+
+ public String getIssuerDN() {
+ return issuerDN;
+ }
+
+ public void setIssuerDN(String issuerDN) {
+ this.issuerDN = issuerDN;
+ }
+
+ public BigInteger getSerialNumber() {
+ return serialNumber;
+ }
+
+ public void setSerialNumber(BigInteger serialNumber) {
+ this.serialNumber = serialNumber;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public String getNotBefore() {
+ return notBefore;
+ }
+
+ public void setNotBefore(String notBefore) {
+ this.notBefore = notBefore;
+ }
+
+ public String getNotAfter() {
+ return notAfter;
+ }
+
+ public void setNotAfter(String notAfter) {
+ this.notAfter = notAfter;
+ }
+
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ }
+
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertDataDetail.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertDataDetail.java
new file mode 100755
index 00000000000..c882c0c0201
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/CertDataDetail.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.service;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * Model class for certificate data with detail.
+ */
+public class CertDataDetail extends CertData {
+ private X509Certificate certificate;
+
+ public X509Certificate getCertificate() {
+ return certificate;
+ }
+
+ public void setCertificate(X509Certificate certificate) {
+ this.certificate = certificate;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/KeyStoreData.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/KeyStoreData.java
new file mode 100755
index 00000000000..2fb6cda220f
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/KeyStoreData.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.service;
+
+/**
+ * Model class for key store data.
+ */
+public class KeyStoreData {
+
+ private CertData[] certs;
+ private CertData key;
+ private String keyValue;
+ private String keyStoreName = null;
+ private String keyStoreType = null;
+ private String provider = null;
+ private String pubKeyFilePath = null;
+ private boolean isPrivateStore = false;
+
+ public String getKeyStoreName() {
+ return keyStoreName;
+ }
+
+ public void setKeyStoreName(String keyStoreName) {
+ this.keyStoreName = keyStoreName;
+ }
+
+ public String getKeyStoreType() {
+ return keyStoreType;
+ }
+
+ public void setKeyStoreType(String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ public void setProvider(String provider) {
+ this.provider = provider;
+ }
+
+ public boolean getPrivateStore() {
+ return isPrivateStore;
+ }
+
+ public void setPrivateStore(boolean isPrivateStore) {
+ this.isPrivateStore = isPrivateStore;
+ }
+
+ public CertData[] getCerts() {
+ return certs;
+ }
+
+ public void setCerts(CertData[] certs) {
+ this.certs = certs;
+ }
+
+ public CertData getKey() {
+ return key;
+ }
+
+ public void setKey(CertData key) {
+ this.key = key;
+ }
+
+ public String getKeyValue() {
+ return keyValue;
+ }
+
+ public void setKeyValue(String keyValue) {
+ this.keyValue = keyValue;
+ }
+
+ public String getPubKeyFilePath() {
+ return pubKeyFilePath;
+ }
+
+ public void setPubKeyFilePath(String pubKeyFilePath) {
+ this.pubKeyFilePath = pubKeyFilePath;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedCertData.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedCertData.java
new file mode 100755
index 00000000000..aaf4f85d146
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedCertData.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.service;
+
+import java.util.Arrays;
+
+/**
+ * Model class for paginated cert data.
+ */
+public class PaginatedCertData {
+ private CertData[] certDataSet;
+
+ private int numberOfPages;
+
+ public CertData[] getCertDataSet() {
+ return Arrays.copyOf(certDataSet, certDataSet.length);
+ }
+
+ public void setCertDataSet(CertData[] certDataSet) {
+ this.certDataSet = Arrays.copyOf(certDataSet, certDataSet.length);
+ }
+
+ public int getNumberOfPages() {
+ return numberOfPages;
+ }
+
+ public void setNumberOfPages(int numberOfPages) {
+ this.numberOfPages = numberOfPages;
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedKeyStoreData.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedKeyStoreData.java
new file mode 100755
index 00000000000..6c27a8d21d0
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/service/PaginatedKeyStoreData.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.service;
+
+/**
+ * Model class for paginated key store data.
+ */
+public class PaginatedKeyStoreData {
+
+ private CertData key;
+ private String keyValue;
+ private String keyStoreName = null;
+ private String keyStoreType = null;
+ private String provider = null;
+ private String pubKeyFilePath = null;
+ private boolean isPrivateStore = false;
+ private PaginatedCertData paginatedCertData;
+ private PaginatedCertData paginatedKeyData;
+
+ public PaginatedCertData getPaginatedKeyData() {
+ return paginatedKeyData;
+ }
+
+ public void setPaginatedKeyData(PaginatedCertData paginatedKeyData) {
+ this.paginatedKeyData = paginatedKeyData;
+ }
+
+ public String getKeyStoreName() {
+ return keyStoreName;
+ }
+
+ public void setKeyStoreName(String keyStoreName) {
+ this.keyStoreName = keyStoreName;
+ }
+
+ public String getKeyStoreType() {
+ return keyStoreType;
+ }
+
+ public void setKeyStoreType(String keyStoreType) {
+ this.keyStoreType = keyStoreType;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ public void setProvider(String provider) {
+ this.provider = provider;
+ }
+
+ public boolean getPrivateStore() {
+ return isPrivateStore;
+ }
+
+ public void setPrivateStore(boolean isPrivateStore) {
+ this.isPrivateStore = isPrivateStore;
+ }
+
+ public CertData getKey() {
+ return key;
+ }
+
+ public void setKey(CertData key) {
+ this.key = key;
+ }
+
+ public String getKeyValue() {
+ return keyValue;
+ }
+
+ public void setKeyValue(String keyValue) {
+ this.keyValue = keyValue;
+ }
+
+ public String getPubKeyFilePath() {
+ return pubKeyFilePath;
+ }
+
+ public void setPubKeyFilePath(String pubKeyFilePath) {
+ this.pubKeyFilePath = pubKeyFilePath;
+ }
+
+ public PaginatedCertData getPaginatedCertData() {
+ return paginatedCertData;
+ }
+
+ public void setPaginatedCertData(PaginatedCertData paginatedCertData) {
+ this.paginatedCertData = paginatedCertData;
+ }
+
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreIOStreamUtils.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreIOStreamUtils.java
new file mode 100644
index 00000000000..57df95783fd
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreIOStreamUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+
+/**
+ * Utility class for IO streams.
+ */
+public class KeyStoreIOStreamUtils {
+
+ private static final Log log = LogFactory.getLog(KeyStoreIOStreamUtils.class);
+
+ public static void closeAllStreams(InputStream input, OutputStream output){
+ closeInputStream(input);
+ closeOutputStream(output);
+ }
+
+ public static void closeInputStream(InputStream input) {
+ try {
+ if (input != null) {
+ input.close();
+ }
+ } catch (IOException ioe) {
+ log.error("Error occurred while closing Input stream", ioe);
+ }
+ }
+
+ public static void closeOutputStream(OutputStream output) {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ } catch (IOException ioe) {
+ log.error("Error occurred while closing Output stream", ioe);
+ }
+ }
+
+ public static void flushOutputStream(OutputStream output) {
+ try {
+ if (output != null) {
+ output.flush();
+ }
+ } catch (IOException ioe) {
+ log.error("Error occurred while flushing Output stream", ioe);
+ }
+ }
+
+ public static void closeReader(Reader reader) {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException ioe) {
+ log.error("Error occurred while closing Reader", ioe);
+ }
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreMgtUtil.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreMgtUtil.java
new file mode 100755
index 00000000000..7efde7e89a5
--- /dev/null
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/util/KeyStoreMgtUtil.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2010, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. 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.wso2.carbon.core.keystore.util;
+
+import org.apache.axis2.context.ConfigurationContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.core.internal.KeyStoreMgtDataHolder;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.user.api.Tenant;
+import org.wso2.carbon.user.api.TenantManager;
+import org.wso2.carbon.user.api.UserStoreException;
+import org.wso2.carbon.utils.ServerConstants;
+import org.wso2.carbon.utils.WSO2Constants;
+import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * This class includes Key Store management utility functions.
+ */
+public class KeyStoreMgtUtil {
+
+ private static final Log log = LogFactory.getLog(KeyStoreMgtUtil.class);
+
+ private KeyStoreMgtUtil(){}
+
+ /**
+ * Dumping the generated pub. cert to a file
+ *
+ * @param configurationContext
+ * @param cert content of the certificate
+ * @param fileName file name
+ * @return file system location of the pub. cert
+ */
+ public static String dumpCert(ConfigurationContext configurationContext, byte[] cert,
+ String fileName) {
+ if (!verifyCertExistence(fileName, configurationContext)) {
+ String workDir = (String) configurationContext.getProperty(ServerConstants.WORK_DIR);
+ File pubCert = new File(workDir + File.separator + "pub_certs");
+
+ if (fileName == null) {
+ fileName = String.valueOf(System.currentTimeMillis() + new SecureRandom().nextDouble()) + ".cert";
+ }
+ if (!pubCert.exists()) {
+ pubCert.mkdirs();
+ }
+
+ String filePath = workDir + File.separator + "pub_certs" + File.separator + fileName;
+ OutputStream outStream = null;
+ try {
+ outStream = new FileOutputStream(filePath);
+ outStream.write(cert);
+ } catch (Exception e) {
+ String msg = "Error when writing the public certificate to a file";
+ log.error(msg);
+ throw new SecurityException("msg", e);
+ } finally {
+ KeyStoreIOStreamUtils.flushOutputStream(outStream);
+ KeyStoreIOStreamUtils.closeOutputStream(outStream);
+ }
+
+ Map fileResourcesMap = (Map) configurationContext.getProperty(WSO2Constants.FILE_RESOURCE_MAP);
+ if (fileResourcesMap == null) {
+ fileResourcesMap = new Hashtable();
+ configurationContext.setProperty(WSO2Constants.FILE_RESOURCE_MAP, fileResourcesMap);
+ }
+
+ fileResourcesMap.put(fileName, filePath);
+ }
+ return WSO2Constants.ContextPaths.DOWNLOAD_PATH + "?id=" + fileName;
+ }
+
+ /**
+ * Check whether the certificate is available in the file system
+ *
+ * @param fileName file name
+ * @param configurationContext configuration context of the current message
+ */
+ private static boolean verifyCertExistence(String fileName, ConfigurationContext configurationContext) {
+ String workDir = (String) configurationContext.getProperty(ServerConstants.WORK_DIR);
+ String filePath = workDir + File.separator + "pub_certs" + File.separator + fileName;
+ File pubCert = new File(workDir + File.separator + "pub_certs" + File.separator + fileName);
+
+ //if cert is still available then exit
+ if (pubCert.exists()) {
+ Map fileResourcesMap = (Map) configurationContext.getProperty(WSO2Constants.FILE_RESOURCE_MAP);
+ if (fileResourcesMap == null) {
+ fileResourcesMap = new Hashtable();
+ configurationContext.setProperty(WSO2Constants.FILE_RESOURCE_MAP, fileResourcesMap);
+ }
+ if (fileResourcesMap.get(fileName) == null) {
+ fileResourcesMap.put(fileName, filePath);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get the tenant UUID for the given tenant ID.
+ * @param tenantId Tenant ID
+ * @return Tenant UUID
+ * @throws KeyStoreManagementException If an error occurs while getting the tenant UUID.
+ * @throws UserStoreException If an error occurs while getting the tenant UUID.
+ */
+ public static String getTenantUUID(int tenantId) throws KeyStoreManagementException, UserStoreException {
+
+ // Super tenant does not have a tenant UUID. Therefore, set a hard coded value.
+ if (tenantId == MultitenantConstants.SUPER_TENANT_ID) {
+ // Set a hard length of 36 characters for super tenant ID.
+ // This is to avoid the database column length constraint violation.
+ return String.format("%1$-36d", tenantId);
+ }
+
+ if (tenantId != MultitenantConstants.INVALID_TENANT_ID) {
+ TenantManager tenantManager = KeyStoreMgtDataHolder.getRealmService().getTenantManager();
+ Tenant tenant = tenantManager.getTenant(tenantId);
+ return tenant.getTenantUniqueID();
+ }
+
+ throw new KeyStoreManagementException("Invalid tenant id: " + tenantId);
+ }
+}
diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java
index 1cb55cecb84..05c433ddb9b 100644
--- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java
+++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/util/KeyStoreManager.java
@@ -23,10 +23,14 @@
import org.wso2.carbon.base.api.ServerConfigurationService;
import org.wso2.carbon.core.RegistryResources;
import org.wso2.carbon.core.internal.CarbonCoreDataHolder;
-import org.wso2.carbon.registry.api.Registry;
+import org.wso2.carbon.core.keystore.KeyStoreManagementException;
+import org.wso2.carbon.core.keystore.dao.KeyStoreDAO;
+import org.wso2.carbon.core.keystore.dao.impl.KeyStoreDAOImpl;
+import org.wso2.carbon.core.keystore.model.KeyStoreModel;
+import org.wso2.carbon.core.keystore.util.KeyStoreMgtUtil;
import org.wso2.carbon.registry.core.Resource;
-import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.service.RegistryService;
+import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
@@ -36,7 +40,9 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
import java.util.Date;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -49,17 +55,16 @@ public class KeyStoreManager {
private KeyStore primaryKeyStore = null;
private KeyStore registryKeyStore = null;
private KeyStore internalKeyStore = null;
- private static ConcurrentHashMap mtKeyStoreManagers =
- new ConcurrentHashMap();
- private static Log log = LogFactory.getLog(KeyStoreManager.class);
+ private static final ConcurrentHashMap mtKeyStoreManagers = new ConcurrentHashMap<>();
+ private static final Log LOG = LogFactory.getLog(KeyStoreManager.class);
- private Registry registry = null;
- private ConcurrentHashMap loadedKeyStores = null;
- private int tenantId = MultitenantConstants.SUPER_TENANT_ID;
+ private KeyStoreDAO keyStoreDAO = null;
- private ServerConfigurationService serverConfigService;
+ private final ConcurrentHashMap loadedKeyStores;
+ private final int tenantId;
+ private String tenantUUID = null;
- private RegistryService registryService;
+ private final ServerConfigurationService serverConfigService;
/**
* Private Constructor of the KeyStoreManager
@@ -71,26 +76,21 @@ public class KeyStoreManager {
private KeyStoreManager(int tenantId, ServerConfigurationService serverConfigService,
RegistryService registryService) {
this.serverConfigService = serverConfigService;
- this.registryService = registryService;
- loadedKeyStores = new ConcurrentHashMap();
+ loadedKeyStores = new ConcurrentHashMap<>();
this.tenantId = tenantId;
try {
- registry = registryService.getGovernanceSystemRegistry(tenantId);
- } catch (RegistryException e) {
- String message = "Error when retrieving the system governance registry";
- log.error(message, e);
- throw new SecurityException(message, e);
+ this.tenantUUID = KeyStoreMgtUtil.getTenantUUID(tenantId);
+ } catch (KeyStoreManagementException | UserStoreException e) {
+ LOG.error("Error while getting the tenant UUID for tenant ID : " + tenantId, e);
}
+
+ keyStoreDAO = new KeyStoreDAOImpl();
}
public ServerConfigurationService getServerConfigService() {
return serverConfigService;
}
- public RegistryService getRegistryService() {
- return registryService;
- }
-
/**
* Get a KeyStoreManager instance for that tenant. This method will return an KeyStoreManager
* instance if exists, or creates a new one. Only use this at runtime, or else,
@@ -133,20 +133,20 @@ public KeyStore getKeyStore(String keyStoreName) throws Exception {
return loadedKeyStores.get(keyStoreName).getKeyStore();
}
- String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName;
- if (registry.resourceExists(path)) {
- org.wso2.carbon.registry.api.Resource resource = registry.get(path);
- byte[] bytes = (byte[]) resource.getContent();
- KeyStore keyStore = KeyStore.getInstance(resource
- .getProperty(RegistryResources.SecurityManagement.PROP_TYPE));
+ Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(this.tenantUUID, keyStoreName);
+ if (optionalKeyStoreModel.isPresent()) {
+ KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
+
+ byte[] bytes = keyStoreModel.getContent();
+ KeyStore keyStore = KeyStore.getInstance(keyStoreModel.getType());
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
- String encryptedPassword = resource
- .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD);
- String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword));
+ char[] encryptedPassword = keyStoreModel.getPassword();
+ char[] password = new String(cryptoUtil.base64DecodeAndDecrypt(Arrays.toString(encryptedPassword)))
+ .toCharArray();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
- keyStore.load(stream, password.toCharArray());
- KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, resource.getLastModified());
- resource.discard();
+ keyStore.load(stream, password);
+
+ KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated());
if (loadedKeyStores.containsKey(keyStoreName)) {
loadedKeyStores.replace(keyStoreName, keyStoreBean);
@@ -172,60 +172,42 @@ public Key getPrivateKey(String keyStoreName, String alias) {
return getDefaultPrivateKey();
}
- String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName;
- org.wso2.carbon.registry.api.Resource resource;
+ KeyStoreModel keyStoreModel;
KeyStore keyStore;
- if (registry.resourceExists(path)) {
- resource = registry.get(path);
+ Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(this.tenantUUID, keyStoreName);
+ if (optionalKeyStoreModel.isPresent()) {
+ keyStoreModel = optionalKeyStoreModel.get();
} else {
- throw new SecurityException("Given Key store is not available in registry : " + keyStoreName);
+ throw new SecurityException("Given Key store is not available in Database : " + keyStoreName);
}
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
- String encryptedPassword = resource
- .getProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_PASS);
- String privateKeyPasswd = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword));
+ char[] encryptedPassword = keyStoreModel.getPrivateKeyPass();
+ char[] privateKeyPasswd = new String(cryptoUtil.base64DecodeAndDecrypt(Arrays.toString(encryptedPassword)))
+ .toCharArray();
if (isCachedKeyStoreValid(keyStoreName)) {
keyStore = loadedKeyStores.get(keyStoreName).getKeyStore();
- return keyStore.getKey(alias, privateKeyPasswd.toCharArray());
- } else {
- byte[] bytes = (byte[]) resource.getContent();
- String keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt(resource.getProperty(
- RegistryResources.SecurityManagement.PROP_PASSWORD)));
- keyStore = KeyStore.getInstance(resource
- .getProperty(RegistryResources.SecurityManagement.PROP_TYPE));
- ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
- keyStore.load(stream, keyStorePassword.toCharArray());
-
- KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, resource.getLastModified());
- updateKeyStoreCache(keyStoreName, keyStoreBean);
- return keyStore.getKey(alias, privateKeyPasswd.toCharArray());
+ return keyStore.getKey(alias, privateKeyPasswd);
}
+ byte[] bytes = keyStoreModel.getContent();
+ char[] keyStorePassword = new String(cryptoUtil.base64DecodeAndDecrypt(
+ Arrays.toString(keyStoreModel.getPassword()))).toCharArray();
+ keyStore = KeyStore.getInstance(keyStoreModel.getType());
+ ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+ keyStore.load(stream, keyStorePassword);
+
+ KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, keyStoreModel.getLastUpdated());
+ updateKeyStoreCache(keyStoreName, keyStoreBean);
+ return keyStore.getKey(alias, privateKeyPasswd);
} catch (Exception e) {
- log.error("Error loading the private key from the key store : " + keyStoreName);
+ LOG.error("Error loading the private key from the key store : " + keyStoreName);
throw new SecurityException("Error loading the private key from the key store : " +
keyStoreName, e);
}
}
- /**
- * Get the key store password of the given key store resource
- *
- * @param resource key store resource
- * @return password of the key store
- * @throws Exception Error when reading the registry resource of decrypting the password
- */
- public String getPassword(Resource resource) throws Exception {
- CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
- String encryptedPassword = resource
- .getProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_PASS);
- return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword));
-
- }
-
-
/**
* Get the key store password for the given key store name.
* Note: Caching has been not implemented for this method
@@ -234,16 +216,15 @@ public String getPassword(Resource resource) throws Exception {
* @return KeyStore object
* @throws Exception If there is not a key store with the given name
*/
- public String getKeyStorePassword(String keyStoreName) throws Exception {
+ public String getKeyStorePassword(String keyStoreName) throws KeyStoreManagementException, CryptoException {
- String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName;
- if (registry.resourceExists(path)) {
- org.wso2.carbon.registry.api.Resource resource = registry.get(path);
+ Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(this.tenantUUID, keyStoreName);
+ if (optionalKeyStoreModel.isPresent()) {
+ KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
- String encryptedPassword = resource
- .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD);
+ char[] encryptedPassword = keyStoreModel.getPassword();
if(encryptedPassword != null){
- return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword));
+ return new String(cryptoUtil.base64DecodeAndDecrypt(Arrays.toString(encryptedPassword)));
} else {
throw new SecurityException("Key Store Password of " + keyStoreName + " does not exist.");
}
@@ -267,38 +248,43 @@ public void updateKeyStore(String name, KeyStore keyStore) throws Exception {
config
.getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_FILE))
.getAbsolutePath();
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(file);
+ try (FileOutputStream out = new FileOutputStream(file)) {
String password = config
.getFirstProperty(RegistryResources.SecurityManagement.SERVER_PRIMARY_KEYSTORE_PASSWORD);
keyStore.store(out, password.toCharArray());
- } finally {
- if (out != null) {
- out.close();
- }
}
- return;
}
- String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + name;
-
- org.wso2.carbon.registry.api.Resource resource = registry.get(path);
-
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
- String encryptedPassword = resource
- .getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD);
- String password = new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword));
- keyStore.store(outputStream, password.toCharArray());
- outputStream.flush();
- outputStream.close();
-
- resource.setContent(outputStream.toByteArray());
-
- registry.put(path, resource);
- resource.discard();
- updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date()));
+ Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(this.tenantUUID, name);
+ if (optionalKeyStoreModel.isPresent()) {
+ KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();
+ char[] encryptedPassword = keyStoreModel.getPassword();
+ char[] password = new String(cryptoUtil.base64DecodeAndDecrypt(Arrays.toString(encryptedPassword)))
+ .toCharArray();
+ keyStore.store(outputStream, password);
+ outputStream.flush();
+ outputStream.close();
+
+ KeyStoreModel updatedKeyStoreModel = new KeyStoreModel.KeyStoreModelBuilder()
+ .id(keyStoreModel.getId())
+ .fileName(keyStoreModel.getFileName())
+ .type(keyStoreModel.getType())
+ .provider(keyStoreModel.getProvider())
+ .password(keyStoreModel.getPassword())
+ .privateKeyAlias(keyStoreModel.getPrivateKeyAlias())
+ .privateKeyPass(keyStoreModel.getPrivateKeyPass())
+ .content(outputStream.toByteArray())
+ .build();
+
+ keyStoreDAO.updateKeyStore(this.tenantUUID, updatedKeyStoreModel);
+
+ // TODO: is it correct to use new Date() here? The value stored in DB might be different.
+ updateKeyStoreCache(name, new KeyStoreBean(keyStore, new Date()));
+ } else {
+ throw new SecurityException("Key Store with a name : " + name + " does not exist.");
+ }
}
/**
@@ -487,19 +473,21 @@ public X509Certificate getDefaultPrimaryCertificate() throws Exception {
}
private boolean isCachedKeyStoreValid(String keyStoreName) {
- String path = RegistryResources.SecurityManagement.KEY_STORES + "/" + keyStoreName;
boolean cachedKeyStoreValid = false;
try {
if (loadedKeyStores.containsKey(keyStoreName)) {
- org.wso2.carbon.registry.api.Resource metaDataResource = registry.get(path);
- KeyStoreBean keyStoreBean = loadedKeyStores.get(keyStoreName);
- if (keyStoreBean.getLastModifiedDate().equals(metaDataResource.getLastModified())) {
- cachedKeyStoreValid = true;
+ Optional optionalKeyStoreModel = keyStoreDAO.getKeyStore(this.tenantUUID, keyStoreName);
+ if (optionalKeyStoreModel.isPresent()) {
+ KeyStoreModel keyStoreModel = optionalKeyStoreModel.get();
+ KeyStoreBean keyStoreBean = loadedKeyStores.get(keyStoreName);
+ if (keyStoreBean.getLastModifiedDate().equals(keyStoreModel.getLastUpdated())) {
+ cachedKeyStoreValid = true;
+ }
}
}
- } catch (org.wso2.carbon.registry.api.RegistryException e) {
- String errorMsg = "Error reading key store meta data from registry.";
- log.error(errorMsg, e);
+ } catch (KeyStoreManagementException e) {
+ String errorMsg = "Error reading key store meta data from Database.";
+ LOG.error(errorMsg, e);
throw new SecurityException(errorMsg, e);
}
return cachedKeyStoreValid;
@@ -524,7 +512,7 @@ public KeyStore loadKeyStoreFromFileSystem(String keyStorePath, String password,
return store;
} catch (Exception e) {
String errorMsg = "Error loading the key store from the given location.";
- log.error(errorMsg);
+ LOG.error(errorMsg);
throw new SecurityException(errorMsg, e);
} finally {
try {
@@ -532,7 +520,7 @@ public KeyStore loadKeyStoreFromFileSystem(String keyStorePath, String password,
inputStream.close();
}
} catch (IOException e) {
- log.warn("Error when closing the input stream.", e);
+ LOG.warn("Error when closing the input stream.", e);
}
}
}
diff --git a/distribution/kernel/carbon-home/repository/resources/conf/default.json b/distribution/kernel/carbon-home/repository/resources/conf/default.json
index 9db941841cd..69bf6cf4859 100644
--- a/distribution/kernel/carbon-home/repository/resources/conf/default.json
+++ b/distribution/kernel/carbon-home/repository/resources/conf/default.json
@@ -221,6 +221,6 @@
"tenant_mgt.enable_tenant_theme_mgt" : true,
"tenant_mgt.enable_tenant_validation_for_nonsaas_username" : true,
"jce_provider.provider_name" : "BC",
- "signature_util.enable_sha256_algo" : true
-
+ "signature_util.enable_sha256_algo" : true,
+ "keystore_data_persistence_manager.datasource.name" : "jdbc/SHARED_DB"
}
diff --git a/distribution/kernel/carbon-home/repository/resources/conf/templates/repository/conf/carbon.xml.j2 b/distribution/kernel/carbon-home/repository/resources/conf/templates/repository/conf/carbon.xml.j2
index 8c03c1b8460..22cde73233e 100644
--- a/distribution/kernel/carbon-home/repository/resources/conf/templates/repository/conf/carbon.xml.j2
+++ b/distribution/kernel/carbon-home/repository/resources/conf/templates/repository/conf/carbon.xml.j2
@@ -805,4 +805,13 @@
{{signature_util.enable_sha256_algo}}
+
+
+
+
+
+ {{keystore_data_persistence_manager.datasource.name}}
+
+
diff --git a/parent/pom.xml b/parent/pom.xml
index 89a7af1418d..6ee86d3f66f 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -305,6 +305,10 @@
${carbon.kernel.version}
[${carbon.kernel.version}, 4.10.0)
+
+ 2.1.3
+ [2.0.0,2.2.0)
+
1.1.200.v20160504-1450
3.8.0.v20160509-1230
@@ -1743,6 +1747,11 @@
org.wso2.carbon.integration.test.common.admin.clients
${carbon.kernel.version}
+
+ org.wso2.carbon.utils
+ org.wso2.carbon.database.utils
+ ${org.wso2.carbon.database.utils.version}
+
org.apache.woden
woden-api