/* * Copyright 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. */ #ifndef SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_ #define SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_ #include #include #include #include #include namespace keymaster { class AuthorizationSetBuilder; /** * An extension of the keymaster_key_param_set_t struct, which provides serialization memory * management and methods for easy manipulation and construction. */ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t { public: /** * Construct an empty, dynamically-allocated, growable AuthorizationSet. Does not actually * allocate any storage until elements are added, so there is no cost to creating an * AuthorizationSet with this constructor and then reinitializing it to point at pre-allocated * buffers, with \p Reinitialize. */ AuthorizationSet() : elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0), indirect_data_capacity_(0), error_(OK) { elems_ = nullptr; elems_size_ = 0; } /** * Construct an AuthorizationSet from the provided array. The AuthorizationSet copies the data * from the provided array (and the data referenced by its embedded pointers, if any) into * dynamically-allocated storage. If allocation of the needed storage fails, \p is_valid() will * return ALLOCATION_FAILURE. It is the responsibility of the caller to check before using the * set, if allocations might fail. */ AuthorizationSet(const keymaster_key_param_t* elems, size_t count) : elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0), indirect_data_capacity_(0), error_(OK) { elems_ = nullptr; Reinitialize(elems, count); } explicit AuthorizationSet(const keymaster_key_param_set_t& set) : elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0), indirect_data_capacity_(0), error_(OK) { elems_ = nullptr; Reinitialize(set.params, set.length); } explicit AuthorizationSet(const uint8_t* serialized_set, size_t serialized_size) : elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0), indirect_data_capacity_(0), error_(OK) { elems_ = nullptr; Deserialize(&serialized_set, serialized_set + serialized_size); } /** * Construct an AuthorizationSet from the provided builder. This extracts the data from the * builder, rather than copying it, so after this call the builder is empty. */ explicit AuthorizationSet(/* NOT const */ AuthorizationSetBuilder& builder); // Copy constructor. AuthorizationSet(const AuthorizationSet& set) : Serializable(), elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0), indirect_data_capacity_(0), error_(OK) { elems_ = nullptr; error_ = set.error_; if (error_ != OK) return; Reinitialize(set.elems_, set.elems_size_); } // Move constructor. AuthorizationSet(AuthorizationSet&& set) : Serializable() { MoveFrom(set); } // Copy assignment. AuthorizationSet& operator=(const AuthorizationSet& set) { Reinitialize(set.elems_, set.elems_size_); error_ = set.error_; return *this; } // Move assignment. AuthorizationSet& operator=(AuthorizationSet&& set) { FreeData(); MoveFrom(set); return *this; } /** * Clear existing authorization set data */ void Clear(); /** * Reinitialize an AuthorizationSet as a dynamically-allocated, growable copy of the data in the * provided array (and the data referenced by its embedded pointers, if any). If the allocation * of the needed storage fails this method will return false and \p is_valid() will return * ALLOCATION_FAILURE. */ bool Reinitialize(const keymaster_key_param_t* elems, size_t count); bool Reinitialize(const AuthorizationSet& set) { return Reinitialize(set.elems_, set.elems_size_); } bool Reinitialize(const keymaster_key_param_set_t& set) { return Reinitialize(set.params, set.length); } ~AuthorizationSet(); enum Error { OK, ALLOCATION_FAILURE, MALFORMED_DATA, }; Error is_valid() const { return error_; } /** * Returns the size of the set. */ size_t size() const { return elems_size_; } /** * Returns true if the set is empty. */ bool empty() const { return size() == 0; } /** * Returns the total size of all indirect data referenced by set elements. */ size_t indirect_size() const { return indirect_data_size_; } /** * Returns the data in the set, directly. Be careful with this. */ const keymaster_key_param_t* data() const { return elems_; } /** * Sorts the set */ void Sort(); /** * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the * AuthorizationSetBuilder). */ void Deduplicate(); /** * Adds all elements from \p set that are not already present in this AuthorizationSet. As a * side-effect, if \p set is not null this AuthorizationSet will end up sorted. */ void Union(const keymaster_key_param_set_t& set); /** * Removes all elements in \p set from this AuthorizationSet. */ void Difference(const keymaster_key_param_set_t& set); /** * Returns the data in a keymaster_key_param_set_t, suitable for returning to C code. For C * compatibility, the contents are malloced, not new'ed, and so must be freed with free(), or * better yet with keymaster_free_param_set, not delete. The caller takes ownership. */ void CopyToParamSet(keymaster_key_param_set_t* set) const; /** * Returns the offset of the next entry that matches \p tag, starting from the element after \p * begin. If not found, returns -1. */ int find(keymaster_tag_t tag, int begin = -1) const; /** * Removes the entry at the specified index. Returns true if successful, false if the index was * out of bounds. */ bool erase(int index); /** * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration */ const keymaster_key_param_t* begin() const { return elems_; } /** * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration */ const keymaster_key_param_t* end() const { return elems_ + elems_size_; } /** * Returns the nth element of the set. */ keymaster_key_param_t& operator[](int n); /** * Returns the nth element of the set. */ const keymaster_key_param_t& operator[](int n) const; /** * Returns true if the set contains at least one instance of \p tag */ bool Contains(keymaster_tag_t tag) const { return find(tag) != -1; } /** * Returns the number of \p tag entries. */ size_t GetTagCount(keymaster_tag_t tag) const; /** * Returns true if the set contains the specified tag and value. */ template bool Contains(TypedEnumTag tag, T val) const { return ContainsEnumValue(tag, val); } /** * Returns true if the set contains the specified tag and value. */ template bool Contains(TypedEnumTag tag, T val) const { return ContainsEnumValue(tag, val); } /** * Returns true if the set contains the specified tag and value. */ template bool Contains(TypedTag tag, uint32_t val) const { return ContainsIntValue(tag, val); } /** * If the specified integer-typed \p tag exists, places its value in \p val and returns true. * If \p tag is not present, leaves \p val unmodified and returns false. */ template inline bool GetTagValue(TypedTag tag, uint32_t* val) const { return GetTagValueInt(tag, val); } /** * If the specified instance of the specified integer-typed \p tag exists, places its value * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns * false. */ template bool GetTagValue(TypedTag tag, size_t instance, uint32_t* val) const { return GetTagValueIntRep(tag, instance, val); } /** * If the specified long-typed \p tag exists, places its value in \p val and returns true. * If \p tag is not present, leaves \p val unmodified and returns false. */ template inline bool GetTagValue(TypedTag tag, uint64_t* val) const { return GetTagValueLong(tag, val); } /** * If the specified instance of the specified integer-typed \p tag exists, places its value * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns * false. */ template bool GetTagValue(TypedTag tag, size_t instance, uint64_t* val) const { return GetTagValueLongRep(tag, instance, val); } /** * If the specified enumeration-typed \p tag exists, places its value in \p val and returns * true. If \p tag is not present, leaves \p val unmodified and returns false. */ template bool GetTagValue(TypedEnumTag tag, T* val) const { return GetTagValueEnum(tag, reinterpret_cast(val)); } /** * If the specified instance of the specified enumeration-typed \p tag exists, places its value * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns * false. */ template bool GetTagValue(TypedEnumTag tag, size_t instance, T* val) const { return GetTagValueEnumRep(tag, instance, reinterpret_cast(val)); } /** * If exactly one instance of the specified enumeration-typed \p tag exists, places its value in * \p val and returns true. If \p tag is not present or if multiple copies are present, leaves * \p val unmodified and returns false. */ template bool GetTagValue(TypedEnumTag tag, T* val) const { if (GetTagCount(tag) != 1) return false; return GetTagValueEnumRep(tag, 0, reinterpret_cast(val)); } /** * If the specified date-typed \p tag exists, places its value in \p val and returns * true. If \p tag is not present, leaves \p val unmodified and returns false. */ template bool GetTagValue(TypedTag tag, size_t instance, typename TypedTag::value_type* val) const { return GetTagValueIntRep(tag, instance, val); } /** * If the specified bytes-typed \p tag exists, places its value in \p val and returns * true. If \p tag is not present, leaves \p val unmodified and returns false. */ template bool GetTagValue(TypedTag tag, keymaster_blob_t* val) const { return GetTagValueBlob(tag, val); } /** * If the specified bignum-typed \p tag exists, places its value in \p val and returns * true. If \p tag is not present, leaves \p val unmodified and returns false. */ template bool GetTagValue(TypedTag tag, keymaster_blob_t* val) const { return GetTagValueBlob(tag, val); } /** * Returns true if the specified tag is present, and therefore has the value 'true'. */ template bool GetTagValue(TypedTag tag) const { return GetTagValueBool(tag); } /** * If the specified \p tag exists, places its value in \p val and returns true. If \p tag is * not present, leaves \p val unmodified and returns false. */ template bool GetTagValue(TypedTag tag, typename TagValueType::value_type* val) const { return GetTagValueLong(tag, val); } bool push_back(keymaster_key_param_t elem); /** * Grow the elements array to ensure it can contain \p count entries. Preserves any existing * entries. */ bool reserve_elems(size_t count); /** * Grow the indirect data array to ensure it can contain \p length bytes. Preserves any * existing indirect data. */ bool reserve_indirect(size_t length); bool push_back(const keymaster_key_param_set_t& set); /** * Append the tag and enumerated value to the set. */ template bool push_back(TypedEnumTag tag, KeymasterEnum val) { return push_back(Authorization(tag, val)); } /** * Append the boolean tag (value "true") to the set. */ template bool push_back(TypedTag tag) { return push_back(Authorization(tag)); } /** * Append the tag and byte array to the set. Copies the array into internal storage; does not * take ownership of the passed-in array. */ template bool push_back(TypedTag tag, const void* bytes, size_t bytes_len) { return push_back(keymaster_param_blob(tag, static_cast(bytes), bytes_len)); } /** * Append the tag and blob to the set. Copies the blob contents into internal storage; does not * take ownership of the blob's data. */ template bool push_back(TypedTag tag, const keymaster_blob_t& blob) { return push_back(tag, blob.data, blob.data_length); } /** * Append the tag and bignum array to the set. Copies the array into internal storage; does not * take ownership of the passed-in array. */ template bool push_back(TypedTag tag, const void* bytes, size_t bytes_len) { return push_back(keymaster_param_blob(tag, static_cast(bytes), bytes_len)); } template bool push_back(TypedTag tag, typename TypedTag::value_type val) { return push_back(Authorization(tag, val)); } template bool push_back(TypedTag tag, const void* bytes, size_t bytes_len) { return push_back(Authorization(tag, bytes, bytes_len)); } /* Virtual methods from Serializable */ size_t SerializedSize() const; uint8_t* Serialize(uint8_t* serialized_set, const uint8_t* end) const; bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end); size_t SerializedSizeOfElements() const; private: void FreeData(); void MoveFrom(AuthorizationSet& set); void set_invalid(Error err); static size_t ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count); void CopyIndirectData(); bool CheckIndirectData(); bool DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end); bool DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end); bool GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const; bool GetTagValueEnumRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const; bool GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const; bool GetTagValueIntRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const; bool GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const; bool GetTagValueLongRep(keymaster_tag_t tag, size_t instance, uint64_t* val) const; bool GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const; bool GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const; bool GetTagValueBool(keymaster_tag_t tag) const; bool ContainsEnumValue(keymaster_tag_t tag, uint32_t val) const; bool ContainsIntValue(keymaster_tag_t tag, uint32_t val) const; // Define elems_ and elems_size_ as aliases to params and length, respectively. This is to // avoid using the variables without the trailing underscore in the implementation. keymaster_key_param_t*& elems_ = keymaster_key_param_set_t::params; size_t& elems_size_ = keymaster_key_param_set_t::length; size_t elems_capacity_; uint8_t* indirect_data_; size_t indirect_data_size_; size_t indirect_data_capacity_; Error error_; }; class AuthorizationSetBuilder { public: template AuthorizationSetBuilder& Authorization(TagType tag, ValueType value) { set.push_back(tag, value); return *this; } template AuthorizationSetBuilder& Authorization(TypedTag tag) { set.push_back(tag); return *this; } template AuthorizationSetBuilder& Authorization(TypedTag tag) { keymaster_key_param_t param; param.tag = tag; set.push_back(param); return *this; } template AuthorizationSetBuilder& Authorization(TypedTag tag, const uint8_t* data, size_t data_length) { set.push_back(tag, data, data_length); return *this; } template AuthorizationSetBuilder& Authorization(TypedTag tag, const char* data, size_t data_length) { return Authorization(tag, reinterpret_cast(data), data_length); } AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); AuthorizationSetBuilder& AesKey(uint32_t key_size); AuthorizationSetBuilder& TripleDesKey(uint32_t key_size); AuthorizationSetBuilder& HmacKey(uint32_t key_size); AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size); AuthorizationSetBuilder& SigningKey(); AuthorizationSetBuilder& EncryptionKey(); AuthorizationSetBuilder& NoDigestOrPadding(); AuthorizationSetBuilder& EcbMode(); AuthorizationSetBuilder& Digest(keymaster_digest_t digest) { return Authorization(TAG_DIGEST, digest); } AuthorizationSetBuilder& BlockMode(keymaster_block_mode_t mode) { return Authorization(TAG_BLOCK_MODE, mode); } AuthorizationSetBuilder& Padding(keymaster_padding_t padding) { return Authorization(TAG_PADDING, padding); } AuthorizationSetBuilder& Deduplicate() { set.Deduplicate(); return *this; } AuthorizationSet build() const { return set; } private: friend AuthorizationSet; AuthorizationSet set; }; inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, uint64_t public_exponent) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA); Authorization(TAG_KEY_SIZE, key_size); Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); return *this; } inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC); Authorization(TAG_KEY_SIZE, key_size); return *this; } inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES); return Authorization(TAG_KEY_SIZE, key_size); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_TRIPLE_DES); return Authorization(TAG_KEY_SIZE, key_size); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC); Authorization(TAG_KEY_SIZE, key_size); return SigningKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, uint64_t public_exponent) { RsaKey(key_size, public_exponent); return SigningKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent) { RsaKey(key_size, public_exponent); return EncryptionKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { EcdsaKey(key_size); return SigningKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { AesKey(key_size); return EncryptionKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) { TripleDesKey(key_size); return EncryptionKey(); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN); return Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT); return Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { Authorization(TAG_DIGEST, KM_DIGEST_NONE); return Authorization(TAG_PADDING, KM_PAD_NONE); } inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { return Authorization(TAG_BLOCK_MODE, KM_MODE_ECB); } class AuthProxyIterator { constexpr static size_t invalid = ~size_t(0); public: AuthProxyIterator() : pos_(invalid), auth_set1_(nullptr), auth_set2_(nullptr) {} AuthProxyIterator(const AuthorizationSet& auth_set1, const AuthorizationSet& auth_set2) : pos_(0), auth_set1_(&auth_set1), auth_set2_(&auth_set2) {} AuthProxyIterator(const AuthProxyIterator& rhs) : pos_(rhs.pos_), auth_set1_(rhs.auth_set1_), auth_set2_(rhs.auth_set2_) {} ~AuthProxyIterator() {}; AuthProxyIterator& operator=(const AuthProxyIterator& rhs) { if (this != &rhs) { pos_ = rhs.pos_; auth_set1_ = rhs.auth_set1_; auth_set2_ = rhs.auth_set2_; } return *this; } AuthProxyIterator& operator++() { if (pos_ == invalid) return *this; ++pos_; if (pos_ == (auth_set1_->size() + auth_set2_->size())) { pos_ = invalid; } return *this; } const keymaster_key_param_t& operator*() const { if (pos_ < auth_set1_->size()) { return (*auth_set1_)[pos_]; } else { return (*auth_set2_)[pos_ - auth_set1_->size()]; } } AuthProxyIterator operator++(int) { AuthProxyIterator dummy(*this); ++(*this); return dummy; } const keymaster_key_param_t* operator->() const { return &(*(*this)); } bool operator==(const AuthProxyIterator& rhs) { if (pos_ == rhs.pos_) { return pos_ == invalid || (auth_set1_ == rhs.auth_set1_ && auth_set2_ == rhs.auth_set2_); } else return false; } bool operator!=(const AuthProxyIterator& rhs) { return !operator==(rhs); } private: size_t pos_; const AuthorizationSet* auth_set1_; const AuthorizationSet* auth_set2_; }; class AuthProxy { public: AuthProxy(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced) : hw_enforced_(hw_enforced), sw_enforced_(sw_enforced) {} template bool Contains(ARGS&&... args) const { return hw_enforced_.Contains(forward(args)...) || sw_enforced_.Contains(forward(args)...); } template bool GetTagValue(ARGS&&... args) const { return hw_enforced_.GetTagValue(forward(args)...) || sw_enforced_.GetTagValue(forward(args)...); } AuthProxyIterator begin() const { return AuthProxyIterator(hw_enforced_, sw_enforced_); } AuthProxyIterator end() const { return AuthProxyIterator(); } size_t size() const { return hw_enforced_.size() + sw_enforced_.size(); } keymaster_key_param_t operator[](size_t pos) const { if (pos < hw_enforced_.size()) return hw_enforced_[pos]; if ((pos - hw_enforced_.size()) < sw_enforced_.size()) { return sw_enforced_[pos - hw_enforced_.size()]; } return {}; } private: const AuthorizationSet& hw_enforced_; const AuthorizationSet& sw_enforced_; }; } // namespace keymaster #endif // SYSTEM_KEYMASTER_KEY_AUTHORIZATION_SET_H_