Menu

Install and get credentials through UCM

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 UCM 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 whitelisted applications. This is described below.
  • unmanaged: The credential storage can be used by any application and no whitelisting is enforced. This is described in Configure Keyguard settings.

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 On-Device Encryption (ODE) key. If needed, the password can be retrieved by way of PIN 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 or Wi-Fi.

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";
Bundle options = new Bundle();
// To install certificate for Wi-Fi
options.putBoolean(UniversalCredentialManager.BUNDLE_EXTRA_ALLOW_WIFI, true);
// To install certificate for VPN and apps
options.putBoolean(UniversalCredentialManager.BUNDLE_EXTRA_ALLOW_WIFI, false);

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

Whitelist an app for storage access

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

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 whitelist 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 whitelist 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 whitelist, then remove select applications that you don't want to access the storage.

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

Manage storage space properties

Some credential storage has plugin-specific properties such as a PIN unlock from timing out. You can configure the properties as follows:

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

Bundle data = new Bundle();
// Set Property
String propertyTag = "PIN_TIMEOUT"; // This value should be supported by plugin vendor
int timeoutInterval = 10;
data.putInt(propertyTag, timeoutInterval);
Bundle result = ucmManager.setCredentialStorageProperty(cs, data);

// Get Property
Bundle retrived = ucmManager.getCredentialStorageProperty(cs, data);

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:

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 whitelisted for the particular storage space which contains the certificate and the certificate must also be whitelisted 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
    • WiFI 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

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 do so, through either Device Admin or Android Enterprise DO/PO.

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:

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);