blob: 2fde0da882ef26858f983518b83f49954e682187 [file] [log] [blame]
Chad Brubaker40a1a9b2015-02-20 14:08:13 -08001/*
2 * Copyright (C) 2015 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#define LOG_TAG "KeystoreOperation"
17
18#include "operation.h"
19
20#include <algorithm>
21
22namespace android {
23OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient)
24 : mDeathRecipient(deathRecipient) {
25}
26
27sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle,
28 const keymaster1_device_t* dev,
Chad Brubaker06801e02015-03-31 15:13:13 -070029 sp<IBinder> appToken,
30 const keymaster_key_blob_t& key, bool pruneable) {
Chad Brubaker40a1a9b2015-02-20 14:08:13 -080031 sp<IBinder> token = new BBinder();
Chad Brubaker06801e02015-03-31 15:13:13 -070032 mMap[token] = Operation(handle, dev, key, appToken);
Chad Brubaker40a1a9b2015-02-20 14:08:13 -080033 if (pruneable) {
34 mLru.push_back(token);
35 }
36 if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) {
37 appToken->linkToDeath(mDeathRecipient);
38 }
39 mAppTokenMap[appToken].push_back(token);
40 return token;
41}
42
43bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle,
Chad Brubaker06801e02015-03-31 15:13:13 -070044 const keymaster1_device_t** outDevice,
45 keymaster_key_blob_t* key) {
Chad Brubaker40a1a9b2015-02-20 14:08:13 -080046 if (!outHandle || !outDevice) {
47 return false;
48 }
49 auto entry = mMap.find(token);
50 if (entry == mMap.end()) {
51 return false;
52 }
53 updateLru(token);
54
55 *outHandle = entry->second.handle;
56 *outDevice = entry->second.device;
Chad Brubaker06801e02015-03-31 15:13:13 -070057 if (key) {
58 key->key_material_size = entry->second.key.key_material_size;
59 uint8_t* material = new uint8_t[key->key_material_size];
60 memcpy(reinterpret_cast<void*>(material), entry->second.key.key_material,
61 key->key_material_size);
62 key->key_material = material;
63 }
Chad Brubaker40a1a9b2015-02-20 14:08:13 -080064 return true;
65}
66
67void OperationMap::updateLru(sp<IBinder> token) {
68 auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
69 if (lruEntry != mLru.end()) {
70 mLru.erase(lruEntry);
71 mLru.push_back(token);
72 }
73}
74
75bool OperationMap::removeOperation(sp<IBinder> token) {
76 auto entry = mMap.find(token);
77 if (entry == mMap.end()) {
78 return false;
79 }
80 sp<IBinder> appToken = entry->second.appToken;
Chad Brubaker06801e02015-03-31 15:13:13 -070081 delete[] entry->second.key.key_material;
Chad Brubaker40a1a9b2015-02-20 14:08:13 -080082 mMap.erase(entry);
83 auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
84 if (lruEntry != mLru.end()) {
85 mLru.erase(lruEntry);
86 }
87 removeOperationTracking(token, appToken);
88 return true;
89}
90
91void OperationMap::removeOperationTracking(sp<IBinder> token, sp<IBinder> appToken) {
92 auto appEntry = mAppTokenMap.find(appToken);
93 if (appEntry == mAppTokenMap.end()) {
94 ALOGE("Entry for %p contains unmapped application token %p", token.get(), appToken.get());
95 return;
96 }
97 auto tokenEntry = std::find(appEntry->second.begin(), appEntry->second.end(), token);
98 appEntry->second.erase(tokenEntry);
99 // Stop listening for death if all operations tied to the token have finished.
100 if (appEntry->second.size() == 0) {
101 appToken->unlinkToDeath(mDeathRecipient);
102 mAppTokenMap.erase(appEntry);
103 }
104}
105
106bool OperationMap::hasPruneableOperation() {
107 return mLru.size() != 0;
108}
109
110sp<IBinder> OperationMap::getOldestPruneableOperation() {
111 if (!hasPruneableOperation()) {
112 return sp<IBinder>(NULL);
113 }
114 return mLru[0];
115}
116
117std::vector<sp<IBinder>> OperationMap::getOperationsForToken(sp<IBinder> appToken) {
118 auto appEntry = mAppTokenMap.find(appToken);
119 if (appEntry != mAppTokenMap.end()) {
120 return appEntry->second;
121 } else {
122 return std::vector<sp<IBinder>>();
123 }
124}
125
126OperationMap::Operation::Operation(keymaster_operation_handle_t handle_,
127 const keymaster1_device_t* device_,
Chad Brubaker06801e02015-03-31 15:13:13 -0700128 const keymaster_key_blob_t& key_,
Chad Brubaker40a1a9b2015-02-20 14:08:13 -0800129 sp<IBinder> appToken_)
130 : handle(handle_),
131 device(device_),
132 appToken(appToken_) {
Chad Brubaker06801e02015-03-31 15:13:13 -0700133 uint8_t* material = new uint8_t[key_.key_material_size];
134 memcpy(material, key_.key_material, key_.key_material_size);
135 key.key_material = material;
136 key.key_material_size = key_.key_material_size;
Chad Brubaker40a1a9b2015-02-20 14:08:13 -0800137}
138
139OperationMap::Operation::Operation() : handle(0), device(NULL), appToken(NULL) {
Chad Brubaker06801e02015-03-31 15:13:13 -0700140 key.key_material = NULL;
141 key.key_material_size = 0;
Chad Brubaker40a1a9b2015-02-20 14:08:13 -0800142}
143} // namespace android