Back to top

Install and get credentials through UCM

Last updated February 8th, 2024

This section describes how applications can access credentials through the UCM framework. The UCM framework provides a single set of APIs to access credentials on a variety of third-party storage devices. To browse the APIs available, see the package com.samsung.android.knox.ucm.configurator. If you are new to the UCM framework, see How the UCM framework works. If you are developing a UCM plugin, see Create a UCM plugin.

Before developing with Knox, ensure that you have activated your Knox license.

Check available credential storage

To find all the available credential storage on a device, call getAvailableCredentialStorage:

// System User Configuration
UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage[] storages = ucmManager.getAvailableCredentialStorages();
for (CredentialStorage cs: storages) {
  String name = cs.name;
  String packageName = cs.packageName;
  String manufacturer = cs.manufacturer;
  String signature = cs.signature;
}

If your application is running in a secure container, identify the container as follows:

// Container User Configuration
UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext, containerId);
CredentialStorage[] storages = ucmManager.getAvailableCredentialStorages();
for (CredentialStorage cs: storages) {
  String name = cs.name;
  String packageName = cs.packageName;
  String manufacturer = cs.manufacturer;
  String signature = cs.signature;
}

Manage a credential storage space

A credential storage can be either:

  • managed — The credential storage can be used by only allowed applications. This is described below.
  • unmanaged — The credential storage can be used by any application and no allowlist is enforced. See Store Keyguard credentials in UCM keystore for details.

Your app can manage a storage space through the UCM APIs. Managing storage space means performing the following:

  • Allow only specific apps to install certificates in the storage space. All other apps are forbidden to do so.
  • Create a list of approved apps that are allowed to access the storage space.
  • Create a list of approved apps that are allowed to access the credentials stored in the storage space.
  • Configure the storage space.
  • Use the storage space to keep the password for unlocking the device. If needed, the password can be retrieved by way of PIN authentication.
  • Use the storage space to keep the FBE (File Based Encryption) master key. If needed, the password can be retrieved using PIN or biometric authentication.
UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage cs = selectCredentialStorage();

// manage Credential Storage
int ret = ucmManager.manageCredentialStorage(cs, true);
boolean managed = ucmManager.isCredentialStorageManaged(cs);

// unmanage Credential Storage
ret = ucmManager.unmanageCredentialStorage(cs, false);

Install a certificate in a storage space

Your app can install or remove certificates from a managed storage space. You can identify certificates used to authenticate access to VPN.

Your app can manage only the certificates it installs, and cannot managed certificates installed by other apps in the storage.

UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage cs = selectCredentialStorage();

// Read certificate file
File certFile = new File("/mnt/sdcard/cert.p12");
byte certBuffer[] = new byte[(int) certFile.length()];
FileInputStream certfis = new FileInputStream(certFile);
certfis.read(certBuffer);
certfis.close();

String alias = "Test";
String password = "1234";

int result = ucmManager.installCertificate(cs, certByffer, alias, password, Null);

Allow an app for storage access

To allow an application to access credential storage, you must first set up a managed credential storage as described above. Then, to add the application to the allowlist:

UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage cs = selectCredentialStorage();

List<AppIdentity> appList = new ArrayList<AppIdentity>();
AppIdentity pkg = new AppIdentity();
pkg.setPackageName("com.android.email");
String signatureHash = "ABCDEF";
// Application signature is optional, but it is recommended to send application signature for security purpose.
pkg.setSignature(signatureHash);
appList.add(pkg);

// add allowlist application to access Credential Storage
Bundle data = new Bundle();
data.putInt(BUNDLE_EXTRA_ACCESS_TYPE, UCM_ACCESS_TYPE_STORAGE);
int result = mUCM.addPackagesToWhiteList(cs, appList, data);

// add allowlist application to access the certificate stored inside Credential Storage
data.putInt(BUNDLE_EXTRA_ACCESS_TYPE, UCM_ACCESS_TYPE_CERTIFICATE);
String alias = "TestCertificate";
data.putString(BUNDLE_EXTRA_ALIAS, alias);
result = mUCM.addPackagesToWhiteList(cs, appList, data);

You can use the wild character (*) to add all applications to the allowlist, then remove select applications that you don’t want to access the storage.

As described in How the UCM framework works, your app cannot control the allowlist of pre-installed certificates. If the credential storage has pre-installed certificates, an app can use the certificate only through storage access permissions.

Secure credentials using JCE

The UCM framework supports standard Java Cryptography Extension (JCE) APIs to encrypt credentials.

Your application can add a UCM plugin keystore provider, create a keystore instance, and perform cryptographic operations on credentials in the keystore.

The JCE framework and UCM framework route calls to the correct UCM provider and credential storage as shown below:

UsingJCE.png

To add a UCM keystore provider and create an instance of a keystore:

UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage cs = selectCredentialStorage();

// Add providers
UniversalCredentialUtil ucmUtil = UniversalCredentialUtil.getInstance();
Provider[] providerList = ucmUtil.getProviders();
String providerName = "";
for (Provider provider: providerList) {
  providerName = provider.getName();
  // Plugin Properties
  String pluginId = provider.getProperty(UniversalCredentialUtil.AGENT_ID);
  String pluginSummary = provider.getProperty(UniversalCredentialUtil.AGENT_SUMMARY);
  String pluginTitle = provider.getProperty(UniversalCredentialUtil.AGENT_TITLE);
  String pluginVendorId = provider.getProperty(UniversalCredentialUtil.AGENT_VENDORID);
  int position = Security.addProvider(provider);
}

