1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.utils; 18 19 import android.security.keystore.KeyProperties; 20 import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; 21 import android.util.Log; 22 23 import java.security.Key; 24 import java.security.KeyStore; 25 import java.security.KeyStoreException; 26 import java.security.NoSuchAlgorithmException; 27 import java.security.PrivateKey; 28 import java.security.UnrecoverableKeyException; 29 import java.security.cert.Certificate; 30 import java.util.ArrayList; 31 import java.util.Collection; 32 import java.util.Enumeration; 33 34 /** 35 * This class provides a portable and unified way to load the content of AndroidKeyStore through 36 * public API. 37 * @hide 38 */ 39 public class AndroidKeystoreAliasLoader { 40 private static final String TAG = "SettingsKeystoreUtils"; 41 42 private static final String KEYSTORE_PROVIDER = "AndroidKeyStore"; 43 44 private final Collection<String> mKeyCertAliases; 45 private final Collection<String> mCaCertAliases; 46 /** 47 * This Constructor loads all aliases of asymmetric keys pairs and certificates in the 48 * AndroidKeyStore within the given namespace. 49 * Viable namespaces are {@link KeyProperties#NAMESPACE_WIFI}, 50 * {@link KeyProperties#NAMESPACE_APPLICATION}, or null. The latter two are equivalent in 51 * that they will load the keystore content of the app's own namespace. In case of settings, 52 * this is the namespace of the AID_SYSTEM. 53 * 54 * @param namespace {@link KeyProperties#NAMESPACE_WIFI}, 55 * {@link KeyProperties#NAMESPACE_APPLICATION}, or null 56 * @hide 57 */ AndroidKeystoreAliasLoader(Integer namespace)58 public AndroidKeystoreAliasLoader(Integer namespace) { 59 mKeyCertAliases = new ArrayList<>(); 60 mCaCertAliases = new ArrayList<>(); 61 final KeyStore keyStore; 62 final Enumeration<String> aliases; 63 try { 64 keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER); 65 if (namespace != null && namespace != KeyProperties.NAMESPACE_APPLICATION) { 66 keyStore.load(new AndroidKeyStoreLoadStoreParameter(namespace)); 67 } else { 68 keyStore.load(null); 69 } 70 aliases = keyStore.aliases(); 71 } catch (Exception e) { 72 Log.e(TAG, "Failed to open Android Keystore.", e); 73 // Will return empty lists. 74 return; 75 } 76 77 while (aliases.hasMoreElements()) { 78 final String alias = aliases.nextElement(); 79 try { 80 final Key key = keyStore.getKey(alias, null); 81 if (key != null) { 82 if (key instanceof PrivateKey) { 83 mKeyCertAliases.add(alias); 84 final Certificate[] cert = keyStore.getCertificateChain(alias); 85 if (cert != null && cert.length >= 2) { 86 mCaCertAliases.add(alias); 87 } 88 } 89 } else { 90 if (keyStore.getCertificate(alias) != null) { 91 mCaCertAliases.add(alias); 92 } 93 } 94 } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) { 95 Log.e(TAG, "Failed to load alias: " 96 + alias + " from Android Keystore. Ignoring.", e); 97 } 98 } 99 } 100 101 /** 102 * Returns the aliases of the key pairs and certificates stored in the Android KeyStore at the 103 * time the constructor was called. 104 * @return Collection of keystore aliases. 105 * @hide 106 */ getKeyCertAliases()107 public Collection<String> getKeyCertAliases() { 108 return mKeyCertAliases; 109 } 110 111 /** 112 * Returns the aliases of the trusted certificates stored in the Android KeyStore at the 113 * time the constructor was called. 114 * @return Collection of keystore aliases. 115 * @hide 116 */ getCaCertAliases()117 public Collection<String> getCaCertAliases() { 118 return mCaCertAliases; 119 } 120 } 121