blob: a0ca5717bf1da62f26e5f7dc701578aa49738e31 [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"
Shawn Willden74aff352014-08-11 14:08:31 -060024#include "google_keymaster_utils.h"
Shawn Willden5ada7b62014-07-29 09:44:17 -060025
26namespace keymaster {
27
28static inline bool is_blob_tag(keymaster_tag_t tag) {
29 return (keymaster_tag_get_type(tag) == KM_BYTES || keymaster_tag_get_type(tag) == KM_BIGNUM);
30}
31
32const size_t STARTING_ELEMS_CAPACITY = 8;
33
Shawn Willden58e1a542014-08-08 21:58:29 -060034AuthorizationSet::AuthorizationSet(const AuthorizationSet& set)
35 : elems_(NULL), indirect_data_(NULL) {
Shawn Willden76364712014-08-11 17:48:04 -060036 Reinitialize(set.elems_, set.elems_size_);
Shawn Willden5ada7b62014-07-29 09:44:17 -060037}
38
Shawn Willden8d336ae2014-08-09 15:47:05 -060039AuthorizationSet::~AuthorizationSet() {
40 FreeData();
41}
Shawn Willden58e1a542014-08-08 21:58:29 -060042
Shawn Willden5ada7b62014-07-29 09:44:17 -060043bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
44 FreeData();
45
46 elems_size_ = count;
47 elems_capacity_ = count;
48 indirect_data_size_ = ComputeIndirectDataSize(elems, count);
49 indirect_data_capacity_ = indirect_data_size_;
Shawn Willden58e1a542014-08-08 21:58:29 -060050 error_ = OK;
Shawn Willden5ada7b62014-07-29 09:44:17 -060051
52 indirect_data_ = new uint8_t[indirect_data_size_];
53 elems_ = new keymaster_key_param_t[elems_size_];
54 if (indirect_data_ == NULL || elems_ == NULL) {
55 set_invalid(ALLOCATION_FAILURE);
56 return false;
57 }
Shawn Willden5ada7b62014-07-29 09:44:17 -060058
59 memcpy(elems_, elems, sizeof(keymaster_key_param_t) * elems_size_);
60 CopyIndirectData();
Shawn Willden5ada7b62014-07-29 09:44:17 -060061 return true;
62}
63
Shawn Willden5ada7b62014-07-29 09:44:17 -060064void AuthorizationSet::set_invalid(Error error) {
65 error_ = error;
66 FreeData();
67}
68
69int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
70 int i = ++begin;
Shawn Willden8d336ae2014-08-09 15:47:05 -060071 while (i < (int)elems_size_ && elems_[i].tag != tag)
72 ++i;
Shawn Willden5ada7b62014-07-29 09:44:17 -060073 if (i == (int)elems_size_)
74 return -1;
75 else
76 return i;
77}
78
79keymaster_key_param_t empty;
Shawn Willden5ada7b62014-07-29 09:44:17 -060080keymaster_key_param_t AuthorizationSet::operator[](int at) const {
81 if (at < (int)elems_size_) {
Shawn Willden8d336ae2014-08-09 15:47:05 -060082 return elems_[at];
Shawn Willden5ada7b62014-07-29 09:44:17 -060083 }
84 memset(&empty, 0, sizeof(empty));
85 return empty;
86}
87
Shawn Willden76364712014-08-11 17:48:04 -060088template <typename T> int comparator(const T& a, const T& b) {
89 if (a < b)
90 return -1;
91 else if (a > b)
92 return 1;
93 else
94 return 0;
95}
96
97static int param_comparator(const void* a, const void* b) {
98 const keymaster_key_param_t* lhs = static_cast<const keymaster_key_param_t*>(a);
99 const keymaster_key_param_t* rhs = static_cast<const keymaster_key_param_t*>(b);
100
101 if (lhs->tag < rhs->tag)
102 return -1;
103 else if (lhs->tag > rhs->tag)
104 return 1;
105 else
106 switch (keymaster_tag_get_type(lhs->tag)) {
107 default:
108 case KM_INVALID:
109 return 0;
110 case KM_ENUM:
111 case KM_ENUM_REP:
112 return comparator(lhs->enumerated, rhs->enumerated);
113 case KM_INT:
114 case KM_INT_REP:
115 return comparator(lhs->integer, rhs->integer);
116 case KM_LONG:
117 return comparator(lhs->long_integer, rhs->long_integer);
118 case KM_DATE:
119 return comparator(lhs->date_time, rhs->date_time);
120 case KM_BOOL:
121 return comparator(lhs->boolean, rhs->boolean);
122 case KM_BIGNUM:
123 case KM_BYTES: {
124 size_t min_len = lhs->blob.data_length;
125 if (rhs->blob.data_length < min_len)
126 min_len = rhs->blob.data_length;
127
128 if (lhs->blob.data_length == rhs->blob.data_length && min_len > 0)
129 return memcmp(lhs->blob.data, rhs->blob.data, min_len);
130 int cmp_result = memcmp(lhs->blob.data, rhs->blob.data, min_len);
131 if (cmp_result == 0) {
132 // The blobs are equal up to the length of the shortest (which may have length 0),
133 // so the shorter is less, the longer is greater and if they have the same length
134 // they're identical.
135 return comparator(lhs->blob.data_length, rhs->blob.data_length);
136 }
137 return cmp_result;
138 } break;
139 }
140}
141
Shawn Willden5ada7b62014-07-29 09:44:17 -0600142bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
143 if (elems_size_ >= elems_capacity_) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600144 size_t new_capacity = elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY;
145 keymaster_key_param_t* new_elems = new keymaster_key_param_t[new_capacity];
146 if (new_elems == NULL) {
147 set_invalid(ALLOCATION_FAILURE);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600148 return false;
149 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600150 memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
151 delete[] elems_;
152 elems_ = new_elems;
153 elems_capacity_ = new_capacity;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600154 }
155
156 if (is_blob_tag(elem.tag)) {
157 if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600158 size_t new_capacity = 2 * (indirect_data_capacity_ + elem.blob.data_length);
159 uint8_t* new_data = new uint8_t[new_capacity];
Shawn Willdenebf627f2014-08-12 11:15:29 -0600160 if (new_data == NULL) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600161 set_invalid(ALLOCATION_FAILURE);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600162 return false;
163 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600164 memcpy(new_data, indirect_data_, indirect_data_size_);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600165 // Fix up the data pointers to point into the new region.
166 for (size_t i = 0; i < elems_size_; ++i) {
167 if (is_blob_tag(elems_[i].tag))
168 elems_[i].blob.data = new_data + (elems_[i].blob.data - indirect_data_);
169 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600170 delete[] indirect_data_;
171 indirect_data_ = new_data;
172 indirect_data_capacity_ = new_capacity;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600173 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600174
Shawn Willden5ada7b62014-07-29 09:44:17 -0600175 memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600176 elem.blob.data = indirect_data_ + indirect_data_size_;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600177 indirect_data_size_ += elem.blob.data_length;
178 }
179
180 elems_[elems_size_++] = elem;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600181 return true;
182}
183
Shawn Willden8d336ae2014-08-09 15:47:05 -0600184static size_t serialized_size(const keymaster_key_param_t& param) {
185 switch (keymaster_tag_get_type(param.tag)) {
186 case KM_INVALID:
187 default:
188 return sizeof(uint32_t);
189 case KM_ENUM:
190 case KM_ENUM_REP:
191 case KM_INT:
192 case KM_INT_REP:
193 return sizeof(uint32_t) * 2;
194 case KM_LONG:
195 case KM_DATE:
196 return sizeof(uint32_t) + sizeof(uint64_t);
197 case KM_BOOL:
198 return sizeof(uint32_t) + 1;
199 break;
200 case KM_BIGNUM:
201 case KM_BYTES:
202 return sizeof(uint32_t) * 3;
203 }
Shawn Willden58e1a542014-08-08 21:58:29 -0600204}
205
Shawn Willden8d336ae2014-08-09 15:47:05 -0600206static uint8_t* serialize(const keymaster_key_param_t& param, uint8_t* buf, const uint8_t* end,
207 const uint8_t* indirect_base) {
Shawn Willden172f8c92014-08-17 07:50:34 -0600208 buf = append_uint32_to_buf(buf, end, param.tag);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600209 switch (keymaster_tag_get_type(param.tag)) {
210 case KM_INVALID:
211 break;
212 case KM_ENUM:
213 case KM_ENUM_REP:
Shawn Willden172f8c92014-08-17 07:50:34 -0600214 buf = append_uint32_to_buf(buf, end, param.enumerated);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600215 break;
216 case KM_INT:
217 case KM_INT_REP:
Shawn Willden172f8c92014-08-17 07:50:34 -0600218 buf = append_uint32_to_buf(buf, end, param.integer);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600219 break;
220 case KM_LONG:
Shawn Willden172f8c92014-08-17 07:50:34 -0600221 buf = append_uint64_to_buf(buf, end, param.long_integer);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600222 break;
223 case KM_DATE:
Shawn Willden172f8c92014-08-17 07:50:34 -0600224 buf = append_uint64_to_buf(buf, end, param.date_time);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600225 break;
226 case KM_BOOL:
227 if (buf < end)
228 *buf = static_cast<uint8_t>(param.boolean);
229 buf++;
230 break;
231 case KM_BIGNUM:
232 case KM_BYTES:
Shawn Willden172f8c92014-08-17 07:50:34 -0600233 buf = append_uint32_to_buf(buf, end, param.blob.data_length);
234 buf = append_uint32_to_buf(buf, end, param.blob.data - indirect_base);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600235 break;
236 }
237 return buf;
238}
239
Shawn Willden172f8c92014-08-17 07:50:34 -0600240static bool deserialize(keymaster_key_param_t* param, const uint8_t** buf_ptr, const uint8_t* end,
Shawn Willden8d336ae2014-08-09 15:47:05 -0600241 const uint8_t* indirect_base, const uint8_t* indirect_end) {
Shawn Willden172f8c92014-08-17 07:50:34 -0600242 if (!copy_uint32_from_buf(buf_ptr, end, &param->tag))
Shawn Willden8d336ae2014-08-09 15:47:05 -0600243 return false;
Shawn Willden8d336ae2014-08-09 15:47:05 -0600244
245 switch (keymaster_tag_get_type(param->tag)) {
246 default:
247 case KM_INVALID:
248 return false;
249 case KM_ENUM:
250 case KM_ENUM_REP:
Shawn Willden172f8c92014-08-17 07:50:34 -0600251 return copy_uint32_from_buf(buf_ptr, end, &param->enumerated);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600252 case KM_INT:
253 case KM_INT_REP:
Shawn Willden172f8c92014-08-17 07:50:34 -0600254 return copy_uint32_from_buf(buf_ptr, end, &param->integer);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600255 case KM_LONG:
Shawn Willden172f8c92014-08-17 07:50:34 -0600256 return copy_uint64_from_buf(buf_ptr, end, &param->long_integer);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600257 case KM_DATE:
Shawn Willden172f8c92014-08-17 07:50:34 -0600258 return copy_uint64_from_buf(buf_ptr, end, &param->date_time);
Shawn Willden8d336ae2014-08-09 15:47:05 -0600259 break;
260 case KM_BOOL:
Shawn Willden172f8c92014-08-17 07:50:34 -0600261 if (*buf_ptr < end) {
262 param->boolean = static_cast<bool>(**buf_ptr);
263 (*buf_ptr)++;
Shawn Willden8d336ae2014-08-09 15:47:05 -0600264 return true;
265 }
266 return false;
267
268 case KM_BIGNUM:
269 case KM_BYTES: {
Shawn Willden8d336ae2014-08-09 15:47:05 -0600270 uint32_t offset;
Shawn Willden172f8c92014-08-17 07:50:34 -0600271 if (!copy_uint32_from_buf(buf_ptr, end, &param->blob.data_length) ||
272 !copy_uint32_from_buf(buf_ptr, end, &offset))
Shawn Willden8d336ae2014-08-09 15:47:05 -0600273 return false;
274 if (static_cast<ptrdiff_t>(offset) > indirect_end - indirect_base ||
Shawn Willden172f8c92014-08-17 07:50:34 -0600275 static_cast<ptrdiff_t>(offset + param->blob.data_length) > indirect_end - indirect_base)
Shawn Willden8d336ae2014-08-09 15:47:05 -0600276 return false;
Shawn Willden8d336ae2014-08-09 15:47:05 -0600277 param->blob.data = indirect_base + offset;
278 return true;
279 }
280 }
281}
282
283size_t AuthorizationSet::SerializedSizeOfElements() const {
284 size_t size = 0;
285 for (size_t i = 0; i < elems_size_; ++i) {
286 size += serialized_size(elems_[i]);
287 }
288 return size;
289}
290
291size_t AuthorizationSet::SerializedSize() const {
292 return sizeof(uint32_t) + // Size of indirect_data_
293 indirect_data_size_ + // indirect_data_
294 sizeof(uint32_t) + // Number of elems_
295 sizeof(uint32_t) + // Size of elems_
296 SerializedSizeOfElements(); // elems_
297}
298
299uint8_t* AuthorizationSet::Serialize(uint8_t* buf, const uint8_t* end) const {
300 buf = append_size_and_data_to_buf(buf, end, indirect_data_, indirect_data_size_);
Shawn Willden172f8c92014-08-17 07:50:34 -0600301 buf = append_uint32_to_buf(buf, end, elems_size_);
302 buf = append_uint32_to_buf(buf, end, SerializedSizeOfElements());
Shawn Willden8d336ae2014-08-09 15:47:05 -0600303 for (size_t i = 0; i < elems_size_; ++i) {
304 buf = serialize(elems_[i], buf, end, indirect_data_);
305 }
306 return buf;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600307}
308
Shawn Willden172f8c92014-08-17 07:50:34 -0600309bool AuthorizationSet::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
Shawn Willden5ada7b62014-07-29 09:44:17 -0600310 FreeData();
311
Shawn Willden8d336ae2014-08-09 15:47:05 -0600312 uint32_t elements_count;
313 uint32_t elements_size;
Shawn Willden172f8c92014-08-17 07:50:34 -0600314 if (!copy_size_and_data_from_buf(buf_ptr, end, &indirect_data_size_, &indirect_data_) ||
315 !copy_uint32_from_buf(buf_ptr, end, &elements_count) ||
316 !copy_uint32_from_buf(buf_ptr, end, &elements_size)) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600317 set_invalid(MALFORMED_DATA);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600318 return false;
319 }
320
Shawn Willden834e8072014-08-09 16:38:53 -0600321 // Note that the following validation of elements_count is weak, but it prevents allocation of
322 // elems_ arrays which are clearly too large to be reasonable.
Shawn Willden172f8c92014-08-17 07:50:34 -0600323 if (elements_size > end - *buf_ptr || elements_count * sizeof(uint32_t) > elements_size) {
Shawn Willden834e8072014-08-09 16:38:53 -0600324 set_invalid(MALFORMED_DATA);
325 return false;
326 }
327
Shawn Willden8d336ae2014-08-09 15:47:05 -0600328 elems_ = new keymaster_key_param_t[elements_count];
Shawn Willden5ada7b62014-07-29 09:44:17 -0600329 if (elems_ == NULL) {
330 set_invalid(ALLOCATION_FAILURE);
331 return false;
332 }
Shawn Willden5ada7b62014-07-29 09:44:17 -0600333
Shawn Willden8d336ae2014-08-09 15:47:05 -0600334 uint8_t* indirect_end = indirect_data_ + indirect_data_size_;
Shawn Willden172f8c92014-08-17 07:50:34 -0600335 const uint8_t* elements_end = *buf_ptr + elements_size;
Shawn Willden8d336ae2014-08-09 15:47:05 -0600336 for (size_t i = 0; i < elements_count; ++i) {
Shawn Willden172f8c92014-08-17 07:50:34 -0600337 if (!deserialize(elems_ + i, buf_ptr, elements_end, indirect_data_, indirect_end)) {
Shawn Willden8d336ae2014-08-09 15:47:05 -0600338 set_invalid(MALFORMED_DATA);
339 return false;
340 }
341 }
342
343 if (indirect_data_size_ != ComputeIndirectDataSize(elems_, elements_count)) {
Shawn Willden58e1a542014-08-08 21:58:29 -0600344 set_invalid(MALFORMED_DATA);
Shawn Willden5ada7b62014-07-29 09:44:17 -0600345 return false;
Shawn Willden58e1a542014-08-08 21:58:29 -0600346 }
Shawn Willden5ada7b62014-07-29 09:44:17 -0600347
Shawn Willden8d336ae2014-08-09 15:47:05 -0600348 elems_size_ = elements_count;
349 elems_capacity_ = elements_count;
350 indirect_data_capacity_ = indirect_data_size_;
Shawn Willden58e1a542014-08-08 21:58:29 -0600351 error_ = OK;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600352
Shawn Willden8d336ae2014-08-09 15:47:05 -0600353 return true;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600354}
355
356void AuthorizationSet::FreeData() {
Shawn Willden58e1a542014-08-08 21:58:29 -0600357 if (elems_ != NULL)
Shawn Willden74aff352014-08-11 14:08:31 -0600358 memset_s(elems_, 0, elems_size_ * sizeof(keymaster_key_param_t));
Shawn Willden58e1a542014-08-08 21:58:29 -0600359 if (indirect_data_ != NULL)
Shawn Willden74aff352014-08-11 14:08:31 -0600360 memset_s(indirect_data_, 0, indirect_data_size_);
Shawn Willden58e1a542014-08-08 21:58:29 -0600361
362 delete[] elems_;
363 delete[] indirect_data_;
364
Shawn Willden5ada7b62014-07-29 09:44:17 -0600365 elems_ = NULL;
366 indirect_data_ = NULL;
367 elems_size_ = 0;
368 elems_capacity_ = 0;
369 indirect_data_size_ = 0;
370 indirect_data_capacity_ = 0;
371}
372
373/* static */
374size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
375 size_t size = 0;
376 for (size_t i = 0; i < count; ++i) {
377 if (is_blob_tag(elems[i].tag)) {
378 size += elems[i].blob.data_length;
379 }
380 }
381 return size;
382}
383
384void AuthorizationSet::CopyIndirectData() {
385 memset(indirect_data_, 0, indirect_data_size_);
386
387 uint8_t* indirect_data_pos = indirect_data_;
388 for (size_t i = 0; i < elems_size_; ++i) {
389 assert(indirect_data_pos <= indirect_data_ + indirect_data_size_);
390 if (is_blob_tag(elems_[i].tag)) {
391 memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
392 elems_[i].blob.data = indirect_data_pos;
393 indirect_data_pos += elems_[i].blob.data_length;
394 }
395 }
396 assert(indirect_data_pos == indirect_data_ + indirect_data_size_);
397}
398
Shawn Willden5ada7b62014-07-29 09:44:17 -0600399bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
400 int pos = find(tag);
401 if (pos == -1) {
402 return false;
403 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600404 *val = elems_[pos].enumerated;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600405 return true;
406}
407
408bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
409 uint32_t* val) const {
410 size_t count = 0;
411 int pos = -1;
412 while (count <= instance) {
413 pos = find(tag, pos);
414 if (pos == -1) {
415 return false;
416 }
417 ++count;
418 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600419 *val = elems_[pos].enumerated;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600420 return true;
421}
422
423bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
424 int pos = find(tag);
425 if (pos == -1) {
426 return false;
427 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600428 *val = elems_[pos].integer;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600429 return true;
430}
431
432bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
433 uint32_t* val) const {
434 size_t count = 0;
435 int pos = -1;
436 while (count <= instance) {
437 pos = find(tag, pos);
438 if (pos == -1) {
439 return false;
440 }
441 ++count;
442 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600443 *val = elems_[pos].integer;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600444 return true;
445}
446
447bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
448 int pos = find(tag);
449 if (pos == -1) {
450 return false;
451 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600452 *val = elems_[pos].long_integer;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600453 return true;
454}
455
456bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
457 int pos = find(tag);
458 if (pos == -1) {
459 return false;
460 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600461 *val = elems_[pos].date_time;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600462 return true;
463}
464
465bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
466 int pos = find(tag);
467 if (pos == -1) {
468 return false;
469 }
Shawn Willdenebf627f2014-08-12 11:15:29 -0600470 *val = elems_[pos].blob;
Shawn Willden5ada7b62014-07-29 09:44:17 -0600471 return true;
472}
473
474} // namespace keymaster