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