/* * 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_VOLD_KEYMASTER_TAGS_H_ #define SYSTEM_VOLD_KEYMASTER_TAGS_H_ /** * This header contains various definitions that make working with keymaster tags safer and easier. * * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose * of making it impossible to make certain classes of mistakes when operating on keymaster * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE * and then to assign Algorithm::RSA to algorithm element of its union. But because the user * must choose the union field, there could be a mismatch which the compiler has now way to * diagnose. * * The machinery in this header solves these problems by describing which union field corresponds * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG, * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal. * * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag * to its value c++ type and the correct union element of KeyParameter. This is done by means of * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a * reference to the correct element of KeyParameter. * E.g.: * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)" * yields a reference to param.f.purpose * If used in an assignment the compiler can now check the compatibility of the assigned value. * * For convenience we also provide the constructor like function Authorization(). * Authorization takes a typed tag and a value and checks at compile time whether the value given * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the * given tag and value and returns it by value. * * The second convenience function, authorizationValue, allows access to the KeyParameter value in * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped * reference. * E.g.: * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA); * auto value1 = authorizationValue(TAG_PURPOSE, param); * auto value2 = authorizationValue(TAG_ALGORITM, param); * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access. */ #include #include #include namespace keystore { using ::android::hardware::keymaster::V3_0::Algorithm; using ::android::hardware::keymaster::V3_0::BlockMode; using ::android::hardware::keymaster::V3_0::Digest; using ::android::hardware::keymaster::V3_0::EcCurve; using ::android::hardware::keymaster::V3_0::ErrorCode; using ::android::hardware::keymaster::V3_0::HardwareAuthToken; using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; using ::android::hardware::keymaster::V3_0::IKeymasterDevice; using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements; using ::android::hardware::keymaster::V3_0::KeyCharacteristics; using ::android::hardware::keymaster::V3_0::KeyDerivationFunction; using ::android::hardware::keymaster::V3_0::KeyFormat; using ::android::hardware::keymaster::V3_0::KeyOrigin; using ::android::hardware::keymaster::V3_0::KeyParameter; using ::android::hardware::keymaster::V3_0::KeyPurpose; using ::android::hardware::keymaster::V3_0::PaddingMode; using ::android::hardware::keymaster::V3_0::Tag; using ::android::hardware::keymaster::V3_0::TagType; using ::android::hardware::hidl_vec; using ::android::hardware::Return; // The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We // need these old values to be able to support old keys that use them. static const int32_t KM_TAG_DIGEST_OLD = static_cast(TagType::ENUM) | 5; static const int32_t KM_TAG_PADDING_OLD = static_cast(TagType::ENUM) | 7; constexpr TagType typeFromTag(Tag tag) { return static_cast(static_cast(tag) & static_cast(0xf0000000)); } /** * TypedTag is a templatized version of Tag, which provides compile-time checking of * keymaster tag types. Instances are convertible to Tag, so they can be used wherever * Tag is expected, and because they encode the tag type it's possible to create * function overloads that only operate on tags with a particular type. */ template struct TypedTag { inline TypedTag() { // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile // error (no match for template specialization StaticAssert), with no run-time cost. static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); } operator Tag() const { return tag; } }; template struct Tag2TypedTag { typedef TypedTag type; }; template struct Tag2String; #define _TAGS_STRINGIFY(x) #x #define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x) #define DECLARE_TYPED_TAG(name) \ typedef typename Tag2TypedTag::type TAG_##name##_t; \ extern TAG_##name##_t TAG_##name; \ template <> \ struct Tag2String { \ static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \ } DECLARE_TYPED_TAG(INVALID); DECLARE_TYPED_TAG(KEY_SIZE); DECLARE_TYPED_TAG(MAC_LENGTH); DECLARE_TYPED_TAG(CALLER_NONCE); DECLARE_TYPED_TAG(MIN_MAC_LENGTH); DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE); DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); DECLARE_TYPED_TAG(ACTIVE_DATETIME); DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); DECLARE_TYPED_TAG(ALL_USERS); DECLARE_TYPED_TAG(USER_ID); DECLARE_TYPED_TAG(USER_SECURE_ID); DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); DECLARE_TYPED_TAG(AUTH_TIMEOUT); DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); DECLARE_TYPED_TAG(ALL_APPLICATIONS); DECLARE_TYPED_TAG(APPLICATION_ID); DECLARE_TYPED_TAG(APPLICATION_DATA); DECLARE_TYPED_TAG(CREATION_DATETIME); DECLARE_TYPED_TAG(ROLLBACK_RESISTANT); DECLARE_TYPED_TAG(ROOT_OF_TRUST); DECLARE_TYPED_TAG(ASSOCIATED_DATA); DECLARE_TYPED_TAG(NONCE); DECLARE_TYPED_TAG(AUTH_TOKEN); DECLARE_TYPED_TAG(BOOTLOADER_ONLY); DECLARE_TYPED_TAG(OS_VERSION); DECLARE_TYPED_TAG(OS_PATCHLEVEL); DECLARE_TYPED_TAG(UNIQUE_ID); DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); DECLARE_TYPED_TAG(PURPOSE); DECLARE_TYPED_TAG(ALGORITHM); DECLARE_TYPED_TAG(BLOCK_MODE); DECLARE_TYPED_TAG(DIGEST); DECLARE_TYPED_TAG(PADDING); DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS); DECLARE_TYPED_TAG(ORIGIN); DECLARE_TYPED_TAG(USER_AUTH_TYPE); DECLARE_TYPED_TAG(KDF); DECLARE_TYPED_TAG(EC_CURVE); template struct MetaList {}; using all_tags_t = MetaList< TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>; /* implementation in keystore_utils.cpp */ extern const char* stringifyTag(Tag tag); template struct TypedTag2ValueType; #define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ template \ struct TypedTag2ValueType> { \ typedef decltype(static_cast(nullptr)->field_name) type; \ }; \ template \ inline auto accessTagValue(TypedTag, const KeyParameter& param) \ ->const decltype(param.field_name)& { \ return param.field_name; \ } \ template \ inline auto accessTagValue(TypedTag, KeyParameter& param) \ ->decltype(param.field_name)& { \ return param.field_name; \ } MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger) MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger) MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime) MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer) MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer) MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue) MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) #define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ template <> \ struct TypedTag2ValueType { \ typedef decltype(static_cast(nullptr)->field_name) type; \ }; \ inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ ->const decltype(param.field_name)& { \ return param.field_name; \ } \ inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \ ->decltype(param.field_name)& { \ return param.field_name; \ } MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType) template inline KeyParameter makeKeyParameter(TypedTag ttag, ValueT&& value) { KeyParameter param; param.tag = tag; param.f.longInteger = 0; accessTagValue(ttag, param) = std::forward(value); return param; } // the boolean case template inline KeyParameter makeKeyParameter(TypedTag) { KeyParameter param; param.tag = tag; param.f.boolValue = true; return param; } template struct FirstOrNoneHelper; template struct FirstOrNoneHelper { typedef First type; }; template <> struct FirstOrNoneHelper<> { struct type {}; }; template using FirstOrNone = typename FirstOrNoneHelper::type; template inline KeyParameter Authorization(TypedTag ttag, Args&&... args) { static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), "TagType::BOOL Authorizations do not take parameters. Presence is truth."); static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), "Authorization other then TagType::BOOL take exactly one parameter."); static_assert( tag_type == TagType::BOOL || std::is_convertible>>, typename TypedTag2ValueType>::type>::value, "Invalid argument type for given tag."); return makeKeyParameter(ttag, std::forward(args)...); } /** * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out * of band. Note that if the wrapped value is a reference it is unsafe to access the value if * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the * wrapped value. In this case the pointer will be NULL though, and the value will be default * constructed. */ template class NullOr { template struct reference_initializer { static T&& init() { return *static_cast*>(nullptr); } }; template struct pointer_initializer { static T init() { return nullptr; } }; template struct value_initializer { static T init() { return T(); } }; template using initializer_t = std::conditional_t< std::is_lvalue_reference::value, reference_initializer, std::conditional_t::value, pointer_initializer, value_initializer>>; public: NullOr() : value_(initializer_t::init()), null_(true) {} NullOr(ValueT&& value) : value_(std::forward(value)), null_(false) {} bool isOk() const { return !null_; } const ValueT& value() const & { return value_; } ValueT& value() & { return value_; } ValueT&& value() && { return std::move(value_); } private: ValueT value_; bool null_; }; template std::remove_reference_t NullOrOr(T&& v) { if (v.isOk()) return v; return {}; } template std::remove_reference_t NullOrOr(Head&& head, Tail&&... tail) { if (head.isOk()) return head; return NullOrOr(std::forward(tail)...); } template std::remove_reference_t defaultOr(NullOr&& optional, Default&& def) { static_assert( std::is_convertible, std::remove_reference_t>::value, "Type of default value must match the type wrapped by NullOr"); if (optional.isOk()) return optional.value(); return def; } template inline NullOr>::type&> authorizationValue( TypedTag ttag, const KeyParameter& param) { if (tag != param.tag) return {}; return accessTagValue(ttag, param); } } // namespace keystore #endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_