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 android.security;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.os.ServiceManager;
22 import android.os.ServiceSpecificException;
23 import android.security.maintenance.IKeystoreMaintenance;
24 import android.system.keystore2.Domain;
25 import android.system.keystore2.KeyDescriptor;
26 import android.system.keystore2.ResponseCode;
27 import android.util.Log;
28 
29 /**
30  * @hide This is the client side for IKeystoreUserManager AIDL.
31  * It shall only be used by the LockSettingsService.
32  */
33 public class AndroidKeyStoreMaintenance {
34     private static final String TAG = "AndroidKeyStoreMaintenance";
35 
36     public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
37     public static final int INVALID_ARGUMENT = ResponseCode.INVALID_ARGUMENT;
38     public static final int PERMISSION_DENIED = ResponseCode.PERMISSION_DENIED;
39     public static final int KEY_NOT_FOUND = ResponseCode.KEY_NOT_FOUND;
40 
getService()41     private static IKeystoreMaintenance getService() {
42         return IKeystoreMaintenance.Stub.asInterface(
43                 ServiceManager.checkService("android.security.maintenance"));
44     }
45 
46     /**
47      * Informs Keystore 2.0 about adding a user
48      *
49      * @param userId - Android user id of the user being added
50      * @return 0 if successful or a {@code ResponseCode}
51      * @hide
52      */
onUserAdded(@onNull int userId)53     public static int onUserAdded(@NonNull int userId) {
54         try {
55             getService().onUserAdded(userId);
56             return 0;
57         } catch (ServiceSpecificException e) {
58             Log.e(TAG, "onUserAdded failed", e);
59             return e.errorCode;
60         } catch (Exception e) {
61             Log.e(TAG, "Can not connect to keystore", e);
62             return SYSTEM_ERROR;
63         }
64     }
65 
66     /**
67      * Informs Keystore 2.0 about removing a usergit mer
68      *
69      * @param userId - Android user id of the user being removed
70      * @return 0 if successful or a {@code ResponseCode}
71      * @hide
72      */
onUserRemoved(int userId)73     public static int onUserRemoved(int userId) {
74         try {
75             getService().onUserRemoved(userId);
76             return 0;
77         } catch (ServiceSpecificException e) {
78             Log.e(TAG, "onUserRemoved failed", e);
79             return e.errorCode;
80         } catch (Exception e) {
81             Log.e(TAG, "Can not connect to keystore", e);
82             return SYSTEM_ERROR;
83         }
84     }
85 
86     /**
87      * Informs Keystore 2.0 about changing user's password
88      *
89      * @param userId   - Android user id of the user
90      * @param password - a secret derived from the synthetic password provided by the
91      *                 LockSettingService
92      * @return 0 if successful or a {@code ResponseCode}
93      * @hide
94      */
onUserPasswordChanged(int userId, @Nullable byte[] password)95     public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
96         try {
97             getService().onUserPasswordChanged(userId, password);
98             return 0;
99         } catch (ServiceSpecificException e) {
100             Log.e(TAG, "onUserPasswordChanged failed", e);
101             return e.errorCode;
102         } catch (Exception e) {
103             Log.e(TAG, "Can not connect to keystore", e);
104             return SYSTEM_ERROR;
105         }
106     }
107 
108     /**
109      * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to
110      * be cleared.
111      */
clearNamespace(@omain int domain, long namespace)112     public static int clearNamespace(@Domain int domain, long namespace) {
113         try {
114             getService().clearNamespace(domain, namespace);
115             return 0;
116         } catch (ServiceSpecificException e) {
117             Log.e(TAG, "clearNamespace failed", e);
118             return e.errorCode;
119         } catch (Exception e) {
120             Log.e(TAG, "Can not connect to keystore", e);
121             return SYSTEM_ERROR;
122         }
123     }
124 
125     /**
126      * Queries user state from Keystore 2.0.
127      *
128      * @param userId - Android user id of the user.
129      * @return UserState enum variant as integer if successful or an error
130      */
getState(int userId)131     public static int getState(int userId) {
132         try {
133             return getService().getState(userId);
134         } catch (ServiceSpecificException e) {
135             Log.e(TAG, "getState failed", e);
136             return e.errorCode;
137         } catch (Exception e) {
138             Log.e(TAG, "Can not connect to keystore", e);
139             return SYSTEM_ERROR;
140         }
141     }
142 
143     /**
144      * Informs Keystore 2.0 that an off body event was detected.
145      */
onDeviceOffBody()146     public static void onDeviceOffBody() {
147         try {
148             getService().onDeviceOffBody();
149         } catch (Exception e) {
150             // TODO This fails open. This is not a regression with respect to keystore1 but it
151             //      should get fixed.
152             Log.e(TAG, "Error while reporting device off body event.", e);
153         }
154     }
155 
156     /**
157      * Migrates a key given by the source descriptor to the location designated by the destination
158      * descriptor.
159      *
160      * @param source - The key to migrate may be specified by Domain.APP, Domain.SELINUX, or
161      *               Domain.KEY_ID. The caller needs the permissions use, delete, and grant for the
162      *               source namespace.
163      * @param destination - The new designation for the key may be specified by Domain.APP or
164      *                    Domain.SELINUX. The caller need the permission rebind for the destination
165      *                    namespace.
166      *
167      * @return * 0 on success
168      *         * KEY_NOT_FOUND if the source did not exists.
169      *         * PERMISSION_DENIED if any of the required permissions was missing.
170      *         * INVALID_ARGUMENT if the destination was occupied or any domain value other than
171      *                   the allowed once were specified.
172      *         * SYSTEM_ERROR if an unexpected error occurred.
173      */
migrateKeyNamespace(KeyDescriptor source, KeyDescriptor destination)174     public static int migrateKeyNamespace(KeyDescriptor source, KeyDescriptor destination) {
175         try {
176             getService().migrateKeyNamespace(source, destination);
177             return 0;
178         } catch (ServiceSpecificException e) {
179             Log.e(TAG, "migrateKeyNamespace failed", e);
180             return e.errorCode;
181         } catch (Exception e) {
182             Log.e(TAG, "Can not connect to keystore", e);
183             return SYSTEM_ERROR;
184         }
185     }
186 }
187