blob: 4ccd3f142013b95d333824e411dcb9e8c41a519c [file] [log] [blame]
Shawn Willden5ada7b62014-07-29 09:44:17 -06001/*
2 * Copyright (C) 2014 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#include <stdlib.h>
18#include <string.h>
19#include <stddef.h>
20
21#include <assert.h>
22
23#include "authorization_set.h"
24
25namespace keymaster {
26
27static inline bool is_blob_tag(keymaster_tag_t tag) {
28 return (keymaster_tag_get_type(tag) == KM_BYTES || keymaster_tag_get_type(tag) == KM_BIGNUM);
29}
30
31const size_t STARTING_ELEMS_CAPACITY = 8;
32
Shawn Willden58e1a542014-08-08 21:58:29 -060033AuthorizationSet::AuthorizationSet(const AuthorizationSet& set)
34 : elems_(NULL), indirect_data_(NULL) {
35 elems_ = new keymaster_key_param_t[set.elems_size_];
36 if (elems_ == NULL) {
37 error_ = ALLOCATION_FAILURE;
38 return;
39 }
40 memcpy(elems_, set.elems_, set.elems_size_ * sizeof(keymaster_key_param_t));
41 elems_size_ = set.elems_size_;
42 elems_capacity_ = elems_size_;
43
44 if (set.indirect_data_ == NULL) {
45 indirect_data_ = NULL;
46 indirect_data_size_ = 0;
47 indirect_data_capacity_ = 0;
48 } else {
49 indirect_data_ = new uint8_t[set.indirect_data_size_];
50 if (indirect_data_ == NULL) {
51 error_ = ALLOCATION_FAILURE;
52 return;
53 }
54 memcpy(indirect_data_, set.indirect_data_, set.indirect_data_size_);
55 indirect_data_size_ = set.indirect_data_size_;
56 indirect_data_capacity_ = indirect_data_size_;
57 }
58 error_ = OK;
Shawn Willden5ada7b62014-07-29 09:44:17 -060059}
60
Shawn Willden58e1a542014-08-08 21:58:29 -060061AuthorizationSet::~AuthorizationSet() { FreeData(); }
62
Shawn Willden5ada7b62014-07-29 09:44:17 -060063bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
64 FreeData();
65
66 elems_size_ = count;
67 elems_capacity_ = count;
68 indirect_data_size_ = ComputeIndirectDataSize(elems, count);
69 indirect_data_capacity_ = indirect_data_size_;
Shawn Willden58e1a542014-08-08 21:58:29 -060070 error_ = OK;
Shawn Willden5ada7b62014-07-29 09:44:17 -060071
72 indirect_data_ = new uint8_t[indirect_data_size_];
73 elems_ = new keymaster_key_param_t[elems_size_];
74 if (indirect_data_ == NULL || elems_ == NULL) {
75 set_invalid(ALLOCATION_FAILURE);
76 return false;
77 }
Shawn Willden5ada7b62014-07-29 09:44:17 -060078
79 memcpy(elems_, elems, sizeof(keymaster_key_param_t) * elems_size_);
80 CopyIndirectData();
81 ConvertPointersToOffsets(elems_, elems_size_, indirect_data_);
82 return true;
83}
84
Shawn Willden5ada7b62014-07-29 09:44:17 -060085void AuthorizationSet::set_invalid(Error error) {
86 error_ = error;
87 FreeData();
88}
89
90int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
91 int i = ++begin;
92 for (; i < (int)elems_size_ && elems_[i].tag != tag; ++i) {
93 }
94 if (i == (int)elems_size_)
95 return -1;
96 else
97 return i;
98}
99
100keymaster_key_param_t empty;
101
102keymaster_key_param_t AuthorizationSet::operator[](int at) const {
103 if (at < (int)elems_size_) {
104 keymaster_key_param_t retval = elems_[at];
105 if (is_blob_tag(elems_[at].tag)) {
106 // Data "pointer" is actually an offset. Convert it to a pointer.
107 retval.blob.data = indirect_data_ + reinterpret_cast<ptrdiff_t>(retval.blob.data);
108 }
109 return retval;
110 }
111 memset(&empty, 0, sizeof(empty));
112 return empty;
113}
114
115bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
116 if (elems_size_ >= elems_capacity_) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600117 size_t new_capacity = elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY;
118 keymaster_key_param_t* new_elems = new keymaster_key_param_t[new_capacity];
119 if (new_elems == NULL) {
120 set_invalid(ALLOCATION_FAILURE);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600121 return false;
122 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600123 memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
124 delete[] elems_;
125 elems_ = new_elems;
126 elems_capacity_ = new_capacity;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600127 }
128
129 if (is_blob_tag(elem.tag)) {
130 if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600131 size_t new_capacity = 2 * (indirect_data_capacity_ + elem.blob.data_length);
132 uint8_t* new_data = new uint8_t[new_capacity];
133 if (new_data == false) {
134 set_invalid(ALLOCATION_FAILURE);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600135 return false;
136 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600137 memcpy(new_data, indirect_data_, indirect_data_size_);
138 delete[] indirect_data_;
139 indirect_data_ = new_data;
140 indirect_data_capacity_ = new_capacity;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600141 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600142
Shawn Willden5ada7b62014-07-29 09:44:17 -0600143 memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
144 elem.blob.data = reinterpret_cast<uint8_t*>(indirect_data_size_);
145 indirect_data_size_ += elem.blob.data_length;
146 }
147
148 elems_[elems_size_++] = elem;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600149 return true;
150}
151
Shawn Willden58e1a542014-08-08 21:58:29 -0600152size_t AuthorizationSet::SerializedSize() const {
153 return sizeof(uint32_t) + // Length of elems_
154 (sizeof(*elems_) * elems_size_) + // elems_
155 sizeof(uint32_t) + // Length of indirect data
156 indirect_data_size_; // Indirect data
157}
158
159uint8_t* AuthorizationSet::Serialize(uint8_t* serialized_set, const uint8_t* end) const {
Shawn Willden5ada7b62014-07-29 09:44:17 -0600160 serialized_set =
Shawn Willden58e1a542014-08-08 21:58:29 -0600161 append_size_and_data_to_buf(serialized_set, end, elems_, elems_size_ * sizeof(*elems_));
162 return append_size_and_data_to_buf(serialized_set, end, indirect_data_, indirect_data_size_);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600163}
164
Shawn Willden58e1a542014-08-08 21:58:29 -0600165bool AuthorizationSet::Deserialize(const uint8_t** buf, const uint8_t* end) {
Shawn Willden5ada7b62014-07-29 09:44:17 -0600166 FreeData();
167
Shawn Willden5ada7b62014-07-29 09:44:17 -0600168 uint32_t elems_buf_size;
169 if (!copy_from_buf(buf, end, &elems_buf_size) ||
170 (elems_buf_size % sizeof(keymaster_key_param_t)) != 0 || end < (*buf + elems_buf_size)) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600171 set_invalid(MALFORMED_DATA);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600172 return false;
173 }
174
175 elems_ = new keymaster_key_param_t[elems_buf_size / sizeof(keymaster_key_param_t)];
176 if (elems_ == NULL) {
177 set_invalid(ALLOCATION_FAILURE);
178 return false;
179 }
180 memcpy(elems_, *buf, elems_buf_size);
181 *buf += elems_buf_size;
182
183 uint32_t indirect_size;
184 if (!copy_from_buf(buf, end, &indirect_size) ||
185 indirect_size !=
Shawn Willden58e1a542014-08-08 21:58:29 -0600186 ComputeIndirectDataSize(elems_, elems_buf_size / sizeof(keymaster_key_param_t))) {
187 set_invalid(MALFORMED_DATA);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600188 return false;
Shawn Willden58e1a542014-08-08 21:58:29 -0600189 }
Shawn Willden5ada7b62014-07-29 09:44:17 -0600190
191 indirect_data_ = new uint8_t[indirect_size];
192 if (indirect_data_ == NULL) {
193 set_invalid(ALLOCATION_FAILURE);
194 return false;
195 }
196 memcpy(indirect_data_, *buf, indirect_size);
197 *buf += indirect_size;
198
199 elems_size_ = elems_buf_size / sizeof(keymaster_key_param_t);
200 elems_capacity_ = elems_size_;
201 indirect_data_size_ = indirect_size;
202 indirect_data_capacity_ = indirect_size;
Shawn Willden58e1a542014-08-08 21:58:29 -0600203 error_ = OK;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600204
205 return CheckIndirectDataOffsets();
206}
207
208void AuthorizationSet::FreeData() {
Shawn Willden58e1a542014-08-08 21:58:29 -0600209 if (elems_ != NULL)
210 memset(elems_, 0, elems_size_ * sizeof(keymaster_key_param_t));
211 if (indirect_data_ != NULL)
212 memset(indirect_data_, 0, indirect_data_size_);
213
214 delete[] elems_;
215 delete[] indirect_data_;
216
Shawn Willden5ada7b62014-07-29 09:44:17 -0600217 elems_ = NULL;
218 indirect_data_ = NULL;
219 elems_size_ = 0;
220 elems_capacity_ = 0;
221 indirect_data_size_ = 0;
222 indirect_data_capacity_ = 0;
223}
224
225/* static */
226size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
227 size_t size = 0;
228 for (size_t i = 0; i < count; ++i) {
229 if (is_blob_tag(elems[i].tag)) {
230 size += elems[i].blob.data_length;
231 }
232 }
233 return size;
234}
235
236void AuthorizationSet::CopyIndirectData() {
237 memset(indirect_data_, 0, indirect_data_size_);
238
239 uint8_t* indirect_data_pos = indirect_data_;
240 for (size_t i = 0; i < elems_size_; ++i) {
241 assert(indirect_data_pos <= indirect_data_ + indirect_data_size_);
242 if (is_blob_tag(elems_[i].tag)) {
243 memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
244 elems_[i].blob.data = indirect_data_pos;
245 indirect_data_pos += elems_[i].blob.data_length;
246 }
247 }
248 assert(indirect_data_pos == indirect_data_ + indirect_data_size_);
249}
250
251/* static */
252void AuthorizationSet::ConvertPointersToOffsets(keymaster_key_param_t* elems, size_t count,
253 const uint8_t* indirect_base) {
254 for (size_t i = 0; i < count; ++i) {
255 if (is_blob_tag(elems[i].tag)) {
256 elems[i].blob.data = reinterpret_cast<uint8_t*>(elems[i].blob.data - indirect_base);
257 }
258 }
259}
260
261bool AuthorizationSet::CheckIndirectDataOffsets() {
262 // TODO(swillden): Find an efficient way to test for overlaps. Verifying that the total size of
263 // the indirect blobs found matches the size of the indirect data buffer and that all of the
264 // offsets fall into the correct region precludes most sorts of indirect data table
265 // malformation, but it doesn't prevent overlaps which are accompanied by unused regions whose
266 // total size exactly offsets the overlaps.
267 size_t computed_indirect_data_size = 0;
268
269 for (size_t i = 0; i < elems_size_; ++i) {
270 if (is_blob_tag(elems_[i].tag)) {
271 computed_indirect_data_size += elems_[i].blob.data_length;
272 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(elems_[i].blob.data);
273 if (offset < 0 || offset > (ptrdiff_t)indirect_data_size_ ||
274 offset + elems_[i].blob.data_length > indirect_data_size_) {
275 set_invalid(BOUNDS_CHECKING_FAILURE);
276 return false;
277 }
278 }
279 }
280
281 if (computed_indirect_data_size != indirect_data_size_) {
282 set_invalid(MALFORMED_DATA);
283 return false;
284 }
285
286 return true;
287}
288
289bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
290 int pos = find(tag);
291 if (pos == -1) {
292 return false;
293 }
294 *val = (*this)[pos].enumerated;
295 return true;
296}
297
298bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
299 uint32_t* val) const {
300 size_t count = 0;
301 int pos = -1;
302 while (count <= instance) {
303 pos = find(tag, pos);
304 if (pos == -1) {
305 return false;
306 }
307 ++count;
308 }
309 *val = (*this)[pos].enumerated;
310 return true;
311}
312
313bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
314 int pos = find(tag);
315 if (pos == -1) {
316 return false;
317 }
318 *val = (*this)[pos].integer;
319 return true;
320}
321
322bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
323 uint32_t* val) const {
324 size_t count = 0;
325 int pos = -1;
326 while (count <= instance) {
327 pos = find(tag, pos);
328 if (pos == -1) {
329 return false;
330 }
331 ++count;
332 }
333 *val = (*this)[pos].integer;
334 return true;
335}
336
337bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
338 int pos = find(tag);
339 if (pos == -1) {
340 return false;
341 }
342 *val = (*this)[pos].long_integer;
343 return true;
344}
345
346bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
347 int pos = find(tag);
348 if (pos == -1) {
349 return false;
350 }
351 *val = (*this)[pos].date_time;
352 return true;
353}
354
355bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
356 int pos = find(tag);
357 if (pos == -1) {
358 return false;
359 }
360 *val = (*this)[pos].blob;
361 return true;
362}
363
364} // namespace keymaster