blob: b9ccf291b7486fdd1126670c1ac98169f7e6aca3 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.utils;
import android.os.Process;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import android.util.Log;
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.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
/**
* This class provides a portable and unified way to load the content of AndroidKeyStore through
* public API.
* @hide
*/
public class AndroidKeystoreAliasLoader {
private static final String TAG = "SettingsKeystoreUtils";
private final Collection<String> mKeyCertAliases;
private final Collection<String> mCaCertAliases;
/**
* This Constructor loads all aliases of asymmetric key pairs and certificates in the
* AndroidKeyStore within the given namespace.
* Viable namespaces are {@link KeyProperties#NAMESPACE_WIFI},
* {@link KeyProperties#NAMESPACE_APPLICATION}, or null. The latter two are equivalent in
* that they will load the keystore content of the app's own namespace. In case of settings,
* this is the namespace of the AID_SYSTEM.
*
* @param namespace {@link KeyProperties#NAMESPACE_WIFI},
* {@link KeyProperties#NAMESPACE_APPLICATION}, or null
* @hide
*/
public AndroidKeystoreAliasLoader(Integer namespace) {
mKeyCertAliases = new ArrayList<>();
mCaCertAliases = new ArrayList<>();
KeyStore keyStore = null;
final Enumeration<String> aliases;
try {
if (namespace != null && namespace != KeyProperties.NAMESPACE_APPLICATION) {
if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(new AndroidKeyStoreLoadStoreParameter(namespace));
} else {
// In the legacy case we pass in the WIFI UID because that is the only
// possible special namespace that existed as of this writing,
// and new namespaces must only be added using the new mechanism.
keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(Process.WIFI_UID);
}
} else {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
}
aliases = keyStore.aliases();
} catch (Exception e) {
Log.e(TAG, "Failed to open Android Keystore.", e);
// Will return empty lists.
return;
}
while (aliases.hasMoreElements()) {
final String alias = aliases.nextElement();
try {
final Key key = keyStore.getKey(alias, null);
if (key != null) {
if (key instanceof PrivateKey) {
mKeyCertAliases.add(alias);
}
} else {
if (keyStore.getCertificate(alias) != null) {
mCaCertAliases.add(alias);
}
}
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
Log.e(TAG, "Failed to load alias: "
+ alias + " from Android Keystore. Ignoring.", e);
}
}
}
/**
* Returns the aliases of the key pairs and certificates stored in the Android KeyStore at the
* time the constructor was called.
* @return Collection of keystore aliases.
* @hide
*/
public Collection<String> getKeyCertAliases() {
return mKeyCertAliases;
}
/**
* Returns the aliases of the trusted certificates stored in the Android KeyStore at the
* time the constructor was called.
* @return Collection of keystore aliases.
* @hide
*/
public Collection<String> getCaCertAliases() {
return mCaCertAliases;
}
}