/* * 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.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.security.cert.Certificate; 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 static final String KEYSTORE_PROVIDER = "AndroidKeyStore"; private final Collection mKeyCertAliases; private final Collection mCaCertAliases; /** * This Constructor loads all aliases of asymmetric keys 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<>(); final KeyStore keyStore; final Enumeration aliases; try { keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER); if (namespace != null && namespace != KeyProperties.NAMESPACE_APPLICATION) { keyStore.load(new AndroidKeyStoreLoadStoreParameter(namespace)); } else { 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); final Certificate[] cert = keyStore.getCertificateChain(alias); if (cert != null && cert.length >= 2) { mCaCertAliases.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 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 getCaCertAliases() { return mCaCertAliases; } }