123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- /*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <keymaster/authorization_set.h>
- #include <assert.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <keymaster/new>
- #include <keymaster/android_keymaster_utils.h>
- #include <keymaster/logger.h>
- namespace keymaster {
- static inline bool is_blob_tag(keymaster_tag_t tag) {
- return (keymaster_tag_get_type(tag) == KM_BYTES || keymaster_tag_get_type(tag) == KM_BIGNUM);
- }
- const size_t STARTING_ELEMS_CAPACITY = 8;
- AuthorizationSet::AuthorizationSet(AuthorizationSetBuilder& builder) {
- elems_ = builder.set.elems_;
- builder.set.elems_ = nullptr;
- elems_size_ = builder.set.elems_size_;
- builder.set.elems_size_ = 0;
- elems_capacity_ = builder.set.elems_capacity_;
- builder.set.elems_capacity_ = 0;
- indirect_data_ = builder.set.indirect_data_;
- builder.set.indirect_data_ = nullptr;
- indirect_data_capacity_ = builder.set.indirect_data_capacity_;
- builder.set.indirect_data_capacity_ = 0;
- indirect_data_size_ = builder.set.indirect_data_size_;
- builder.set.indirect_data_size_ = 0;
- error_ = builder.set.error_;
- builder.set.error_ = OK;
- }
- AuthorizationSet::~AuthorizationSet() {
- FreeData();
- }
- bool AuthorizationSet::reserve_elems(size_t count) {
- if (is_valid() != OK)
- return false;
- if (count > elems_capacity_) {
- keymaster_key_param_t* new_elems = new (std::nothrow) keymaster_key_param_t[count];
- if (new_elems == nullptr) {
- set_invalid(ALLOCATION_FAILURE);
- return false;
- }
- memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
- delete[] elems_;
- elems_ = new_elems;
- elems_capacity_ = count;
- }
- return true;
- }
- bool AuthorizationSet::reserve_indirect(size_t length) {
- if (is_valid() != OK)
- return false;
- if (length > indirect_data_capacity_) {
- uint8_t* new_data = new (std::nothrow) uint8_t[length];
- if (new_data == nullptr) {
- set_invalid(ALLOCATION_FAILURE);
- return false;
- }
- memcpy(new_data, indirect_data_, indirect_data_size_);
- // Fix up the data pointers to point into the new region.
- for (size_t i = 0; i < elems_size_; ++i) {
- if (is_blob_tag(elems_[i].tag))
- elems_[i].blob.data = new_data + (elems_[i].blob.data - indirect_data_);
- }
- delete[] indirect_data_;
- indirect_data_ = new_data;
- indirect_data_capacity_ = length;
- }
- return true;
- }
- void AuthorizationSet::MoveFrom(AuthorizationSet& set) {
- elems_ = set.elems_;
- elems_size_ = set.elems_size_;
- elems_capacity_ = set.elems_capacity_;
- indirect_data_ = set.indirect_data_;
- indirect_data_size_ = set.indirect_data_size_;
- indirect_data_capacity_ = set.indirect_data_capacity_;
- error_ = set.error_;
- set.elems_ = nullptr;
- set.elems_size_ = 0;
- set.elems_capacity_ = 0;
- set.indirect_data_ = nullptr;
- set.indirect_data_size_ = 0;
- set.indirect_data_capacity_ = 0;
- set.error_ = OK;
- }
- bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
- FreeData();
- if (elems == nullptr || count == 0) {
- error_ = OK;
- return true;
- }
- if (!reserve_elems(count))
- return false;
- if (!reserve_indirect(ComputeIndirectDataSize(elems, count)))
- return false;
- memcpy(elems_, elems, sizeof(keymaster_key_param_t) * count);
- elems_size_ = count;
- CopyIndirectData();
- error_ = OK;
- return true;
- }
- void AuthorizationSet::set_invalid(Error error) {
- FreeData();
- error_ = error;
- }
- void AuthorizationSet::Sort() {
- qsort(elems_, elems_size_, sizeof(*elems_),
- reinterpret_cast<int (*)(const void*, const void*)>(keymaster_param_compare));
- }
- void AuthorizationSet::Deduplicate() {
- Sort();
- size_t invalid_count = 0;
- for (size_t i = 1; i < size(); ++i) {
- if (elems_[i - 1].tag == KM_TAG_INVALID)
- ++invalid_count;
- else if (keymaster_param_compare(elems_ + i - 1, elems_ + i) == 0) {
- // Mark dups as invalid. Note that this "leaks" the data referenced by KM_BYTES and
- // KM_BIGNUM entries, but those are just pointers into indirect_data_, so it will all
- // get cleaned up.
- elems_[i - 1].tag = KM_TAG_INVALID;
- ++invalid_count;
- }
- }
- if (size() > 0 && elems_[size() - 1].tag == KM_TAG_INVALID)
- ++invalid_count;
- if (invalid_count == 0)
- return;
- Sort();
- // Since KM_TAG_INVALID == 0, all of the invalid entries are first.
- elems_size_ -= invalid_count;
- memmove(elems_, elems_ + invalid_count, size() * sizeof(*elems_));
- }
- void AuthorizationSet::Union(const keymaster_key_param_set_t& set) {
- if (set.length == 0)
- return;
- push_back(set);
- Deduplicate();
- }
- void AuthorizationSet::Difference(const keymaster_key_param_set_t& set) {
- if (set.length == 0)
- return;
- Deduplicate();
- for (size_t i = 0; i < set.length; i++) {
- int index = -1;
- do {
- index = find(set.params[i].tag, index);
- if (index != -1 && keymaster_param_compare(&elems_[index], &set.params[i]) == 0) {
- erase(index);
- break;
- }
- } while (index != -1);
- }
- }
- void AuthorizationSet::CopyToParamSet(keymaster_key_param_set_t* set) const {
- assert(set);
- set->length = size();
- set->params =
- reinterpret_cast<keymaster_key_param_t*>(malloc(sizeof(keymaster_key_param_t) * size()));
- for (size_t i = 0; i < size(); ++i) {
- const keymaster_key_param_t src = (*this)[i];
- keymaster_key_param_t& dst(set->params[i]);
- dst = src;
- keymaster_tag_type_t type = keymaster_tag_get_type(src.tag);
- if (type == KM_BIGNUM || type == KM_BYTES) {
- void* tmp = malloc(src.blob.data_length);
- memcpy(tmp, src.blob.data, src.blob.data_length);
- dst.blob.data = reinterpret_cast<uint8_t*>(tmp);
- }
- }
- }
- int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
- if (is_valid() != OK)
- return -1;
- int i = ++begin;
- while (i < (int)elems_size_ && elems_[i].tag != tag)
- ++i;
- if (i == (int)elems_size_)
- return -1;
- else
- return i;
- }
- bool AuthorizationSet::erase(int index) {
- if (index < 0 || index >= static_cast<int>(size()))
- return false;
- --elems_size_;
- for (size_t i = index; i < elems_size_; ++i)
- elems_[i] = elems_[i + 1];
- return true;
- }
- keymaster_key_param_t empty_param = {KM_TAG_INVALID, {}};
- keymaster_key_param_t& AuthorizationSet::operator[](int at) {
- if (is_valid() == OK && at < (int)elems_size_) {
- return elems_[at];
- }
- empty_param = {KM_TAG_INVALID, {}};
- return empty_param;
- }
- const keymaster_key_param_t& AuthorizationSet::operator[](int at) const {
- if (is_valid() == OK && at < (int)elems_size_) {
- return elems_[at];
- }
- empty_param = {KM_TAG_INVALID, {}};
- return empty_param;
- }
- bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
- if (is_valid() != OK)
- return false;
- if (!reserve_elems(elems_size_ + set.length))
- return false;
- if (!reserve_indirect(indirect_data_size_ + ComputeIndirectDataSize(set.params, set.length)))
- return false;
- for (size_t i = 0; i < set.length; ++i)
- if (!push_back(set.params[i]))
- return false;
- return true;
- }
- bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
- if (is_valid() != OK)
- return false;
- if (elems_size_ >= elems_capacity_)
- if (!reserve_elems(elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY))
- return false;
- if (is_blob_tag(elem.tag)) {
- if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length)
- if (!reserve_indirect(2 * (indirect_data_capacity_ + elem.blob.data_length)))
- return false;
- memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
- elem.blob.data = indirect_data_ + indirect_data_size_;
- indirect_data_size_ += elem.blob.data_length;
- }
- elems_[elems_size_++] = elem;
- return true;
- }
- static size_t serialized_size(const keymaster_key_param_t& param) {
- switch (keymaster_tag_get_type(param.tag)) {
- case KM_INVALID:
- return sizeof(uint32_t);
- case KM_ENUM:
- case KM_ENUM_REP:
- case KM_UINT:
- case KM_UINT_REP:
- return sizeof(uint32_t) * 2;
- case KM_ULONG:
- case KM_ULONG_REP:
- case KM_DATE:
- return sizeof(uint32_t) + sizeof(uint64_t);
- case KM_BOOL:
- return sizeof(uint32_t) + 1;
- case KM_BIGNUM:
- case KM_BYTES:
- return sizeof(uint32_t) * 3;
- }
- return sizeof(uint32_t);
- }
- static uint8_t* serialize(const keymaster_key_param_t& param, uint8_t* buf, const uint8_t* end,
- const uint8_t* indirect_base) {
- buf = append_uint32_to_buf(buf, end, param.tag);
- switch (keymaster_tag_get_type(param.tag)) {
- case KM_INVALID:
- break;
- case KM_ENUM:
- case KM_ENUM_REP:
- buf = append_uint32_to_buf(buf, end, param.enumerated);
- break;
- case KM_UINT:
- case KM_UINT_REP:
- buf = append_uint32_to_buf(buf, end, param.integer);
- break;
- case KM_ULONG:
- case KM_ULONG_REP:
- buf = append_uint64_to_buf(buf, end, param.long_integer);
- break;
- case KM_DATE:
- buf = append_uint64_to_buf(buf, end, param.date_time);
- break;
- case KM_BOOL:
- if (buf < end)
- *buf = static_cast<uint8_t>(param.boolean);
- buf++;
- break;
- case KM_BIGNUM:
- case KM_BYTES:
- buf = append_uint32_to_buf(buf, end, param.blob.data_length);
- buf = append_uint32_to_buf(buf, end, param.blob.data - indirect_base);
- break;
- }
- return buf;
- }
- static bool deserialize(keymaster_key_param_t* param, const uint8_t** buf_ptr, const uint8_t* end,
- const uint8_t* indirect_base, const uint8_t* indirect_end) {
- if (!copy_uint32_from_buf(buf_ptr, end, ¶m->tag))
- return false;
- switch (keymaster_tag_get_type(param->tag)) {
- case KM_INVALID:
- return false;
- case KM_ENUM:
- case KM_ENUM_REP:
- return copy_uint32_from_buf(buf_ptr, end, ¶m->enumerated);
- case KM_UINT:
- case KM_UINT_REP:
- return copy_uint32_from_buf(buf_ptr, end, ¶m->integer);
- case KM_ULONG:
- case KM_ULONG_REP:
- return copy_uint64_from_buf(buf_ptr, end, ¶m->long_integer);
- case KM_DATE:
- return copy_uint64_from_buf(buf_ptr, end, ¶m->date_time);
- break;
- case KM_BOOL:
- if (*buf_ptr < end) {
- uint8_t temp = **buf_ptr;
- // Bools are converted to 0 or 1 when serialized so only accept
- // one of these values when deserializing.
- if (temp <= 1) {
- param->boolean = static_cast<bool>(temp);
- (*buf_ptr)++;
- return true;
- }
- }
- return false;
- case KM_BIGNUM:
- case KM_BYTES: {
- uint32_t offset;
- if (!copy_uint32_from_buf(buf_ptr, end, ¶m->blob.data_length) ||
- !copy_uint32_from_buf(buf_ptr, end, &offset))
- return false;
- if (param->blob.data_length + offset < param->blob.data_length || // Overflow check
- static_cast<ptrdiff_t>(offset) > indirect_end - indirect_base ||
- static_cast<ptrdiff_t>(offset + param->blob.data_length) > indirect_end - indirect_base)
- return false;
- param->blob.data = indirect_base + offset;
- return true;
- }
- }
- return false;
- }
- size_t AuthorizationSet::SerializedSizeOfElements() const {
- size_t size = 0;
- for (size_t i = 0; i < elems_size_; ++i) {
- size += serialized_size(elems_[i]);
- }
- return size;
- }
- size_t AuthorizationSet::SerializedSize() const {
- return sizeof(uint32_t) + // Size of indirect_data_
- indirect_data_size_ + // indirect_data_
- sizeof(uint32_t) + // Number of elems_
- sizeof(uint32_t) + // Size of elems_
- SerializedSizeOfElements(); // elems_
- }
- uint8_t* AuthorizationSet::Serialize(uint8_t* buf, const uint8_t* end) const {
- buf = append_size_and_data_to_buf(buf, end, indirect_data_, indirect_data_size_);
- buf = append_uint32_to_buf(buf, end, elems_size_);
- buf = append_uint32_to_buf(buf, end, SerializedSizeOfElements());
- for (size_t i = 0; i < elems_size_; ++i) {
- buf = serialize(elems_[i], buf, end, indirect_data_);
- }
- return buf;
- }
- bool AuthorizationSet::DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end) {
- UniquePtr<uint8_t[]> indirect_buf;
- if (!copy_size_and_data_from_buf(buf_ptr, end, &indirect_data_size_, &indirect_buf)) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- indirect_data_ = indirect_buf.release();
- return true;
- }
- bool AuthorizationSet::DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end) {
- uint32_t elements_count;
- uint32_t elements_size;
- if (!copy_uint32_from_buf(buf_ptr, end, &elements_count) ||
- !copy_uint32_from_buf(buf_ptr, end, &elements_size)) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- // Note that the following validation of elements_count is weak, but it prevents allocation of
- // elems_ arrays which are clearly too large to be reasonable.
- if (static_cast<ptrdiff_t>(elements_size) > end - *buf_ptr ||
- elements_count * sizeof(uint32_t) > elements_size ||
- *buf_ptr + (elements_count * sizeof(*elems_)) < *buf_ptr) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- if (!reserve_elems(elements_count))
- return false;
- uint8_t* indirect_end = indirect_data_ + indirect_data_size_;
- const uint8_t* elements_end = *buf_ptr + elements_size;
- for (size_t i = 0; i < elements_count; ++i) {
- if (!deserialize(elems_ + i, buf_ptr, elements_end, indirect_data_, indirect_end)) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- }
- // Check if all the elements were consumed. If not, something was malformed as the
- // retrieved elements_count and elements_size are not consistent with each other.
- if (*buf_ptr != elements_end) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- elems_size_ = elements_count;
- return true;
- }
- bool AuthorizationSet::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
- FreeData();
- if (!DeserializeIndirectData(buf_ptr, end) || !DeserializeElementsData(buf_ptr, end))
- return false;
- if (indirect_data_size_ != ComputeIndirectDataSize(elems_, elems_size_)) {
- LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
- set_invalid(MALFORMED_DATA);
- return false;
- }
- return true;
- }
- void AuthorizationSet::Clear() {
- memset_s(elems_, 0, elems_size_ * sizeof(keymaster_key_param_t));
- memset_s(indirect_data_, 0, indirect_data_size_);
- elems_size_ = 0;
- indirect_data_size_ = 0;
- error_ = OK;
- }
- void AuthorizationSet::FreeData() {
- Clear();
- delete[] elems_;
- delete[] indirect_data_;
- elems_ = nullptr;
- indirect_data_ = nullptr;
- elems_capacity_ = 0;
- indirect_data_capacity_ = 0;
- error_ = OK;
- }
- /* static */
- size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
- size_t size = 0;
- for (size_t i = 0; i < count; ++i) {
- if (is_blob_tag(elems[i].tag)) {
- size += elems[i].blob.data_length;
- }
- }
- return size;
- }
- void AuthorizationSet::CopyIndirectData() {
- memset_s(indirect_data_, 0, indirect_data_capacity_);
- uint8_t* indirect_data_pos = indirect_data_;
- for (size_t i = 0; i < elems_size_; ++i) {
- assert(indirect_data_pos <= indirect_data_ + indirect_data_capacity_);
- if (is_blob_tag(elems_[i].tag)) {
- memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
- elems_[i].blob.data = indirect_data_pos;
- indirect_data_pos += elems_[i].blob.data_length;
- }
- }
- assert(indirect_data_pos == indirect_data_ + indirect_data_capacity_);
- indirect_data_size_ = indirect_data_pos - indirect_data_;
- }
- size_t AuthorizationSet::GetTagCount(keymaster_tag_t tag) const {
- size_t count = 0;
- for (int pos = -1; (pos = find(tag, pos)) != -1;)
- ++count;
- return count;
- }
- bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- *val = elems_[pos].enumerated;
- return true;
- }
- bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
- uint32_t* val) const {
- size_t count = 0;
- int pos = -1;
- while (count <= instance) {
- pos = find(tag, pos);
- if (pos == -1) {
- return false;
- }
- ++count;
- }
- *val = elems_[pos].enumerated;
- return true;
- }
- bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- *val = elems_[pos].integer;
- return true;
- }
- bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
- uint32_t* val) const {
- size_t count = 0;
- int pos = -1;
- while (count <= instance) {
- pos = find(tag, pos);
- if (pos == -1) {
- return false;
- }
- ++count;
- }
- *val = elems_[pos].integer;
- return true;
- }
- bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- *val = elems_[pos].long_integer;
- return true;
- }
- bool AuthorizationSet::GetTagValueLongRep(keymaster_tag_t tag, size_t instance,
- uint64_t* val) const {
- size_t count = 0;
- int pos = -1;
- while (count <= instance) {
- pos = find(tag, pos);
- if (pos == -1) {
- return false;
- }
- ++count;
- }
- *val = elems_[pos].long_integer;
- return true;
- }
- bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- *val = elems_[pos].date_time;
- return true;
- }
- bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- *val = elems_[pos].blob;
- return true;
- }
- bool AuthorizationSet::GetTagValueBool(keymaster_tag_t tag) const {
- int pos = find(tag);
- if (pos == -1) {
- return false;
- }
- assert(elems_[pos].boolean);
- return elems_[pos].boolean;
- }
- bool AuthorizationSet::ContainsEnumValue(keymaster_tag_t tag, uint32_t value) const {
- for (auto& entry : *this)
- if (entry.tag == tag && entry.enumerated == value)
- return true;
- return false;
- }
- bool AuthorizationSet::ContainsIntValue(keymaster_tag_t tag, uint32_t value) const {
- for (auto& entry : *this)
- if (entry.tag == tag && entry.integer == value)
- return true;
- return false;
- }
- } // namespace keymaster
|