| /* |
| * 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 <UniquePtr.h> |
| |
| #include <hardware/keymaster_defs.h> |
| #include <keymaster/keymaster_tags.h> |
| #include <keymaster/serializable.h> |
| |
| 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_(NULL), 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) : indirect_data_(nullptr) { |
| elems_ = nullptr; |
| Reinitialize(elems, count); |
| } |
| |
| explicit AuthorizationSet(const keymaster_key_param_set_t& set) : indirect_data_(nullptr) { |
| elems_ = nullptr; |
| Reinitialize(set.params, set.length); |
| } |
| |
| explicit AuthorizationSet(const uint8_t* serialized_set, size_t serialized_size) |
| : indirect_data_(nullptr) { |
| 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(), indirect_data_(nullptr) { |
| elems_ = nullptr; |
| Reinitialize(set.elems_, set.elems_size_); |
| } |
| |
| /** |
| * 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 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 and removes duplicates (inadvertently duplicating tags is easy to do with the |
| * AuthorizationSetBuilder). |
| */ |
| void Deduplicate(); |
| |
| /** |
| * 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; |
| |
| /** |
| * 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) const; |
| |
| /** |
| * 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 <keymaster_tag_t Tag, typename T> |
| bool Contains(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T val) const { |
| return ContainsEnumValue(tag, val); |
| } |
| |
| /** |
| * Returns true if the set contains the specified tag and value. |
| */ |
| template <keymaster_tag_t Tag, typename T> |
| bool Contains(TypedEnumTag<KM_ENUM, Tag, T> tag, T val) const { |
| return ContainsEnumValue(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 <keymaster_tag_t T> |
| inline bool GetTagValue(TypedTag<KM_UINT, T> 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 <keymaster_tag_t Tag> |
| bool GetTagValue(TypedTag<KM_UINT_REP, Tag> 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 <keymaster_tag_t T> |
| inline bool GetTagValue(TypedTag<KM_ULONG, T> 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 <keymaster_tag_t Tag> |
| bool GetTagValue(TypedTag<KM_ULONG_REP, Tag> 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 <keymaster_tag_t Tag, typename T> |
| bool GetTagValue(TypedEnumTag<KM_ENUM, Tag, T> tag, T* val) const { |
| return GetTagValueEnum(tag, reinterpret_cast<uint32_t*>(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 <keymaster_tag_t Tag, typename T> |
| bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, size_t instance, T* val) const { |
| return GetTagValueEnumRep(tag, instance, reinterpret_cast<uint32_t*>(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 <keymaster_tag_t Tag, typename T> |
| bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T* val) const { |
| if (GetTagCount(tag) != 1) |
| return false; |
| return GetTagValueEnumRep(tag, 0, reinterpret_cast<uint32_t*>(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 <keymaster_tag_t Tag> |
| bool GetTagValue(TypedTag<KM_UINT_REP, Tag> tag, size_t instance, |
| typename TypedTag<KM_UINT_REP, Tag>::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 <keymaster_tag_t Tag> |
| bool GetTagValue(TypedTag<KM_BYTES, Tag> 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 <keymaster_tag_t Tag> |
| bool GetTagValue(TypedTag<KM_BIGNUM, Tag> 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 <keymaster_tag_t Tag> bool GetTagValue(TypedTag<KM_BOOL, Tag> 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 <keymaster_tag_t Tag, keymaster_tag_type_t Type> |
| bool GetTagValue(TypedTag<Type, Tag> tag, typename TagValueType<Type>::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 <keymaster_tag_t Tag, keymaster_tag_type_t Type, typename KeymasterEnum> |
| bool push_back(TypedEnumTag<Type, Tag, KeymasterEnum> tag, KeymasterEnum val) { |
| return push_back(Authorization(tag, val)); |
| } |
| |
| /** |
| * Append the boolean tag (value "true") to the set. |
| */ |
| template <keymaster_tag_t Tag> bool push_back(TypedTag<KM_BOOL, Tag> 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 <keymaster_tag_t Tag> |
| bool push_back(TypedTag<KM_BYTES, Tag> tag, const void* bytes, size_t bytes_len) { |
| return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(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 <keymaster_tag_t Tag> |
| bool push_back(TypedTag<KM_BYTES, Tag> 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 <keymaster_tag_t Tag> |
| bool push_back(TypedTag<KM_BIGNUM, Tag> tag, const void* bytes, size_t bytes_len) { |
| return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(bytes), bytes_len)); |
| } |
| |
| template <keymaster_tag_t Tag, keymaster_tag_type_t Type> |
| bool push_back(TypedTag<Type, Tag> tag, typename TypedTag<Type, Tag>::value_type val) { |
| return push_back(Authorization(tag, val)); |
| } |
| |
| template <keymaster_tag_t Tag, keymaster_tag_type_t Type> |
| bool push_back(TypedTag<Type, Tag> 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: |
| // Disallow assignment |
| void operator=(const AuthorizationSet&); |
| |
| void FreeData(); |
| 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; |
| |
| // Define elems_ and elems_size_ as aliases to params and length, respectivley. 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 <typename TagType, typename ValueType> |
| AuthorizationSetBuilder& Authorization(TagType tag, ValueType value) { |
| set.push_back(tag, value); |
| return *this; |
| } |
| |
| template <keymaster_tag_t Tag> |
| AuthorizationSetBuilder& Authorization(TypedTag<KM_BOOL, Tag> tag) { |
| set.push_back(tag); |
| return *this; |
| } |
| |
| template <keymaster_tag_t Tag> |
| AuthorizationSetBuilder& Authorization(TypedTag<KM_INVALID, Tag> tag) { |
| keymaster_key_param_t param; |
| param.tag = tag; |
| set.push_back(param); |
| return *this; |
| } |
| |
| template <keymaster_tag_t Tag> |
| AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const uint8_t* data, |
| size_t data_length) { |
| set.push_back(tag, data, data_length); |
| return *this; |
| } |
| |
| template <keymaster_tag_t Tag> |
| AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const char* data, |
| size_t data_length) { |
| return Authorization(tag, reinterpret_cast<const uint8_t*>(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& 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& SigningKey(); |
| AuthorizationSetBuilder& EncryptionKey(); |
| AuthorizationSetBuilder& NoDigestOrPadding(); |
| AuthorizationSetBuilder& EcbMode(); |
| |
| AuthorizationSetBuilder& Digest(keymaster_digest_t digest) { |
| return Authorization(TAG_DIGEST, digest); |
| } |
| |
| 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::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::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); |
| } |
| |
| } // namespace keymaster |
| |
| #endif // SYSTEM_KEYMASTER_KEY_AUTHORIZATION_SET_H_ |