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