• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.server.locksettings;
18 
19 import android.os.IBinder;
20 import android.os.RemoteException;
21 import android.service.gatekeeper.GateKeeperResponse;
22 import android.service.gatekeeper.IGateKeeperService;
23 import android.util.ArrayMap;
24 
25 import junit.framework.AssertionFailedError;
26 
27 import java.nio.ByteBuffer;
28 import java.util.Arrays;
29 import java.util.Random;
30 
31 public class FakeGateKeeperService implements IGateKeeperService {
32     static class VerifyHandle {
33         public byte[] password;
34         public long sid;
35 
VerifyHandle(byte[] password, long sid)36         public VerifyHandle(byte[] password, long sid) {
37             this.password = password;
38             this.sid = sid;
39         }
40 
VerifyHandle(byte[] handle)41         public VerifyHandle(byte[] handle) {
42             ByteBuffer buffer = ByteBuffer.allocate(handle.length);
43             buffer.put(handle, 0, handle.length);
44             buffer.flip();
45             int version = buffer.get();
46             sid = buffer.getLong();
47             password = new byte[buffer.remaining()];
48             buffer.get(password);
49         }
50 
toBytes()51         public byte[] toBytes() {
52             ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + password.length);
53             buffer.put((byte)0);
54             buffer.putLong(sid);
55             buffer.put(password);
56             return buffer.array();
57         }
58     }
59 
60     static class AuthToken {
61         public long challenge;
62         public long sid;
63 
AuthToken(long challenge, long sid)64         public AuthToken(long challenge, long sid) {
65             this.challenge = challenge;
66             this.sid = sid;
67         }
68 
AuthToken(byte[] handle)69         public AuthToken(byte[] handle) {
70             ByteBuffer buffer = ByteBuffer.allocate(handle.length);
71             buffer.put(handle, 0, handle.length);
72             buffer.flip();
73             int version = buffer.get();
74             challenge = buffer.getLong();
75             sid = buffer.getLong();
76         }
77 
toBytes()78         public byte[] toBytes() {
79             ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + Long.BYTES);
80             buffer.put((byte)0);
81             buffer.putLong(challenge);
82             buffer.putLong(sid);
83             return buffer.array();
84         }
85     }
86 
87     private ArrayMap<Integer, Long> sidMap = new ArrayMap<>();
88     private ArrayMap<Integer, AuthToken> authTokenMap = new ArrayMap<>();
89 
90     private ArrayMap<Integer, byte[]> handleMap = new ArrayMap<>();
91 
92     @Override
enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword, byte[] desiredPassword)93     public GateKeeperResponse enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword,
94             byte[] desiredPassword) throws android.os.RemoteException {
95         if (currentPasswordHandle != null) {
96             VerifyHandle handle = new VerifyHandle(currentPasswordHandle);
97             if (Arrays.equals(currentPassword, handle.password)) {
98                 // Trusted enroll
99                 VerifyHandle newHandle = new VerifyHandle(desiredPassword, handle.sid);
100                 refreshSid(uid, handle.sid, false);
101                 handleMap.put(uid, newHandle.toBytes());
102                 return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
103             } else if (currentPassword != null) {
104                 // current password is provided but does not match handle, this is an error case.
105                 return null;
106             }
107             // Fall through: password handle is provided, but no password
108         }
109         // Untrusted/new enrollment: generate a new SID
110         long newSid = new Random().nextLong();
111         VerifyHandle newHandle = new VerifyHandle(desiredPassword, newSid);
112         refreshSid(uid, newSid, true);
113         handleMap.put(uid, newHandle.toBytes());
114         return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
115     }
116 
117     @Override
verify(int uid, byte[] enrolledPasswordHandle, byte[] providedPassword)118     public GateKeeperResponse verify(int uid, byte[] enrolledPasswordHandle,
119             byte[] providedPassword) throws android.os.RemoteException {
120         return verifyChallenge(uid, 0, enrolledPasswordHandle, providedPassword);
121     }
122 
123     @Override
verifyChallenge(int uid, long challenge, byte[] enrolledPasswordHandle, byte[] providedPassword)124     public GateKeeperResponse verifyChallenge(int uid, long challenge,
125             byte[] enrolledPasswordHandle, byte[] providedPassword) throws RemoteException {
126 
127         VerifyHandle handle = new VerifyHandle(enrolledPasswordHandle);
128         if (Arrays.equals(handle.password, providedPassword)) {
129             byte[] knownHandle = handleMap.get(uid);
130             if (knownHandle != null) {
131                 if (!Arrays.equals(knownHandle, enrolledPasswordHandle)) {
132                     throw new AssertionFailedError("Got correct but obsolete handle");
133                 }
134             }
135             refreshSid(uid, handle.sid, false);
136             AuthToken token = new AuthToken(challenge, handle.sid);
137             refreshAuthToken(uid, token);
138             return GateKeeperResponse.createOkResponse(token.toBytes(), false);
139         } else {
140             return GateKeeperResponse.createGenericResponse(GateKeeperResponse.RESPONSE_ERROR);
141         }
142     }
143 
refreshAuthToken(int uid, AuthToken token)144     private void refreshAuthToken(int uid, AuthToken token) {
145         authTokenMap.put(uid, token);
146     }
147 
getAuthToken(int uid)148     public AuthToken getAuthToken(int uid) {
149         return authTokenMap.get(uid);
150     }
151 
getAuthTokenForSid(long sid)152     public AuthToken getAuthTokenForSid(long sid) {
153         for(AuthToken token : authTokenMap.values()) {
154             if (token.sid == sid) {
155                 return token;
156             }
157         }
158         return null;
159     }
160 
clearAuthToken(int uid)161     public void clearAuthToken(int uid) {
162         authTokenMap.remove(uid);
163     }
164 
165     @Override
asBinder()166     public IBinder asBinder() {
167         throw new UnsupportedOperationException();
168     }
169 
170     @Override
clearSecureUserId(int userId)171     public void clearSecureUserId(int userId) throws RemoteException {
172         sidMap.remove(userId);
173     }
174 
175     @Override
reportDeviceSetupComplete()176     public void reportDeviceSetupComplete() throws RemoteException {
177     }
178 
179     @Override
getSecureUserId(int userId)180     public long getSecureUserId(int userId) throws RemoteException {
181         if (sidMap.containsKey(userId)) {
182             return sidMap.get(userId);
183         } else {
184             return 0L;
185         }
186     }
187 
refreshSid(int uid, long sid, boolean force)188     private void refreshSid(int uid, long sid, boolean force) {
189         if (!sidMap.containsKey(uid) || force) {
190             sidMap.put(uid, sid);
191         } else{
192             if (sidMap.get(uid) != sid) {
193                 throw new AssertionFailedError("Inconsistent SID");
194             }
195         }
196     }
197 
198 }
199