// Get provider
KeyStore ucmKeystore = KeyStore.getInstance("KNOX", providerName);
ucmKeyStore.load(null);

Get credentials from a UCM keystore

The UCM framework is integrated with the Android KeyChain class. This means that apps that are already using the KeyChain API to access certificates can continue to do so when those certificates are stored by way of the UCM framework.

Of course, the app still needs to be allowed for the particular storage space which contains the certificate and the certificate must also be allowed for the app.

Each credential storage has an alias by which applications refer to the certificate when retrieving it. As multiple storage providers may be used, alias name clash is an issue. So UCM expands the alias to include the source credential storage as well in the following URI scheme:

ucmkeychain://source/resourceId/uid/alias
  • source is the name of the credential storage provider
  • resourceId is an integer which indicates one of the following types:
    • Private KeyChain
    • Public KeyChain
    • All
  • uid is the Android UID for the requesting application
  • alias is the name provided by the storage vendor’s plugin for the storage space

URI-Flow.png

Your application can retrieve the full URI for a credential directly as shown below. After the URI is known, your application can call a KeyChain API such as getPrivateKey() or getCertificateChains() to retrieve the credentials.

// Use Knox UCM to get URI string that represents credential storage and its resource from keychain
String ucmAlias = UniversalCredentialUtil.getKeychainUri("com.samsung.testplugin:pluginname", "TestCertificate");
// Get credentials
PrivateKey privatekey = KeyChain.getPrivateKey(getApplicationContext(), ucmAlias);
X509Certificate[] certList = KeyChain.getCertificateChain(getApplicationContext(), ucmAlias);

Your application can also retrieve the credentials from a UCM keystore by calling the Android KeyChainAliasCallback() API as follows:

// Use Android KeychainAliasCallback to get credentials
public class MainActivity extends Activity implements KeyChainAliasCallback {
  @Override
  public void alias(final String alias) {
    String ucmAlias = alias;
    PrivateKey privatekey = KeyChain.getPrivateKey(getApplicationContext(), ucmAlias);
    X509Certificate[] certList = KeyChain.getCertificateChain(getApplicationContext(), ucmAlias);
  }
}

Store Keyguard credentials in UCM keystore

Android’s Keyguard uses the Gatekeeper and KeyMaster components to authenticate device users based on their pattern, PIN, or password. The UCM framework is integrated with Keyguard such that an application can store the device unlock credentials in a secure UCM keystore.

An application must have the appropriate privileges and permissions to store the credentials in UCM keystore, either through Device Admin or Android Enterprise DO.

UCM passes the user unlock data to the credential storage for verification. Upon success, the credential storage gives the generated password to the UCM framework which, in turn, verifies whether or not the password is proper with the Gatekeeper.

The following diagram shows the flow for this process:

keyguard.png

The UCM Keyguard is based on user authentication so the storage vendor’s plugin must support password generation by way of the generateKeyguardPassword() call.

UniversalCredentialManager ucmManager = UniversalCredentialManager.getUCMManager(mContext);
CredentialStorage cs = selectCredentialStorage();

// enforce UCM Keyguard
Bundle options = new Bundle();
int result = ucmManager.enforceCredentialStorageAsLockType(cs, options);

// check enforced Credential Storage
CredentialStorage enforced = ucmManager.getEnforcedCredentialStorageForLockType();
String name = cs.name;
String packageName = cs.packageName;
String manufacturer = cs.manufacturer
String signature = cs.signature;

// disable UCM Keyguard
result = ucmManager.enforceCredentialStorageAsLockType(null, null);

Enabling UCM Keyguard requires user interaction because a notification appears when the app calls the enforceCredentialStorageAsLockType.

If the device lock type is changed to the UCM Keyguard by a someone other than your application, the lock type can’t be altered by anyone other than the user who set it initially.

When the UCM Keyguard status changes (set or unset), an application can receive an intent that includes status and package information as shown in the following code sample:

private BroadcastReceiver mUcmReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(UniversalCredentialManager.ACTION_UCM_KEYGUARD_SET)) {
      Bundle data = intent.getExtras();
      if (data != null) {
        int usertId = data.getInt(UniversalCredentialManager.BUNDLE_EXTRA_USER_ID, 0);
        String packageName = data.getString(UniversalCredentialManager.BUNDLE_EXTRA_PACKAGE);
      }
    } else if (intent.getAction().equals(UniversalCredentialManager.ACTION_UCM_KEYGUARD_UNSET)) {
      Bundle data = intent.getExtras();
      if (data != null) {
        int usertId = data.getInt(UniversalCredentialManager.BUNDLE_EXTRA_USER_ID, 0);
        String packageName = data.getString(UniversalCredentialManager.BUNDLE_EXTRA_PACKAGE);
      }
    }
  }
};

IntentFilter filter = new IntentFilter();
filter.addAction(UniversalCredentialManager.ACTION_UCM_KEYGUARD_SET);
filter.addAction(UniversalCredentialManager.ACTION_UCM_KEYGUARD_UNSET);
registerReceiver(mUcmReceiver, filter);

Is this page helpful?