• 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.recoverablekeystore.storage;
18 
19 import android.annotation.Nullable;
20 import android.util.SparseArray;
21 
22 import com.android.internal.widget.LockPatternUtils;
23 
24 import java.util.ArrayList;
25 
26 import javax.security.auth.Destroyable;
27 
28 /**
29  * Stores pending recovery sessions in memory. We do not write these to disk, as it contains hashes
30  * of the user's lock screen.
31  *
32  * @hide
33  */
34 public class RecoverySessionStorage implements Destroyable {
35 
36     private final SparseArray<ArrayList<Entry>> mSessionsByUid = new SparseArray<>();
37 
38     /**
39      * Returns the session for the given user with the given id.
40      *
41      * @param uid The uid of the recovery agent who created the session.
42      * @param sessionId The unique identifier for the session.
43      * @return The session info.
44      *
45      * @hide
46      */
47     @Nullable
get(int uid, String sessionId)48     public Entry get(int uid, String sessionId) {
49         ArrayList<Entry> userEntries = mSessionsByUid.get(uid);
50         if (userEntries == null) {
51             return null;
52         }
53         for (Entry entry : userEntries) {
54             if (sessionId.equals(entry.mSessionId)) {
55                 return entry;
56             }
57         }
58         return null;
59     }
60 
61     /**
62      * Adds a pending session for the given user.
63      *
64      * @param uid The uid of the recovery agent who created the session.
65      * @param entry The session info.
66      *
67      * @hide
68      */
add(int uid, Entry entry)69     public void add(int uid, Entry entry) {
70         if (mSessionsByUid.get(uid) == null) {
71             mSessionsByUid.put(uid, new ArrayList<>());
72         }
73         mSessionsByUid.get(uid).add(entry);
74     }
75 
76     /**
77      * Deletes the session with {@code sessionId} created by app with {@code uid}.
78      */
remove(int uid, String sessionId)79     public void remove(int uid, String sessionId) {
80         if (mSessionsByUid.get(uid) == null) {
81             return;
82         }
83         mSessionsByUid.get(uid).removeIf(session -> session.mSessionId.equals(sessionId));
84     }
85 
86     /**
87      * Removes all sessions associated with the given recovery agent uid.
88      *
89      * @param uid The uid of the recovery agent whose sessions to remove.
90      *
91      * @hide
92      */
remove(int uid)93     public void remove(int uid) {
94         ArrayList<Entry> entries = mSessionsByUid.get(uid);
95         if (entries == null) {
96             return;
97         }
98         for (Entry entry : entries) {
99             entry.destroy();
100         }
101         mSessionsByUid.remove(uid);
102     }
103 
104     /**
105      * Returns the total count of pending sessions.
106      *
107      * @hide
108      */
size()109     public int size() {
110         int size = 0;
111         int numberOfUsers = mSessionsByUid.size();
112         for (int i = 0; i < numberOfUsers; i++) {
113             ArrayList<Entry> entries = mSessionsByUid.valueAt(i);
114             size += entries.size();
115         }
116         return size;
117     }
118 
119     /**
120      * Wipes the memory of any sensitive information (i.e., lock screen hashes and key claimants).
121      *
122      * @hide
123      */
124     @Override
destroy()125     public void destroy() {
126         int numberOfUids = mSessionsByUid.size();
127         for (int i = 0; i < numberOfUids; i++) {
128             ArrayList<Entry> entries = mSessionsByUid.valueAt(i);
129             for (Entry entry : entries) {
130                 entry.destroy();
131             }
132         }
133     }
134 
135     /**
136      * Information about a recovery session.
137      *
138      * @hide
139      */
140     public static class Entry implements Destroyable {
141         private final byte[] mLskfHash;
142         private final byte[] mKeyClaimant;
143         private final byte[] mVaultParams;
144         private final String mSessionId;
145 
146         /**
147          * @hide
148          */
Entry(String sessionId, byte[] lskfHash, byte[] keyClaimant, byte[] vaultParams)149         public Entry(String sessionId, byte[] lskfHash, byte[] keyClaimant, byte[] vaultParams) {
150             mLskfHash = lskfHash;
151             mSessionId = sessionId;
152             mKeyClaimant = keyClaimant;
153             mVaultParams = vaultParams;
154         }
155 
156         /**
157          * Returns the hash of the lock screen associated with the recovery attempt.
158          *
159          * @hide
160          */
getLskfHash()161         public byte[] getLskfHash() {
162             return mLskfHash;
163         }
164 
165         /**
166          * Returns the key generated for this recovery attempt (used to decrypt data returned by
167          * the server).
168          *
169          * @hide
170          */
getKeyClaimant()171         public byte[] getKeyClaimant() {
172             return mKeyClaimant;
173         }
174 
175         /**
176          * Returns the vault params associated with the session.
177          *
178          * @hide
179          */
getVaultParams()180         public byte[] getVaultParams() {
181             return mVaultParams;
182         }
183 
184         /**
185          * Overwrites the memory for the lskf hash and key claimant.
186          *
187          * @hide
188          */
189         @Override
destroy()190         public void destroy() {
191             LockPatternUtils.zeroize(mLskfHash);
192             LockPatternUtils.zeroize(mKeyClaimant);
193         }
194     }
195 }
196