From 446ed291e75601b569904c6741cb13e291efcfdd Mon Sep 17 00:00:00 2001 From: UdeshAthukorala Date: Thu, 12 Dec 2024 12:23:36 +0530 Subject: [PATCH 1/4] Move keystore persistence manager implementations to org.wso2.carbon.utils component --- core/org.wso2.carbon.core/pom.xml | 2 +- .../carbon/core/util/KeyStoreManager.java | 132 +++++++++-- core/org.wso2.carbon.utils/pom.xml | 1 + .../KeyStorePersistenceManager.java | 30 +-- .../PersistenceManagerConstants.java | 48 ++++ .../RegistryKeyStorePersistenceManager.java | 218 ++++++------------ .../persistence/model}/KeyStoreMetadata.java | 2 +- .../persistence/model/KeyStoreModel.java | 158 +++++++++++++ 8 files changed, 405 insertions(+), 186 deletions(-) rename core/{org.wso2.carbon.core/src/main/java/org/wso2/carbon/core => org.wso2.carbon.utils/src/main/java/org/wso2/carbon}/keystore/persistence/KeyStorePersistenceManager.java (70%) create mode 100644 core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/PersistenceManagerConstants.java rename core/{org.wso2.carbon.core/src/main/java/org/wso2/carbon/core => org.wso2.carbon.utils/src/main/java/org/wso2/carbon}/keystore/persistence/RegistryKeyStorePersistenceManager.java (56%) rename core/{org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security => org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model}/KeyStoreMetadata.java (97%) create mode 100644 core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java diff --git a/core/org.wso2.carbon.core/pom.xml b/core/org.wso2.carbon.core/pom.xml index 8858e49503..53adef45f6 100644 --- a/core/org.wso2.carbon.core/pom.xml +++ b/core/org.wso2.carbon.core/pom.xml @@ -225,7 +225,7 @@ org.wso2.carbon.core org.wso2.carbon.core.internal.CarbonCoreActivator - org.wso2.carbon.core.internal, org.wso2.carbon.core.encryption, org.wso2.carbon.core.keystore.persistence + org.wso2.carbon.core.internal, org.wso2.carbon.core.encryption !org.wso2.carbon.core.internal, 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 67fc362e12..2fee15e2ac 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 @@ -19,6 +19,7 @@ import org.apache.axiom.om.OMElement; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.CarbonException; @@ -26,17 +27,21 @@ import org.wso2.carbon.base.api.ServerConfigurationService; import org.wso2.carbon.core.RegistryResources; import org.wso2.carbon.core.internal.CarbonCoreDataHolder; -import org.wso2.carbon.core.keystore.persistence.RegistryKeyStorePersistenceManager; -import org.wso2.carbon.core.security.KeyStoreMetadata; +import org.wso2.carbon.keystore.persistence.RegistryKeyStorePersistenceManager; +import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; +import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import org.wso2.carbon.utils.security.KeystoreUtils; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; 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; @@ -44,6 +49,7 @@ import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -215,8 +221,37 @@ public void addKeyStore(byte[] keystoreContent, String filename, char[] password if (KeyStoreUtil.isPrimaryStore(filename) || KeyStoreUtil.isTrustStore(filename)) { throw new SecurityException("Key store " + filename + " already available"); } - registryKeyStorePersistenceManager.addKeystore(filename, keystoreContent, provider, type, passwordChar, - privateKeyPasswordChar, tenantId); + + KeyStoreModel keyStoreModel = new KeyStoreModel(); + keyStoreModel.setName(filename); + keyStoreModel.setContent(keystoreContent); + keyStoreModel.setType(type); + keyStoreModel.setProvider(provider); + + try (InputStream inputStream = new ByteArrayInputStream(keystoreContent)) { + KeyStore keyStore = KeystoreUtils.getKeystoreInstance(type); + keyStore.load(inputStream, passwordChar); + String pvtKeyAlias = KeyStoreUtil.getPrivateKeyAlias(keyStore); + if (StringUtils.isNotBlank(pvtKeyAlias)) { + keyStoreModel.setPrivateKeyAlias(pvtKeyAlias); + X509Certificate publicCert = (X509Certificate) keyStore.getCertificate(pvtKeyAlias); + + if (publicCert != null) { + keyStoreModel.setPublicCert(publicCert); + } + if (ArrayUtils.isNotEmpty(privateKeyPasswordChar)) { + // Check weather private key password is correct. + keyStore.getKey(pvtKeyAlias, privateKeyPasswordChar); + keyStoreModel.setEncryptedPrivateKeyPass(encryptPassword(privateKeyPasswordChar)); + } + } + } catch (IOException | KeyStoreException | NoSuchAlgorithmException | NoSuchProviderException | + UnrecoverableKeyException | CertificateException e) { + throw new SecurityException("Error adding key store " + filename, e); + } + + keyStoreModel.setEncryptedPassword(encryptPassword(passwordChar)); + registryKeyStorePersistenceManager.addKeystore(keyStoreModel); } /** @@ -383,11 +418,12 @@ public String getPassword(org.wso2.carbon.registry.core.Resource resource) throw * * @param keyStoreName key store name * @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) { - return String.valueOf(registryKeyStorePersistenceManager.getKeyStorePassword(keyStoreName, tenantId)); + String encryptedPassword = + registryKeyStorePersistenceManager.getEncryptedKeyStorePassword(keyStoreName, tenantId); + return String.valueOf (decryptPassword(encryptedPassword)); } /** @@ -447,8 +483,22 @@ private void updateTrustStore(KeyStore keyStore) { private void updateTenantKeyStore(String keyStoreName, KeyStore keyStore) { - registryKeyStorePersistenceManager.updateKeyStore(keyStoreName, keyStore, tenantId); - updateTenantKeyStoreCache(keyStoreName, new KeyStoreBean(keyStore, new Date())); + char[] passwordChar = new char[0]; + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + KeyStoreModel keyStoreModel = new KeyStoreModel(); + passwordChar = getKeyStorePassword(keyStoreName).toCharArray(); + keyStore.store(outputStream, passwordChar); + outputStream.flush(); + keyStoreModel.setName(keyStoreName); + keyStoreModel.setContent(outputStream.toByteArray()); + keyStoreModel.setTenantId(tenantId); + registryKeyStorePersistenceManager.updateKeyStore(keyStoreModel); + updateTenantKeyStoreCache(keyStoreName, new KeyStoreBean(keyStore, new Date())); + } catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) { + throw new SecurityException("Error updating tenanted key store: " + keyStoreName, e); + } finally { + clearPasswordCharArray(passwordChar); + } } /** @@ -502,11 +552,25 @@ private KeyStore getTenantKeyStore(String keyStoreName) throws Exception { return tenantKeyStores.get(keyStoreName).getKeyStore(); } - KeyStore keyStore = registryKeyStorePersistenceManager.getKeyStore(keyStoreName, tenantId); - KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, - registryKeyStorePersistenceManager.getKeyStoreLastModifiedDate(keyStoreName, tenantId)); - updateTenantKeyStoreCache(keyStoreName, keyStoreBean); - return keyStore; + KeyStoreModel keyStoreModel = registryKeyStorePersistenceManager.getKeyStore(keyStoreName, tenantId); + + char[] passwordChar = new char[0]; + try { + byte[] bytes = keyStoreModel.getContent(); + KeyStore keyStore = KeystoreUtils.getKeystoreInstance(keyStoreModel.getType()); + passwordChar = decryptPassword(keyStoreModel.getEncryptedPassword()); + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + keyStore.load(stream, passwordChar); + KeyStoreBean keyStoreBean = new KeyStoreBean(keyStore, + registryKeyStorePersistenceManager.getKeyStoreLastModifiedDate(keyStoreName, tenantId)); + updateTenantKeyStoreCache(keyStoreName, keyStoreBean); + return keyStore; + } catch (KeyStoreException | NoSuchProviderException | IOException | CertificateException | + NoSuchAlgorithmException e) { + throw new SecurityException("Error getting key store: " + keyStoreName, e); + } finally { + clearPasswordCharArray(passwordChar); + } } /** @@ -688,7 +752,9 @@ private PrivateKey getTenantPrivateKey(String keyStoreName, String alias) throws char[] privateKeyPasswordChar = new char[0]; try { KeyStore keyStore = getTenantKeyStore(keyStoreName); - privateKeyPasswordChar = registryKeyStorePersistenceManager.getPrivateKeyPassword(keyStoreName, tenantId); + String encryptedPrivateKeyPassword = + registryKeyStorePersistenceManager.getEncryptedPrivateKeyPassword(keyStoreName, tenantId); + privateKeyPasswordChar = decryptPassword(encryptedPrivateKeyPassword); return (PrivateKey) keyStore.getKey(alias, privateKeyPasswordChar); } finally { Arrays.fill(privateKeyPasswordChar, '\0'); @@ -845,4 +911,40 @@ public KeyStore loadKeyStoreFromFileSystem(String keyStorePath, String password, } } } + + /** + * This method encrypts the given passwordChar using the default crypto util. + * + * @param passwordChar Password to be encrypted as a character array. + * @return encrypted password. + */ + private String encryptPassword(char[] passwordChar) { + + try { + return CryptoUtil.getDefaultCryptoUtil().encryptAndBase64Encode(String.valueOf(passwordChar).getBytes()); + } catch (CryptoException e) { + throw new SecurityException("Error encrypting the passwordChar", e); + } + } + + /** + * This method decrypts the given encrypted password using the default crypto util. + * + * @param encryptedPassword Encrypted password. + * @return decrypted password as a character array. + */ + private char[] decryptPassword(String encryptedPassword) { + + try { + CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); + return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)).toCharArray(); + } catch (CryptoException e) { + throw new SecurityException("Error decrypting the password", e); + } + } + + private static void clearPasswordCharArray(char[] passwordChar) { + + Arrays.fill(passwordChar, '\0'); + } } diff --git a/core/org.wso2.carbon.utils/pom.xml b/core/org.wso2.carbon.utils/pom.xml index f1f6eb8a26..44aa3ea3f8 100644 --- a/core/org.wso2.carbon.utils/pom.xml +++ b/core/org.wso2.carbon.utils/pom.xml @@ -256,6 +256,7 @@ !org.wso2.carbon.utils.resolver, org.wso2.carbon, + org.wso2.carbon.keystore.persistence.*; org.wso2.carbon.utils.*, org.wso2.carbon.context, !org.wso2.carbon.context.internal diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/KeyStorePersistenceManager.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java similarity index 70% rename from core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/KeyStorePersistenceManager.java rename to core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java index dffb46768f..0edc862c52 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/KeyStorePersistenceManager.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java @@ -16,11 +16,11 @@ * under the License. */ -package org.wso2.carbon.core.keystore.persistence; +package org.wso2.carbon.keystore.persistence; -import org.wso2.carbon.core.security.KeyStoreMetadata; +import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; +import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; -import java.security.KeyStore; import java.util.Date; import java.util.List; @@ -32,26 +32,20 @@ public interface KeyStorePersistenceManager { /** * Add the key store to the data storage. * - * @param keyStoreName Name of the key store. - * @param keystoreContent Content of the key store. - * @param provider Provider of the key store. - * @param keyStorePasswordChar Key Store Password as a character string. - * @param privateKeyPasswordChar Private key password as a character string. - * @param tenantId Tenant ID. + * @param keyStoreModel Key store model. * @throws SecurityException If an error occurs while adding the key store. */ - void addKeystore(String keyStoreName, byte[] keystoreContent, String provider, String type, - char[] keyStorePasswordChar, char[] privateKeyPasswordChar, int tenantId); + void addKeystore(KeyStoreModel keyStoreModel) throws SecurityException; /** * Get the key store from the data storage. * * @param keyStoreName Name of the key store. * @param tenantId Tenant Id. - * @return Key store. + * @return Key store model. * @throws SecurityException If an error occurs while getting the key store. */ - KeyStore getKeyStore(String keyStoreName, int tenantId) throws SecurityException; + KeyStoreModel getKeyStore(String keyStoreName, int tenantId) throws SecurityException; /** * Method to retrieve list of keystore metadata of all the keystores in a tenant. @@ -65,11 +59,9 @@ void addKeystore(String keyStoreName, byte[] keystoreContent, String provider, S /** * Update the key store in the data storage. * - * @param keyStoreName Key store name. - * @param keyStore Updated key store. - * @param tenantId Tenant Id. + * @param keyStoreModel Key store model. */ - void updateKeyStore(String keyStoreName, KeyStore keyStore, int tenantId); + void updateKeyStore(KeyStoreModel keyStoreModel); /** * Delete the key store from the data storage. @@ -96,7 +88,7 @@ void addKeystore(String keyStoreName, byte[] keystoreContent, String provider, S * @return KeyStore Password as a character array. * @throws SecurityException If there is an error while getting the key store password. */ - char[] getKeyStorePassword(String keyStoreName, int tenantId) throws SecurityException; + String getEncryptedKeyStorePassword(String keyStoreName, int tenantId) throws SecurityException; /** * Get the private key password as a character array for the given key store name. @@ -106,5 +98,5 @@ void addKeystore(String keyStoreName, byte[] keystoreContent, String provider, S * @return Private key password as a character array. * @throws SecurityException If an error occurs while getting the private key password. */ - char[] getPrivateKeyPassword(String keyStoreName, int tenantId) throws SecurityException; + String getEncryptedPrivateKeyPassword(String keyStoreName, int tenantId) throws SecurityException; } diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/PersistenceManagerConstants.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/PersistenceManagerConstants.java new file mode 100644 index 0000000000..a31a71ad7d --- /dev/null +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/PersistenceManagerConstants.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://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.keystore.persistence; + +/** + * Constants used in the persistence manager. + */ +public class PersistenceManagerConstants { + + private PersistenceManagerConstants() { + + } + + public static class RegistryResources { + + private RegistryResources() { + + } + + public static final String ROOT = "/repository/"; + public static final String KEY_STORES = ROOT + "security/key-stores"; + public static final String PRIMARY_KEYSTORE_PHANTOM_RESOURCE = RegistryResources.ROOT + + "security/key-stores/carbon-primary-ks"; + public static final String PROP_PASSWORD = "password"; + public static final String PROP_PROVIDER = "provider"; + public static final String PROP_PRIVATE_KEY_ALIAS = "privatekeyAlias"; + public static final String PROP_TYPE = "type"; + public static final String PROP_PRIVATE_KEY_PASS = "privatekeyPass"; + public static final String TENANT_PUBKEY_RESOURCE = ROOT + "security/pub-key"; + } + +} diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/RegistryKeyStorePersistenceManager.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java similarity index 56% rename from core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/RegistryKeyStorePersistenceManager.java rename to core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java index 5cf82d27f2..e552a2269b 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/keystore/persistence/RegistryKeyStorePersistenceManager.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java @@ -16,44 +16,39 @@ * under the License. */ -package org.wso2.carbon.core.keystore.persistence; +package org.wso2.carbon.keystore.persistence; import org.apache.axiom.om.util.UUIDGenerator; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.core.RegistryResources; -import org.wso2.carbon.core.internal.CarbonCoreDataHolder; -import org.wso2.carbon.core.security.KeyStoreMetadata; -import org.wso2.carbon.core.util.CryptoException; -import org.wso2.carbon.core.util.CryptoUtil; -import org.wso2.carbon.core.util.KeyStoreUtil; +import org.wso2.carbon.context.internal.OSGiDataHolder; +import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; +import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import org.wso2.carbon.registry.api.Association; +import org.wso2.carbon.registry.api.Collection; import org.wso2.carbon.registry.api.Registry; import org.wso2.carbon.registry.api.RegistryException; import org.wso2.carbon.registry.api.Resource; -import org.wso2.carbon.registry.core.Collection; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; -import org.wso2.carbon.utils.security.KeystoreUtils; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.UnrecoverableKeyException; import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.KEY_STORES; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PRIMARY_KEYSTORE_PHANTOM_RESOURCE; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PROP_PASSWORD; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PROP_PRIVATE_KEY_ALIAS; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PROP_PRIVATE_KEY_PASS; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PROP_PROVIDER; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.PROP_TYPE; +import static org.wso2.carbon.keystore.persistence.PersistenceManagerConstants.RegistryResources.TENANT_PUBKEY_RESOURCE; + /** * This implementation handles the keystore storage/persistence related logics in the Registry. */ @@ -67,59 +62,42 @@ public class RegistryKeyStorePersistenceManager implements KeyStorePersistenceMa /** * Add the key store to the registry. * - * @param keyStoreName Name of the key store. - * @param keystoreContent Content of the key store. - * @param provider Provider of the key store. - * @param keyStorePasswordChar Key Store Password as a character array. - * @param privateKeyPasswordChar Private key password as a character array. - * @param tenantId Tenant ID. + * @param keyStoreModel KeyStore model object. * @throws SecurityException If an error occurs while adding the key store. */ - public void addKeystore(String keyStoreName, byte[] keystoreContent, String provider, String type, - char[] keyStorePasswordChar, char[] privateKeyPasswordChar, int tenantId) - throws SecurityException { + public void addKeystore(KeyStoreModel keyStoreModel) throws SecurityException { - Registry registry = getGovernanceRegistry(tenantId); - if (isKeyStoreExistsInRegistry(keyStoreName, registry)) { - throw new SecurityException("Key store " + keyStoreName + " already available"); + Registry registry = getGovernanceRegistry(keyStoreModel.getTenantId()); + if (isKeyStoreExistsInRegistry(keyStoreModel.getName(), registry)) { + throw new SecurityException("Key store " + keyStoreModel.getName() + " already available"); } boolean isTenantPrimaryKeyStore = false; - try (InputStream inputStream = new ByteArrayInputStream(keystoreContent)) { - if (tenantId != MultitenantConstants.SUPER_TENANT_ID && - !registry.resourceExists(RegistryResources.SecurityManagement.KEY_STORES)) { + try { + if (keyStoreModel.getTenantId() != MultitenantConstants.SUPER_TENANT_ID && + !registry.resourceExists(KEY_STORES)) { isTenantPrimaryKeyStore = true; } - KeyStore keyStore = KeystoreUtils.getKeystoreInstance(type); - keyStore.load(inputStream, keyStorePasswordChar); - String pvtKeyAlias = KeyStoreUtil.getPrivateKeyAlias(keyStore); - Resource resource = registry.newResource(); - resource.addProperty(RegistryResources.SecurityManagement.PROP_PASSWORD, - encryptPassword(keyStorePasswordChar)); - resource.addProperty(RegistryResources.SecurityManagement.PROP_PROVIDER, provider); - resource.addProperty(RegistryResources.SecurityManagement.PROP_TYPE, keyStore.getType()); - resource.setContent(keystoreContent); - - if (StringUtils.isNotBlank(pvtKeyAlias)) { - resource.addProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_ALIAS, pvtKeyAlias); - if (ArrayUtils.isNotEmpty(privateKeyPasswordChar)) { - resource.addProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_PASS, - encryptPassword(privateKeyPasswordChar)); - // Check weather private key password is correct. - keyStore.getKey(pvtKeyAlias, privateKeyPasswordChar); - } + resource.addProperty(PROP_PASSWORD, keyStoreModel.getEncryptedPassword()); + resource.addProperty(PROP_PROVIDER, keyStoreModel.getProvider()); + resource.addProperty(PROP_TYPE, keyStoreModel.getType()); + resource.setContent(keyStoreModel.getContent()); + + if (StringUtils.isNotBlank(keyStoreModel.getPrivateKeyAlias())) { + resource.addProperty(PROP_PRIVATE_KEY_ALIAS, keyStoreModel.getEncryptedPrivateKeyPass()); + } + if (StringUtils.isNotBlank(keyStoreModel.getEncryptedPrivateKeyPass())) { + resource.addProperty(PROP_PRIVATE_KEY_PASS, keyStoreModel.getEncryptedPrivateKeyPass()); } - registry.put(getKeyStorePath(keyStoreName), resource); if (isTenantPrimaryKeyStore) { // Create the public key resource for tenant's primary keystore. - addTenantPublicKey(keyStoreName, (X509Certificate) keyStore.getCertificate(pvtKeyAlias), registry); + addTenantPublicKey(keyStoreModel.getName(), keyStoreModel.getPublicCert(), registry); } - } catch (IOException | KeyStoreException | NoSuchAlgorithmException | NoSuchProviderException | - UnrecoverableKeyException | CertificateException | RegistryException e) { - throw new SecurityException("Error adding key store " + keyStoreName, e); + } catch (RegistryException e) { + throw new SecurityException("Error adding key store " + keyStoreModel.getName(), e); } } @@ -138,12 +116,11 @@ private void addTenantPublicKey(String keyStoreName, X509Certificate publicCert, Resource pubKeyResource = registry.newResource(); pubKeyResource.setContent(publicCert.getEncoded()); pubKeyResource.addProperty(PROP_TENANT_PUB_KEY_FILE_NAME_APPENDER, generatePublicCertId()); - registry.put(RegistryResources.SecurityManagement.TENANT_PUBKEY_RESOURCE, pubKeyResource); + registry.put(TENANT_PUBKEY_RESOURCE, pubKeyResource); // Associate the public key with the keystore. - registry.addAssociation( - RegistryResources.SecurityManagement.KEY_STORES + REGISTRY_PATH_SEPARATOR + keyStoreName, - RegistryResources.SecurityManagement.TENANT_PUBKEY_RESOURCE, ASSOCIATION_TENANT_KS_PUB_KEY); + registry.addAssociation(KEY_STORES + REGISTRY_PATH_SEPARATOR + keyStoreName, + TENANT_PUBKEY_RESOURCE, ASSOCIATION_TENANT_KS_PUB_KEY); } catch (RegistryException | CertificateEncodingException e) { throw new SecurityException("Error when writing the keystore public cert to registry for keystore: " + keyStoreName, e); @@ -170,35 +147,30 @@ private static String generatePublicCertId() { * @return Key store. * @throws SecurityException If an error occurs while getting the key store. */ - public KeyStore getKeyStore(String keyStoreName, int tenantId) throws SecurityException { + public KeyStoreModel getKeyStore(String keyStoreName, int tenantId) throws SecurityException { Registry registry = getGovernanceRegistry(tenantId); if (!isKeyStoreExistsInRegistry(keyStoreName, registry)) { throw new SecurityException("Key Store with a name: " + keyStoreName + " does not exist."); } - char[] passwordChar = new char[0]; try { Resource resource = registry.get(getKeyStorePath(keyStoreName)); - byte[] bytes = (byte[]) resource.getContent(); - KeyStore keyStore = KeystoreUtils.getKeystoreInstance(resource - .getProperty(RegistryResources.SecurityManagement.PROP_TYPE)); - passwordChar = getKeyStorePasswordFromRegistryResource(resource, keyStoreName); - ByteArrayInputStream stream = new ByteArrayInputStream(bytes); - keyStore.load(stream, passwordChar); + KeyStoreModel keyStoreModel = new KeyStoreModel(); + keyStoreModel.setName(keyStoreName); + keyStoreModel.setType(resource.getProperty(PROP_TYPE)); + keyStoreModel.setContent((byte[]) resource.getContent()); + keyStoreModel.setEncryptedPassword(resource.getProperty(PROP_PASSWORD)); resource.discard(); - return keyStore; - } catch (RegistryException | KeyStoreException | NoSuchProviderException | IOException | CertificateException | - NoSuchAlgorithmException e) { + return keyStoreModel; + } catch (RegistryException e) { throw new SecurityException("Error getting key store: " + keyStoreName, e); - } finally { - clearPasswordCharArray(passwordChar); } } private String getKeyStorePath(String keyStoreName) { - return RegistryResources.SecurityManagement.KEY_STORES + REGISTRY_PATH_SEPARATOR + keyStoreName; + return KEY_STORES + REGISTRY_PATH_SEPARATOR + keyStoreName; } /** @@ -213,15 +185,15 @@ public List listKeyStores(int tenantId) throws SecurityExcepti Registry registry = getGovernanceRegistry(tenantId); List metadataList = new ArrayList<>(); try { - if (!registry.resourceExists(RegistryResources.SecurityManagement.KEY_STORES)) { + if (!registry.resourceExists(KEY_STORES)) { return metadataList; } - Collection keyStoreCollection = (Collection) registry.get(RegistryResources.SecurityManagement.KEY_STORES); + Collection keyStoreCollection = (Collection) registry.get(KEY_STORES); String[] keyStorePaths = keyStoreCollection.getChildren(); for (String keyStorePath : keyStorePaths) { - if (RegistryResources.SecurityManagement.PRIMARY_KEYSTORE_PHANTOM_RESOURCE.equals(keyStorePath)) { + if (PRIMARY_KEYSTORE_PHANTOM_RESOURCE.equals(keyStorePath)) { continue; } metadataList.add(getKeyStoreMetadata(keyStorePath, registry, tenantId)); @@ -238,9 +210,9 @@ private KeyStoreMetadata getKeyStoreMetadata(String keyStorePath, Registry regis Resource keyStoreResource = registry.get(keyStorePath); int lastIndex = keyStorePath.lastIndexOf(REGISTRY_PATH_SEPARATOR); String name = keyStorePath.substring(lastIndex + 1); - String type = keyStoreResource.getProperty(RegistryResources.SecurityManagement.PROP_TYPE); - String provider = keyStoreResource.getProperty(RegistryResources.SecurityManagement.PROP_PROVIDER); - String alias = keyStoreResource.getProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_ALIAS); + String type = keyStoreResource.getProperty(PROP_TYPE); + String provider = keyStoreResource.getProperty(PROP_PROVIDER); + String alias = keyStoreResource.getProperty(PROP_PRIVATE_KEY_ALIAS); KeyStoreMetadata keyStoreMetadata = new KeyStoreMetadata(); keyStoreMetadata.setKeyStoreName(name); @@ -263,28 +235,19 @@ private KeyStoreMetadata getKeyStoreMetadata(String keyStorePath, Registry regis /** * Update the key store in the registry. * - * @param keyStoreName Key store name. - * @param keyStore Updated key store. - * @param tenantId Tenant Id. + * @param keyStoreModel Key store model. */ - public void updateKeyStore(String keyStoreName, KeyStore keyStore, int tenantId) { + public void updateKeyStore(KeyStoreModel keyStoreModel) { - Registry registry = getGovernanceRegistry(tenantId); - char[] passwordChar = new char[0]; + Registry registry = getGovernanceRegistry(keyStoreModel.getTenantId()); try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - String path = getKeyStorePath(keyStoreName); + String path = getKeyStorePath(keyStoreModel.getName()); Resource resource = registry.get(path); - passwordChar = getKeyStorePasswordFromRegistryResource(resource, keyStoreName); - keyStore.store(outputStream, passwordChar); - outputStream.flush(); - resource.setContent(outputStream.toByteArray()); + resource.setContent(keyStoreModel.getContent()); registry.put(path, resource); resource.discard(); - } catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException | - RegistryException e) { - throw new SecurityException("Error updating tenanted key store: " + keyStoreName, e); - } finally { - clearPasswordCharArray(passwordChar); + } catch (IOException | RegistryException e) { + throw new SecurityException("Error updating tenanted key store: " + keyStoreModel.getName(), e); } } @@ -329,13 +292,13 @@ public Date getKeyStoreLastModifiedDate(String keyStoreName, int tenantId) { } /** - * Get the password for the given key store name. + * Get the encrypted password for the given key store name. * * @param keyStoreName Key store name. * @return KeyStore Password. * @throws SecurityException If there is an error while getting the key store password. */ - public char[] getKeyStorePassword(String keyStoreName, int tenantId) throws SecurityException { + public String getEncryptedKeyStorePassword(String keyStoreName, int tenantId) throws SecurityException { Registry registry = getGovernanceRegistry(tenantId); if (!isKeyStoreExistsInRegistry(keyStoreName, registry)) { @@ -344,7 +307,7 @@ public char[] getKeyStorePassword(String keyStoreName, int tenantId) throws Secu try { Resource resource = registry.get(getKeyStorePath(keyStoreName)); - return getKeyStorePasswordFromRegistryResource(resource, keyStoreName); + return resource.getProperty(PROP_PASSWORD); } catch (RegistryException e) { throw new SecurityException("Error getting password for key store: " + keyStoreName, e); } @@ -358,16 +321,16 @@ public char[] getKeyStorePassword(String keyStoreName, int tenantId) throws Secu * @return Private key password as a character array. * @throws SecurityException If an error occurs while getting the private key password. */ - public char[] getPrivateKeyPassword(String keyStoreName, int tenantId) throws SecurityException { + public String getEncryptedPrivateKeyPassword(String keyStoreName, int tenantId) throws SecurityException { Registry registry = getGovernanceRegistry(tenantId); try { Resource resource = registry.get(getKeyStorePath(keyStoreName)); - String encryptedPassword = resource.getProperty(RegistryResources.SecurityManagement.PROP_PRIVATE_KEY_PASS); + String encryptedPassword = resource.getProperty(PROP_PRIVATE_KEY_PASS); if (encryptedPassword == null) { throw new SecurityException("Private Key Password of " + keyStoreName + " does not exist."); } - return decryptPassword(encryptedPassword); + return encryptedPassword; } catch (RegistryException e) { throw new SecurityException("Error getting private key password for key store: " + keyStoreName, e); } @@ -382,57 +345,12 @@ private boolean isKeyStoreExistsInRegistry(String keyStoreName, Registry registr } } - private char[] getKeyStorePasswordFromRegistryResource(Resource resource, String keyStoreName) { - - String encryptedPassword = resource.getProperty(RegistryResources.SecurityManagement.PROP_PASSWORD); - if (encryptedPassword == null) { - throw new SecurityException("Key Store Password of " + keyStoreName + " does not exist."); - } - return decryptPassword(encryptedPassword); - } - private Registry getGovernanceRegistry(int tenantId) { try { - return CarbonCoreDataHolder.getInstance().getRegistryService().getGovernanceSystemRegistry(tenantId); + return OSGiDataHolder.getInstance().getRegistryService().getGovernanceSystemRegistry(tenantId); } catch (Exception e) { throw new SecurityException("Error while getting the registry for tenant: " + tenantId, e); } } - - /** - * This method encrypts the given passwordChar using the default crypto util. - * - * @param passwordChar Password to be encrypted as a character array. - * @return encrypted password. - */ - private String encryptPassword(char[] passwordChar) { - - try { - return CryptoUtil.getDefaultCryptoUtil().encryptAndBase64Encode(String.valueOf(passwordChar).getBytes()); - } catch (CryptoException e) { - throw new SecurityException("Error encrypting the passwordChar", e); - } - } - - /** - * This method decrypts the given encrypted password using the default crypto util. - * - * @param encryptedPassword Encrypted password. - * @return decrypted password as a character array. - */ - private char[] decryptPassword(String encryptedPassword) { - - try { - CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil(); - return new String(cryptoUtil.base64DecodeAndDecrypt(encryptedPassword)).toCharArray(); - } catch (CryptoException e) { - throw new SecurityException("Error decrypting the password", e); - } - } - - private static void clearPasswordCharArray(char[] passwordChar) { - - Arrays.fill(passwordChar, '\0'); - } } diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java similarity index 97% rename from core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java rename to core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java index 263665d924..f710617360 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.carbon.core.security; +package org.wso2.carbon.keystore.persistence.model; /** * This class holds the metadata of a keystore. diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java new file mode 100644 index 0000000000..27a51ed29d --- /dev/null +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://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.keystore.persistence.model; + +import java.security.cert.X509Certificate; + +/** + * This is the model class for the key store. + */ +public class KeyStoreModel { + + String name; + String type; + String provider; + String encryptedPassword; + String privateKeyAlias; + String encryptedPrivateKeyPass; + byte[] content; + int tenantId; + String publicCertId; + X509Certificate publicCert; + + public KeyStoreModel() { + + } + + public KeyStoreModel(String name, String type, String provider, String encryptedPassword, String privateKeyAlias, + String encryptedPrivateKeyPass, byte[] content, int tenantId, String publicCertId, + X509Certificate publicCert) { + + this.name = name; + this.type = type; + this.provider = provider; + this.encryptedPassword = encryptedPassword; + this.privateKeyAlias = privateKeyAlias; + this.encryptedPrivateKeyPass = encryptedPrivateKeyPass; + this.content = content; + this.tenantId = tenantId; + this.publicCertId = publicCertId; + this.publicCert = publicCert; + } + + public String getName() { + + return name; + } + + public void setName(String name) { + + this.name = name; + } + + public String getPublicCertId() { + + return publicCertId; + } + + public void setPublicCertId(String publicCertId) { + + this.publicCertId = publicCertId; + } + + public String getType() { + + return type; + } + + public void setType(String type) { + + this.type = type; + } + + public String getProvider() { + + return provider; + } + + public void setProvider(String provider) { + + this.provider = provider; + } + + public int getTenantId() { + + return tenantId; + } + + public void setTenantId(int tenantId) { + + this.tenantId = tenantId; + } + + public byte[] getContent() { + + return content; + } + + public void setContent(byte[] content) { + + this.content = content; + } + + public String getEncryptedPassword() { + + return encryptedPassword; + } + + public void setEncryptedPassword(String encryptedPassword) { + + this.encryptedPassword = encryptedPassword; + } + + public String getPrivateKeyAlias() { + + return privateKeyAlias; + } + + public void setPrivateKeyAlias(String privateKeyAlias) { + + this.privateKeyAlias = privateKeyAlias; + } + + public String getEncryptedPrivateKeyPass() { + + return encryptedPrivateKeyPass; + } + + public void setEncryptedPrivateKeyPass(String encryptedPrivateKeyPass) { + + this.encryptedPrivateKeyPass = encryptedPrivateKeyPass; + } + + public X509Certificate getPublicCert() { + + return publicCert; + } + + public void setPublicCert(X509Certificate publicCert) { + + this.publicCert = publicCert; + } +} From 81371ca897b997fe750add42ff2cfad56211a7e1 Mon Sep 17 00:00:00 2001 From: UdeshAthukorala Date: Thu, 12 Dec 2024 21:47:19 +0530 Subject: [PATCH 2/4] Move keystore persistence manager implementations to org.wso2.carbon.utils component --- .../core/security/KeyStoreBasicModel.java} | 4 +- .../carbon/core/util/KeyStoreManager.java | 56 ++++++++++++++----- .../KeyStorePersistenceManager.java | 3 +- .../RegistryKeyStorePersistenceManager.java | 40 +++++++------ .../persistence/model/KeyStoreModel.java | 10 ++-- 5 files changed, 68 insertions(+), 45 deletions(-) rename core/{org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java => org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java} (95%) diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java similarity index 95% rename from core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java rename to core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java index f710617360..53db9f7951 100644 --- a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreMetadata.java +++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java @@ -16,12 +16,12 @@ * under the License. */ -package org.wso2.carbon.keystore.persistence.model; +package org.wso2.carbon.core.security; /** * This class holds the metadata of a keystore. */ -public class KeyStoreMetadata { +public class KeyStoreBasicModel { private String keyStoreName; private String keyStoreType; 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 2fee15e2ac..25a5f2a947 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 @@ -27,8 +27,8 @@ import org.wso2.carbon.base.api.ServerConfigurationService; import org.wso2.carbon.core.RegistryResources; import org.wso2.carbon.core.internal.CarbonCoreDataHolder; +import org.wso2.carbon.core.security.KeyStoreBasicModel; import org.wso2.carbon.keystore.persistence.RegistryKeyStorePersistenceManager; -import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.utils.CarbonUtils; @@ -53,6 +53,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; @@ -227,6 +228,7 @@ public void addKeyStore(byte[] keystoreContent, String filename, char[] password keyStoreModel.setContent(keystoreContent); keyStoreModel.setType(type); keyStoreModel.setProvider(provider); + keyStoreModel.setTenantId(tenantId); try (InputStream inputStream = new ByteArrayInputStream(keystoreContent)) { KeyStore keyStore = KeystoreUtils.getKeystoreInstance(type); @@ -234,7 +236,7 @@ public void addKeyStore(byte[] keystoreContent, String filename, char[] password String pvtKeyAlias = KeyStoreUtil.getPrivateKeyAlias(keyStore); if (StringUtils.isNotBlank(pvtKeyAlias)) { keyStoreModel.setPrivateKeyAlias(pvtKeyAlias); - X509Certificate publicCert = (X509Certificate) keyStore.getCertificate(pvtKeyAlias); + byte[] publicCert = keyStore.getCertificate(pvtKeyAlias).getEncoded(); if (publicCert != null) { keyStoreModel.setPublicCert(publicCert); @@ -306,29 +308,34 @@ public KeyStore getKeyStore(String keyStoreName) throws Exception { * @return KeyStoreMetaData[] Array of KeyStoreMetaData objects. * @throws SecurityException If an error occurs while retrieving the keystore data. */ - public KeyStoreMetadata[] getKeyStoresMetadata(boolean isSuperTenant) throws SecurityException { + public KeyStoreBasicModel[] getKeyStoresMetadata(boolean isSuperTenant) throws SecurityException { CarbonUtils.checkSecurity(); - List metadataList = registryKeyStorePersistenceManager.listKeyStores(tenantId); + List metadataList = new ArrayList<>(); + List keyStoreList = registryKeyStorePersistenceManager.listKeyStores(tenantId); + for (KeyStoreModel keyStoreModel : keyStoreList) { + metadataList.add(getKeyStoreMetaDataFromKeyStoreModel(keyStoreModel)); + } + if (isSuperTenant) { metadataList.add(getPrimaryKeyStoreMetadata()); } - return metadataList.toArray(new KeyStoreMetadata[0]); + return metadataList.toArray(new KeyStoreBasicModel[0]); } - private KeyStoreMetadata getPrimaryKeyStoreMetadata() { + private KeyStoreBasicModel getPrimaryKeyStoreMetadata() { 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); - KeyStoreMetadata primaryKeyStoreMetadata = new KeyStoreMetadata(); - primaryKeyStoreMetadata.setKeyStoreName(name); - primaryKeyStoreMetadata.setKeyStoreType(type); - primaryKeyStoreMetadata.setProvider(" "); - primaryKeyStoreMetadata.setPrivateStore(true); - return primaryKeyStoreMetadata; + KeyStoreBasicModel primaryKeyStoreBasicModel = new KeyStoreBasicModel(); + primaryKeyStoreBasicModel.setKeyStoreName(name); + primaryKeyStoreBasicModel.setKeyStoreType(type); + primaryKeyStoreBasicModel.setProvider(" "); + primaryKeyStoreBasicModel.setPrivateStore(true); + return primaryKeyStoreBasicModel; } /** @@ -421,9 +428,14 @@ public String getPassword(org.wso2.carbon.registry.core.Resource resource) throw */ public String getKeyStorePassword(String keyStoreName) { + return String.valueOf(getKeyStorePasswordAsCharArray(keyStoreName)); + } + + private char[] getKeyStorePasswordAsCharArray(String keyStoreName) { + String encryptedPassword = registryKeyStorePersistenceManager.getEncryptedKeyStorePassword(keyStoreName, tenantId); - return String.valueOf (decryptPassword(encryptedPassword)); + return decryptPassword(encryptedPassword); } /** @@ -486,7 +498,7 @@ private void updateTenantKeyStore(String keyStoreName, KeyStore keyStore) { char[] passwordChar = new char[0]; try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { KeyStoreModel keyStoreModel = new KeyStoreModel(); - passwordChar = getKeyStorePassword(keyStoreName).toCharArray(); + passwordChar = getKeyStorePasswordAsCharArray(keyStoreName); keyStore.store(outputStream, passwordChar); outputStream.flush(); keyStoreModel.setName(keyStoreName); @@ -912,6 +924,22 @@ public KeyStore loadKeyStoreFromFileSystem(String keyStorePath, String password, } } + private KeyStoreBasicModel getKeyStoreMetaDataFromKeyStoreModel(KeyStoreModel keyStoreModel) { + + KeyStoreBasicModel metadata = new KeyStoreBasicModel(); + metadata.setKeyStoreName(keyStoreModel.getName()); + metadata.setProvider(keyStoreModel.getProvider()); + metadata.setKeyStoreType(keyStoreModel.getType()); + metadata.setPrivateStore(keyStoreModel.getPrivateKeyAlias() != null); + String publicCertId = keyStoreModel.getPublicCertId(); + + if (StringUtils.isNotBlank(publicCertId)) { + metadata.setPublicCertId(keyStoreModel.getPublicCertId()); + metadata.setPublicCert(keyStoreModel.getPublicCert()); + } + return metadata; + } + /** * This method encrypts the given passwordChar using the default crypto util. * diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java index 0edc862c52..1ba3cbc1cb 100644 --- a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/KeyStorePersistenceManager.java @@ -18,7 +18,6 @@ package org.wso2.carbon.keystore.persistence; -import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import java.util.Date; @@ -54,7 +53,7 @@ public interface KeyStorePersistenceManager { * @return List of KeyStoreMetaData objects. * @throws SecurityException If an error occurs while retrieving the keystore data. */ - List listKeyStores(int tenantId) throws SecurityException; + List listKeyStores(int tenantId) throws SecurityException; /** * Update the key store in the data storage. diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java index e552a2269b..934804d6be 100644 --- a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/RegistryKeyStorePersistenceManager.java @@ -23,7 +23,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.internal.OSGiDataHolder; -import org.wso2.carbon.keystore.persistence.model.KeyStoreMetadata; import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import org.wso2.carbon.registry.api.Association; import org.wso2.carbon.registry.api.Collection; @@ -34,8 +33,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -86,11 +83,12 @@ public void addKeystore(KeyStoreModel keyStoreModel) throws SecurityException { resource.setContent(keyStoreModel.getContent()); if (StringUtils.isNotBlank(keyStoreModel.getPrivateKeyAlias())) { - resource.addProperty(PROP_PRIVATE_KEY_ALIAS, keyStoreModel.getEncryptedPrivateKeyPass()); + resource.addProperty(PROP_PRIVATE_KEY_ALIAS, keyStoreModel.getPrivateKeyAlias()); } if (StringUtils.isNotBlank(keyStoreModel.getEncryptedPrivateKeyPass())) { resource.addProperty(PROP_PRIVATE_KEY_PASS, keyStoreModel.getEncryptedPrivateKeyPass()); } + registry.put(getKeyStorePath(keyStoreModel.getName()), resource); if (isTenantPrimaryKeyStore) { // Create the public key resource for tenant's primary keystore. @@ -108,20 +106,20 @@ public void addKeystore(KeyStoreModel keyStoreModel) throws SecurityException { * @param publicCert Public certificate of the tenant. * @throws SecurityException If an error occurs while adding the tenant's public certificate. */ - private void addTenantPublicKey(String keyStoreName, X509Certificate publicCert, Registry registry) + private void addTenantPublicKey(String keyStoreName, byte[] publicCert, Registry registry) throws SecurityException { try { // Create the public key resource. Resource pubKeyResource = registry.newResource(); - pubKeyResource.setContent(publicCert.getEncoded()); + pubKeyResource.setContent(publicCert); pubKeyResource.addProperty(PROP_TENANT_PUB_KEY_FILE_NAME_APPENDER, generatePublicCertId()); registry.put(TENANT_PUBKEY_RESOURCE, pubKeyResource); // Associate the public key with the keystore. registry.addAssociation(KEY_STORES + REGISTRY_PATH_SEPARATOR + keyStoreName, TENANT_PUBKEY_RESOURCE, ASSOCIATION_TENANT_KS_PUB_KEY); - } catch (RegistryException | CertificateEncodingException e) { + } catch (RegistryException e) { throw new SecurityException("Error when writing the keystore public cert to registry for keystore: " + keyStoreName, e); } @@ -180,13 +178,13 @@ private String getKeyStorePath(String keyStoreName) { * @return List of KeyStoreMetaData objects. * @throws SecurityException If an error occurs while retrieving the keystore data. */ - public List listKeyStores(int tenantId) throws SecurityException { + public List listKeyStores(int tenantId) throws SecurityException { Registry registry = getGovernanceRegistry(tenantId); - List metadataList = new ArrayList<>(); + List keyStoreList = new ArrayList<>(); try { if (!registry.resourceExists(KEY_STORES)) { - return metadataList; + return keyStoreList; } Collection keyStoreCollection = (Collection) registry.get(KEY_STORES); @@ -196,15 +194,15 @@ public List listKeyStores(int tenantId) throws SecurityExcepti if (PRIMARY_KEYSTORE_PHANTOM_RESOURCE.equals(keyStorePath)) { continue; } - metadataList.add(getKeyStoreMetadata(keyStorePath, registry, tenantId)); + keyStoreList.add(getKeyStoreData(keyStorePath, registry, tenantId)); } - return metadataList; + return keyStoreList; } catch (RegistryException e) { throw new SecurityException("Error when getting keyStore metadata.", e); } } - private KeyStoreMetadata getKeyStoreMetadata(String keyStorePath, Registry registry, int tenantId) + private KeyStoreModel getKeyStoreData(String keyStorePath, Registry registry, int tenantId) throws RegistryException { Resource keyStoreResource = registry.get(keyStorePath); @@ -214,22 +212,22 @@ private KeyStoreMetadata getKeyStoreMetadata(String keyStorePath, Registry regis String provider = keyStoreResource.getProperty(PROP_PROVIDER); String alias = keyStoreResource.getProperty(PROP_PRIVATE_KEY_ALIAS); - KeyStoreMetadata keyStoreMetadata = new KeyStoreMetadata(); - keyStoreMetadata.setKeyStoreName(name); - keyStoreMetadata.setKeyStoreType(type); - keyStoreMetadata.setProvider(provider); - keyStoreMetadata.setPrivateStore(alias != null); + KeyStoreModel keyStoreModel = new KeyStoreModel(); + keyStoreModel.setName(name); + keyStoreModel.setType(type); + keyStoreModel.setProvider(provider); + keyStoreModel.setPrivateKeyAlias(alias); if (tenantId != MultitenantConstants.SUPER_TENANT_ID) { Association[] associations = registry.getAssociations(keyStorePath, ASSOCIATION_TENANT_KS_PUB_KEY); if (associations != null && associations.length > 0) { Resource pubKeyResource = registry.get(associations[0].getDestinationPath()); - keyStoreMetadata.setPublicCertId(pubKeyResource.getProperty(PROP_TENANT_PUB_KEY_FILE_NAME_APPENDER)); - keyStoreMetadata.setPublicCert((byte[]) pubKeyResource.getContent()); + keyStoreModel.setPublicCertId(pubKeyResource.getProperty(PROP_TENANT_PUB_KEY_FILE_NAME_APPENDER)); + keyStoreModel.setPublicCert((byte[]) pubKeyResource.getContent()); } } - return keyStoreMetadata; + return keyStoreModel; } /** diff --git a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java index 27a51ed29d..c7bb86b835 100644 --- a/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java +++ b/core/org.wso2.carbon.utils/src/main/java/org/wso2/carbon/keystore/persistence/model/KeyStoreModel.java @@ -18,8 +18,6 @@ package org.wso2.carbon.keystore.persistence.model; -import java.security.cert.X509Certificate; - /** * This is the model class for the key store. */ @@ -34,7 +32,7 @@ public class KeyStoreModel { byte[] content; int tenantId; String publicCertId; - X509Certificate publicCert; + byte[] publicCert; public KeyStoreModel() { @@ -42,7 +40,7 @@ public KeyStoreModel() { public KeyStoreModel(String name, String type, String provider, String encryptedPassword, String privateKeyAlias, String encryptedPrivateKeyPass, byte[] content, int tenantId, String publicCertId, - X509Certificate publicCert) { + byte[] publicCert) { this.name = name; this.type = type; @@ -146,12 +144,12 @@ public void setEncryptedPrivateKeyPass(String encryptedPrivateKeyPass) { this.encryptedPrivateKeyPass = encryptedPrivateKeyPass; } - public X509Certificate getPublicCert() { + public byte[] getPublicCert() { return publicCert; } - public void setPublicCert(X509Certificate publicCert) { + public void setPublicCert(byte[] publicCert) { this.publicCert = publicCert; } From 1b3e923dbedc6d36cd8a35e43c406cbba7821957 Mon Sep 17 00:00:00 2001 From: UdeshAthukorala Date: Thu, 12 Dec 2024 22:51:18 +0530 Subject: [PATCH 3/4] Move keystore persistence manager implementations to org.wso2.carbon.utils component --- ...eBasicModel.java => KeyStoreMetadata.java} | 2 +- .../carbon/core/util/KeyStoreManager.java | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) rename core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/{KeyStoreBasicModel.java => KeyStoreMetadata.java} (98%) diff --git a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java similarity index 98% rename from core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java rename to core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java index 53db9f7951..263665d924 100644 --- a/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreBasicModel.java +++ b/core/org.wso2.carbon.core/src/main/java/org/wso2/carbon/core/security/KeyStoreMetadata.java @@ -21,7 +21,7 @@ /** * This class holds the metadata of a keystore. */ -public class KeyStoreBasicModel { +public class KeyStoreMetadata { private String keyStoreName; private String keyStoreType; 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 25a5f2a947..ed6880c949 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 @@ -27,7 +27,7 @@ import org.wso2.carbon.base.api.ServerConfigurationService; import org.wso2.carbon.core.RegistryResources; import org.wso2.carbon.core.internal.CarbonCoreDataHolder; -import org.wso2.carbon.core.security.KeyStoreBasicModel; +import org.wso2.carbon.core.security.KeyStoreMetadata; import org.wso2.carbon.keystore.persistence.RegistryKeyStorePersistenceManager; import org.wso2.carbon.keystore.persistence.model.KeyStoreModel; import org.wso2.carbon.registry.core.service.RegistryService; @@ -308,10 +308,10 @@ public KeyStore getKeyStore(String keyStoreName) throws Exception { * @return KeyStoreMetaData[] Array of KeyStoreMetaData objects. * @throws SecurityException If an error occurs while retrieving the keystore data. */ - public KeyStoreBasicModel[] getKeyStoresMetadata(boolean isSuperTenant) throws SecurityException { + public KeyStoreMetadata[] getKeyStoresMetadata(boolean isSuperTenant) throws SecurityException { CarbonUtils.checkSecurity(); - List metadataList = new ArrayList<>(); + List metadataList = new ArrayList<>(); List keyStoreList = registryKeyStorePersistenceManager.listKeyStores(tenantId); for (KeyStoreModel keyStoreModel : keyStoreList) { metadataList.add(getKeyStoreMetaDataFromKeyStoreModel(keyStoreModel)); @@ -320,22 +320,22 @@ public KeyStoreBasicModel[] getKeyStoresMetadata(boolean isSuperTenant) throws S if (isSuperTenant) { metadataList.add(getPrimaryKeyStoreMetadata()); } - return metadataList.toArray(new KeyStoreBasicModel[0]); + return metadataList.toArray(new KeyStoreMetadata[0]); } - private KeyStoreBasicModel getPrimaryKeyStoreMetadata() { + private KeyStoreMetadata getPrimaryKeyStoreMetadata() { 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); - KeyStoreBasicModel primaryKeyStoreBasicModel = new KeyStoreBasicModel(); - primaryKeyStoreBasicModel.setKeyStoreName(name); - primaryKeyStoreBasicModel.setKeyStoreType(type); - primaryKeyStoreBasicModel.setProvider(" "); - primaryKeyStoreBasicModel.setPrivateStore(true); - return primaryKeyStoreBasicModel; + KeyStoreMetadata primaryKeyStoreMetadata = new KeyStoreMetadata(); + primaryKeyStoreMetadata.setKeyStoreName(name); + primaryKeyStoreMetadata.setKeyStoreType(type); + primaryKeyStoreMetadata.setProvider(" "); + primaryKeyStoreMetadata.setPrivateStore(true); + return primaryKeyStoreMetadata; } /** @@ -924,9 +924,9 @@ public KeyStore loadKeyStoreFromFileSystem(String keyStorePath, String password, } } - private KeyStoreBasicModel getKeyStoreMetaDataFromKeyStoreModel(KeyStoreModel keyStoreModel) { + private KeyStoreMetadata getKeyStoreMetaDataFromKeyStoreModel(KeyStoreModel keyStoreModel) { - KeyStoreBasicModel metadata = new KeyStoreBasicModel(); + KeyStoreMetadata metadata = new KeyStoreMetadata(); metadata.setKeyStoreName(keyStoreModel.getName()); metadata.setProvider(keyStoreModel.getProvider()); metadata.setKeyStoreType(keyStoreModel.getType()); From 23a30eda8cd3b64c9ce53678df37c2ae65d26b2c Mon Sep 17 00:00:00 2001 From: UdeshAthukorala Date: Thu, 12 Dec 2024 23:29:44 +0530 Subject: [PATCH 4/4] Move keystore persistence manager implementations to org.wso2.carbon.utils component --- .../java/org/wso2/carbon/core/util/KeyStoreManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/org.wso2.carbon.core/src/test/java/org/wso2/carbon/core/util/KeyStoreManagerTest.java b/core/org.wso2.carbon.core/src/test/java/org/wso2/carbon/core/util/KeyStoreManagerTest.java index d4a0582a36..6248812209 100644 --- a/core/org.wso2.carbon.core/src/test/java/org/wso2/carbon/core/util/KeyStoreManagerTest.java +++ b/core/org.wso2.carbon.core/src/test/java/org/wso2/carbon/core/util/KeyStoreManagerTest.java @@ -24,8 +24,8 @@ import org.wso2.carbon.base.CarbonBaseConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.base.ServerConfiguration; +import org.wso2.carbon.context.internal.OSGiDataHolder; import org.wso2.carbon.core.RegistryResources; -import org.wso2.carbon.core.internal.CarbonCoreDataHolder; import org.wso2.carbon.registry.core.Association; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; @@ -80,7 +80,7 @@ public void setup() throws KeyStoreException, RegistryException { System.setProperty(CarbonBaseConstants.CARBON_HOME, Paths.get(System.getProperty("user.dir"), "src", "test", "resources").toString()); - CarbonCoreDataHolder.getInstance().setRegistryService(this.registryService); + OSGiDataHolder.getInstance().setRegistryService(this.registryService); when(this.registryService.getGovernanceSystemRegistry(anyInt())).thenReturn(this.registry); keyStoreManager = KeyStoreManager.getInstance( MultitenantConstants.SUPER_TENANT_ID, serverConfiguration, registryService);