blob: 94a69e8e5330e92901ef66ca7b99d0f48ac1f852 [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
33AuthorizationSet::~AuthorizationSet() {
34 FreeData();
35}
36
37bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
38 FreeData();
39
40 elems_size_ = count;
41 elems_capacity_ = count;
42 indirect_data_size_ = ComputeIndirectDataSize(elems, count);
43 indirect_data_capacity_ = indirect_data_size_;
44 error_ = OK_GROWABLE;
45
46 indirect_data_ = new uint8_t[indirect_data_size_];
47 elems_ = new keymaster_key_param_t[elems_size_];
48 if (indirect_data_ == NULL || elems_ == NULL) {
49 set_invalid(ALLOCATION_FAILURE);
50 return false;
51 }
52 owns_data_ = true;
53
54 memcpy(elems_, elems, sizeof(keymaster_key_param_t) * elems_size_);
55 CopyIndirectData();
56 ConvertPointersToOffsets(elems_, elems_size_, indirect_data_);
57 return true;
58}
59
60AuthorizationSet::AuthorizationSet(uint8_t* serialized_set, size_t length) : owns_data_(false) {
61 if (!DeserializeInPlace(&serialized_set, serialized_set + length))
62 set_invalid(MALFORMED_DATA);
63}
64
65void AuthorizationSet::Reinitialize(keymaster_key_param_t* elems_array, size_t elems_buf_count,
66 uint8_t* indirect_data_buf, size_t indirect_data_buf_size) {
67 FreeData();
68
69 elems_ = elems_array;
70 elems_size_ = 0;
71 elems_capacity_ = elems_buf_count;
72 indirect_data_ = indirect_data_buf;
73 indirect_data_size_ = 0;
74 indirect_data_capacity_ = indirect_data_buf_size;
75 owns_data_ = false;
76
77 if (CheckIndirectDataOffsets()) {
78 error_ = OK_GROWABLE;
79 }
80}
81
82void AuthorizationSet::set_invalid(Error error) {
83 error_ = error;
84 FreeData();
85}
86
87int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
88 int i = ++begin;
89 for (; i < (int)elems_size_ && elems_[i].tag != tag; ++i) {
90 }
91 if (i == (int)elems_size_)
92 return -1;
93 else
94 return i;
95}
96
97keymaster_key_param_t empty;
98
99keymaster_key_param_t AuthorizationSet::operator[](int at) const {
100 if (at < (int)elems_size_) {
101 keymaster_key_param_t retval = elems_[at];
102 if (is_blob_tag(elems_[at].tag)) {
103 // Data "pointer" is actually an offset. Convert it to a pointer.
104 retval.blob.data = indirect_data_ + reinterpret_cast<ptrdiff_t>(retval.blob.data);
105 }
106 return retval;
107 }
108 memset(&empty, 0, sizeof(empty));
109 return empty;
110}
111
112bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
113 if (elems_size_ >= elems_capacity_) {
114 if (owns_data_) {
115 size_t new_capacity = elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY;
116 keymaster_key_param_t* new_elems = new keymaster_key_param_t[new_capacity];
117 if (new_elems == NULL) {
118 set_invalid(ALLOCATION_FAILURE);
119 return false;
120 }
121 memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
122 delete[] elems_;
123 elems_ = new_elems;
124 elems_capacity_ = new_capacity;
125 } else {
126 return false;
127 }
128 }
129
130 if (is_blob_tag(elem.tag)) {
131 if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length) {
132 if (owns_data_) {
133 size_t new_capacity = 2 * (indirect_data_capacity_ + elem.blob.data_length);
134 uint8_t* new_data = new uint8_t[new_capacity];
135 if (new_data == false) {
136 set_invalid(ALLOCATION_FAILURE);
137 return false;
138 }
139 memcpy(new_data, indirect_data_, indirect_data_size_);
140 delete[] indirect_data_;
141 indirect_data_ = new_data;
142 indirect_data_capacity_ = new_capacity;
143 } else {
144 return false;
145 }
146 }
147 memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
148 elem.blob.data = reinterpret_cast<uint8_t*>(indirect_data_size_);
149 indirect_data_size_ += elem.blob.data_length;
150 }
151
152 elems_[elems_size_++] = elem;
153
154 if (elems_size_ == elems_capacity_ && !owns_data_) {
155 error_ = OK_FULL;
156 }
157 return true;
158}
159
160uint8_t* AuthorizationSet::Serialize(uint8_t* serialized_set) const {
161 serialized_set =
162 append_size_and_data_to_buf(serialized_set, elems_, elems_size_ * sizeof(*elems_));
163 return append_size_and_data_to_buf(serialized_set, indirect_data_, indirect_data_size_);
164}
165
166bool AuthorizationSet::DeserializeInPlace(uint8_t** buf, const uint8_t* end) {
167 uint32_t elems_buf_size;
168 if (!copy_from_buf(buf, end, &elems_buf_size) ||
169 (elems_buf_size % sizeof(keymaster_key_param_t)) != 0 || end < (*buf + elems_buf_size)) {
170 return false;
171 }
172
173 keymaster_key_param_t* elems = reinterpret_cast<keymaster_key_param_t*>(*buf);
174 *buf += elems_buf_size;
175
176 uint32_t indirect_size;
177 if (!copy_from_buf(buf, end, &indirect_size) ||
178 indirect_size !=
179 ComputeIndirectDataSize(elems, elems_buf_size / sizeof(keymaster_key_param_t)))
180 return false;
181
182 uint8_t* indirect_data = *buf;
183 *buf += indirect_size;
184
185 FreeData();
186
187 owns_data_ = false;
188 elems_ = elems;
189 elems_size_ = elems_buf_size / sizeof(keymaster_key_param_t);
190 elems_capacity_ = elems_size_;
191 indirect_data_ = indirect_data;
192 indirect_data_size_ = indirect_size;
193 indirect_data_capacity_ = indirect_size;
194
195 if (CheckIndirectDataOffsets()) {
196 error_ = OK_FULL;
197 return true;
198 }
199 return false;
200}
201
202bool AuthorizationSet::DeserializeToCopy(const uint8_t** buf, const uint8_t* end) {
203 FreeData();
204 owns_data_ = true;
205
206 uint32_t elems_buf_size;
207 if (!copy_from_buf(buf, end, &elems_buf_size) ||
208 (elems_buf_size % sizeof(keymaster_key_param_t)) != 0 || end < (*buf + elems_buf_size)) {
209 return false;
210 }
211
212 elems_ = new keymaster_key_param_t[elems_buf_size / sizeof(keymaster_key_param_t)];
213 if (elems_ == NULL) {
214 set_invalid(ALLOCATION_FAILURE);
215 return false;
216 }
217 memcpy(elems_, *buf, elems_buf_size);
218 *buf += elems_buf_size;
219
220 uint32_t indirect_size;
221 if (!copy_from_buf(buf, end, &indirect_size) ||
222 indirect_size !=
223 ComputeIndirectDataSize(elems_, elems_buf_size / sizeof(keymaster_key_param_t)))
224 return false;
225
226 indirect_data_ = new uint8_t[indirect_size];
227 if (indirect_data_ == NULL) {
228 set_invalid(ALLOCATION_FAILURE);
229 return false;
230 }
231 memcpy(indirect_data_, *buf, indirect_size);
232 *buf += indirect_size;
233
234 elems_size_ = elems_buf_size / sizeof(keymaster_key_param_t);
235 elems_capacity_ = elems_size_;
236 indirect_data_size_ = indirect_size;
237 indirect_data_capacity_ = indirect_size;
238 owns_data_ = true;
239 error_ = OK_GROWABLE;
240
241 return CheckIndirectDataOffsets();
242}
243
244void AuthorizationSet::FreeData() {
245 if (owns_data_) {
246 delete[] elems_;
247 delete[] indirect_data_;
248 }
249 elems_ = NULL;
250 indirect_data_ = NULL;
251 elems_size_ = 0;
252 elems_capacity_ = 0;
253 indirect_data_size_ = 0;
254 indirect_data_capacity_ = 0;
255}
256
257/* static */
258size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
259 size_t size = 0;
260 for (size_t i = 0; i < count; ++i) {
261 if (is_blob_tag(elems[i].tag)) {
262 size += elems[i].blob.data_length;
263 }
264 }
265 return size;
266}
267
268void AuthorizationSet::CopyIndirectData() {
269 memset(indirect_data_, 0, indirect_data_size_);
270
271 uint8_t* indirect_data_pos = indirect_data_;
272 for (size_t i = 0; i < elems_size_; ++i) {
273 assert(indirect_data_pos <= indirect_data_ + indirect_data_size_);
274 if (is_blob_tag(elems_[i].tag)) {
275 memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
276 elems_[i].blob.data = indirect_data_pos;
277 indirect_data_pos += elems_[i].blob.data_length;
278 }
279 }
280 assert(indirect_data_pos == indirect_data_ + indirect_data_size_);
281}
282
283/* static */
284void AuthorizationSet::ConvertPointersToOffsets(keymaster_key_param_t* elems, size_t count,
285 const uint8_t* indirect_base) {
286 for (size_t i = 0; i < count; ++i) {
287 if (is_blob_tag(elems[i].tag)) {
288 elems[i].blob.data = reinterpret_cast<uint8_t*>(elems[i].blob.data - indirect_base);
289 }
290 }
291}
292
293bool AuthorizationSet::CheckIndirectDataOffsets() {
294 // TODO(swillden): Find an efficient way to test for overlaps. Verifying that the total size of
295 // the indirect blobs found matches the size of the indirect data buffer and that all of the
296 // offsets fall into the correct region precludes most sorts of indirect data table
297 // malformation, but it doesn't prevent overlaps which are accompanied by unused regions whose
298 // total size exactly offsets the overlaps.
299 size_t computed_indirect_data_size = 0;
300
301 for (size_t i = 0; i < elems_size_; ++i) {
302 if (is_blob_tag(elems_[i].tag)) {
303 computed_indirect_data_size += elems_[i].blob.data_length;
304 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(elems_[i].blob.data);
305 if (offset < 0 || offset > (ptrdiff_t)indirect_data_size_ ||
306 offset + elems_[i].blob.data_length > indirect_data_size_) {
307 set_invalid(BOUNDS_CHECKING_FAILURE);
308 return false;
309 }
310 }
311 }
312
313 if (computed_indirect_data_size != indirect_data_size_) {
314 set_invalid(MALFORMED_DATA);
315 return false;
316 }
317
318 return true;
319}
320
321bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
322 int pos = find(tag);
323 if (pos == -1) {
324 return false;
325 }
326 *val = (*this)[pos].enumerated;
327 return true;
328}
329
330bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
331 uint32_t* val) const {
332 size_t count = 0;
333 int pos = -1;
334 while (count <= instance) {
335 pos = find(tag, pos);
336 if (pos == -1) {
337 return false;
338 }
339 ++count;
340 }
341 *val = (*this)[pos].enumerated;
342 return true;
343}
344
345bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
346 int pos = find(tag);
347 if (pos == -1) {
348 return false;
349 }
350 *val = (*this)[pos].integer;
351 return true;
352}
353
354bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
355 uint32_t* val) const {
356 size_t count = 0;
357 int pos = -1;
358 while (count <= instance) {
359 pos = find(tag, pos);
360 if (pos == -1) {
361 return false;
362 }
363 ++count;
364 }
365 *val = (*this)[pos].integer;
366 return true;
367}
368
369bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
370 int pos = find(tag);
371 if (pos == -1) {
372 return false;
373 }
374 *val = (*this)[pos].long_integer;
375 return true;
376}
377
378bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
379 int pos = find(tag);
380 if (pos == -1) {
381 return false;
382 }
383 *val = (*this)[pos].date_time;
384 return true;
385}
386
387bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
388 int pos = find(tag);
389 if (pos == -1) {
390 return false;
391 }
392 *val = (*this)[pos].blob;
393 return true;
394}
395
396} // namespace keymaster