Merge "Revise keymint_tags.h"
This commit is contained in:
commit
2528ddcab2
6 changed files with 122 additions and 117 deletions
|
@ -577,8 +577,8 @@ string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode bloc
|
|||
string ciphertext = EncryptMessage(message, params, &out_params);
|
||||
EXPECT_EQ(1U, out_params.size());
|
||||
auto ivVal = out_params.GetTagValue(TAG_NONCE);
|
||||
EXPECT_TRUE(ivVal.isOk());
|
||||
if (ivVal.isOk()) *iv_out = ivVal.value();
|
||||
EXPECT_TRUE(ivVal);
|
||||
if (ivVal) *iv_out = *ivVal;
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,10 @@ namespace {
|
|||
template <TagType tag_type, Tag tag, typename ValueT>
|
||||
bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
|
||||
auto it = std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
|
||||
return param.tag == tag && accessTagValue(ttag, param) == expected_value;
|
||||
if (auto p = authorizationValue(ttag, param)) {
|
||||
return *p == expected_value;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return (it != set.end());
|
||||
}
|
||||
|
@ -251,10 +254,10 @@ class NewKeyGenerationTest : public KeyMintAidlTestBase {
|
|||
|
||||
EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
|
||||
<< "OS version is " << os_version() << " key reported "
|
||||
<< auths.GetTagValue(TAG_OS_VERSION);
|
||||
<< auths.GetTagValue(TAG_OS_VERSION)->get();
|
||||
EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
|
||||
<< "OS patch level is " << os_patch_level() << " key reported "
|
||||
<< auths.GetTagValue(TAG_OS_PATCHLEVEL);
|
||||
<< auths.GetTagValue(TAG_OS_PATCHLEVEL)->get();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2333,8 +2336,8 @@ TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
|
|||
|
||||
vector<uint8_t> CopyIv(const AuthorizationSet& set) {
|
||||
auto iv = set.GetTagValue(TAG_NONCE);
|
||||
EXPECT_TRUE(iv.isOk());
|
||||
return iv.value();
|
||||
EXPECT_TRUE(iv);
|
||||
return iv->get();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2459,13 +2462,13 @@ TEST_P(EncryptionOperationsTest, AesIncremental) {
|
|||
case BlockMode::CBC:
|
||||
case BlockMode::GCM:
|
||||
case BlockMode::CTR:
|
||||
ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
|
||||
EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
|
||||
params.push_back(TAG_NONCE, iv.value());
|
||||
ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
|
||||
EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
|
||||
params.push_back(TAG_NONCE, iv->get());
|
||||
break;
|
||||
|
||||
case BlockMode::ECB:
|
||||
EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
|
||||
EXPECT_FALSE(iv) << "ECB mode should not generate IV";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2649,9 +2652,9 @@ TEST_P(EncryptionOperationsTest, AesCallerNonce) {
|
|||
AuthorizationSet out_params;
|
||||
string ciphertext = EncryptMessage(message, params, &out_params);
|
||||
EXPECT_EQ(message.size(), ciphertext.size());
|
||||
EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
|
||||
EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE)->get().size());
|
||||
|
||||
params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
|
||||
params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE)->get());
|
||||
string plaintext = DecryptMessage(ciphertext, params);
|
||||
EXPECT_EQ(message, plaintext);
|
||||
|
||||
|
@ -2697,9 +2700,9 @@ TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
|
|||
AuthorizationSet out_params;
|
||||
string ciphertext = EncryptMessage(message, params, &out_params);
|
||||
EXPECT_EQ(message.size(), ciphertext.size());
|
||||
EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
|
||||
EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE)->get().size());
|
||||
|
||||
params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
|
||||
params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE)->get());
|
||||
string plaintext = DecryptMessage(ciphertext, params);
|
||||
EXPECT_EQ(message, plaintext);
|
||||
|
||||
|
@ -2893,7 +2896,7 @@ TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
|
|||
AuthorizationSet begin_out_params;
|
||||
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
|
||||
EXPECT_EQ(1U, begin_out_params.size());
|
||||
ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
|
||||
ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE));
|
||||
|
||||
AuthorizationSet finish_out_params;
|
||||
string ciphertext;
|
||||
|
|
|
@ -106,10 +106,11 @@ bool AuthorizationSet::erase(int index) {
|
|||
return false;
|
||||
}
|
||||
|
||||
NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
|
||||
std::optional<std::reference_wrapper<const KeyParameter>> AuthorizationSet::GetEntry(
|
||||
Tag tag) const {
|
||||
int pos = find(tag);
|
||||
if (pos == -1) return {};
|
||||
return data_[pos];
|
||||
return std::reference_wrapper(data_[pos]);
|
||||
}
|
||||
|
||||
AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
|
||||
|
|
|
@ -168,7 +168,7 @@ class AuthorizationSet {
|
|||
bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
|
||||
for (const auto& param : data_) {
|
||||
auto entry = authorizationValue(ttag, param);
|
||||
if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
|
||||
if (entry && static_cast<ValueT>(*entry) == value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -178,9 +178,9 @@ class AuthorizationSet {
|
|||
size_t GetTagCount(Tag tag) const;
|
||||
|
||||
template <typename T>
|
||||
inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
|
||||
inline auto GetTagValue(T tag) const -> decltype(authorizationValue(tag, KeyParameter())) {
|
||||
auto entry = GetEntry(tag);
|
||||
if (entry.isOk()) return authorizationValue(tag, entry.value());
|
||||
if (entry) return authorizationValue(tag, *entry);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ class AuthorizationSet {
|
|||
}
|
||||
|
||||
private:
|
||||
NullOr<const KeyParameter&> GetEntry(Tag tag) const;
|
||||
std::optional<std::reference_wrapper<const KeyParameter>> GetEntry(Tag tag) const;
|
||||
|
||||
std::vector<KeyParameter> data_;
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) {
|
|||
}
|
||||
|
||||
template <typename ValueT>
|
||||
::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
|
||||
::std::ostream& operator<<(::std::ostream& os, const std::optional<ValueT>& value) {
|
||||
if (!value.isOk()) {
|
||||
os << "(value not present)";
|
||||
} else {
|
||||
|
|
|
@ -58,6 +58,10 @@ struct Tag2TypedTag {
|
|||
typedef TypedTag<typeFromTag(tag), tag> type;
|
||||
};
|
||||
|
||||
#ifdef DECLARE_TYPED_TAG
|
||||
#undef DECLARE_TYPED_TAG
|
||||
#endif
|
||||
|
||||
#define DECLARE_TYPED_TAG(name) \
|
||||
typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
|
||||
static TAG_##name##_t TAG_##name;
|
||||
|
@ -72,9 +76,12 @@ DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
|
|||
DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_IMEI);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_MEID);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL);
|
||||
DECLARE_TYPED_TAG(ATTESTATION_ID_SERIAL);
|
||||
DECLARE_TYPED_TAG(AUTH_TIMEOUT);
|
||||
DECLARE_TYPED_TAG(BLOCK_MODE);
|
||||
DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
|
||||
|
@ -118,6 +125,8 @@ DECLARE_TYPED_TAG(USER_ID);
|
|||
DECLARE_TYPED_TAG(USER_SECURE_ID);
|
||||
DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL);
|
||||
|
||||
#undef DECLARE_TYPED_TAG
|
||||
|
||||
template <typename... Elems>
|
||||
struct MetaList {};
|
||||
|
||||
|
@ -133,6 +142,7 @@ using all_tags_t = MetaList<
|
|||
TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
|
||||
TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t,
|
||||
TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t,
|
||||
TAG_ATTESTATION_ID_SERIAL_t, TAG_ATTESTATION_ID_IMEI_t, TAG_ATTESTATION_ID_MEID_t,
|
||||
TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t,
|
||||
TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t,
|
||||
TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t,
|
||||
|
@ -141,21 +151,39 @@ using all_tags_t = MetaList<
|
|||
template <typename TypedTagType>
|
||||
struct TypedTag2ValueType;
|
||||
|
||||
#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
|
||||
template <Tag tag> \
|
||||
struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
|
||||
using type = std::remove_reference<decltype( \
|
||||
static_cast<KeyParameterValue*>(nullptr) \
|
||||
->get<KeyParameterValue::field_name>())>::type; \
|
||||
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \
|
||||
}; \
|
||||
template <Tag tag> \
|
||||
inline auto& accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) { \
|
||||
return param.value.get<KeyParameterValue::field_name>(); \
|
||||
} \
|
||||
template <Tag tag> \
|
||||
inline auto& accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) { \
|
||||
return param.value.get<KeyParameterValue::field_name>(); \
|
||||
#ifdef MAKE_TAG_VALUE_ACCESSOR
|
||||
#undef MAKE_TAG_VALUE_ACCESSOR
|
||||
#endif
|
||||
|
||||
#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
|
||||
template <Tag tag> \
|
||||
struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
|
||||
using type = std::remove_reference< \
|
||||
decltype(static_cast<KeyParameterValue*>(nullptr) \
|
||||
->get<KeyParameterValue::field_name>())>::type; \
|
||||
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \
|
||||
}; \
|
||||
template <Tag tag> \
|
||||
inline std::optional<std::reference_wrapper< \
|
||||
const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>> \
|
||||
accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) { \
|
||||
if (param.value.getTag() == KeyParameterValue::field_name) { \
|
||||
return std::optional( \
|
||||
std::reference_wrapper(param.value.get<KeyParameterValue::field_name>())); \
|
||||
} else { \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
} \
|
||||
template <Tag tag> \
|
||||
inline std::optional< \
|
||||
std::reference_wrapper<typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>> \
|
||||
accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) { \
|
||||
if (param.value.getTag() == KeyParameterValue::field_name) { \
|
||||
return std::optional( \
|
||||
std::reference_wrapper(param.value.get<KeyParameterValue::field_name>())); \
|
||||
} else { \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, longInteger)
|
||||
|
@ -167,19 +195,39 @@ MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, 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<decltype(typed_tag)> { \
|
||||
using type = std::remove_reference<decltype( \
|
||||
static_cast<KeyParameterValue*>(nullptr) \
|
||||
->get<KeyParameterValue::field_name>())>::type; \
|
||||
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \
|
||||
}; \
|
||||
inline auto& accessTagValue(decltype(typed_tag), const KeyParameter& param) { \
|
||||
return param.value.get<KeyParameterValue::field_name>(); \
|
||||
} \
|
||||
inline auto& accessTagValue(decltype(typed_tag), KeyParameter& param) { \
|
||||
return param.value.get<KeyParameterValue::field_name>(); \
|
||||
#undef MAKE_TAG_VALUE_ACCESSOR
|
||||
|
||||
#ifdef MAKE_TAG_ENUM_VALUE_ACCESSOR
|
||||
#undef MAKE_TAG_ENUM_VALUE_ACCESSOR
|
||||
#endif
|
||||
|
||||
#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \
|
||||
template <> \
|
||||
struct TypedTag2ValueType<decltype(typed_tag)> { \
|
||||
using type = std::remove_reference< \
|
||||
decltype(static_cast<KeyParameterValue*>(nullptr) \
|
||||
->get<KeyParameterValue::field_name>())>::type; \
|
||||
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \
|
||||
}; \
|
||||
inline std::optional< \
|
||||
std::reference_wrapper<const typename TypedTag2ValueType<decltype(typed_tag)>::type>> \
|
||||
accessTagValue(decltype(typed_tag), const KeyParameter& param) { \
|
||||
if (param.value.getTag() == KeyParameterValue::field_name) { \
|
||||
return std::optional( \
|
||||
std::reference_wrapper(param.value.get<KeyParameterValue::field_name>())); \
|
||||
} else { \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
} \
|
||||
inline std::optional< \
|
||||
std::reference_wrapper<typename TypedTag2ValueType<decltype(typed_tag)>::type>> \
|
||||
accessTagValue(decltype(typed_tag), KeyParameter& param) { \
|
||||
if (param.value.getTag() == KeyParameterValue::field_name) { \
|
||||
return std::optional( \
|
||||
std::reference_wrapper(param.value.get<KeyParameterValue::field_name>())); \
|
||||
} else { \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, algorithm)
|
||||
|
@ -192,6 +240,8 @@ MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, keyPurpose)
|
|||
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, hardwareAuthenticatorType)
|
||||
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, securityLevel)
|
||||
|
||||
#undef MAKE_TAG_ENUM_VALUE_ACCESSOR
|
||||
|
||||
template <TagType tag_type, Tag tag, typename ValueT>
|
||||
inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
|
||||
KeyParameter retval;
|
||||
|
@ -210,6 +260,14 @@ inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
|
|||
return retval;
|
||||
}
|
||||
|
||||
// the invalid case
|
||||
inline KeyParameter makeKeyParameter(TypedTag<TagType::INVALID, Tag::INVALID>) {
|
||||
KeyParameter retval;
|
||||
retval.tag = Tag::INVALID;
|
||||
retval.value = KeyParameterValue::make<KeyParameterValue::invalid>(0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename... Pack>
|
||||
struct FirstOrNoneHelper;
|
||||
template <typename First>
|
||||
|
@ -240,88 +298,31 @@ inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args)
|
|||
return makeKeyParameter(ttag, std::forward<Args>(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.
|
||||
*
|
||||
* TODO(seleneh) replace this with std::optional.
|
||||
*/
|
||||
template <typename ValueT>
|
||||
class NullOr {
|
||||
using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value,
|
||||
std::remove_reference_t<ValueT>*, ValueT>;
|
||||
|
||||
struct pointer_initializer {
|
||||
static std::nullptr_t init() { return nullptr; }
|
||||
};
|
||||
struct value_initializer {
|
||||
static ValueT init() { return ValueT(); }
|
||||
};
|
||||
struct value_pointer_deref_t {
|
||||
static ValueT& deref(ValueT& v) { return v; }
|
||||
};
|
||||
struct reference_deref_t {
|
||||
static auto& deref(internal_t v) { return *v; }
|
||||
};
|
||||
using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value ||
|
||||
std::is_pointer<ValueT>::value,
|
||||
pointer_initializer, value_initializer>;
|
||||
using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t,
|
||||
value_pointer_deref_t>;
|
||||
|
||||
public:
|
||||
NullOr() : value_(initializer_t::init()), null_(true) {}
|
||||
template <typename T>
|
||||
NullOr(T&& value, typename std::enable_if<
|
||||
!std::is_lvalue_reference<ValueT>::value &&
|
||||
std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
|
||||
int>::type = 0)
|
||||
: value_(std::forward<ValueT>(value)), null_(false) {}
|
||||
template <typename T>
|
||||
NullOr(T& value, typename std::enable_if<
|
||||
std::is_lvalue_reference<ValueT>::value &&
|
||||
std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
|
||||
int>::type = 0)
|
||||
: value_(&value), null_(false) {}
|
||||
|
||||
bool isOk() const { return !null_; }
|
||||
|
||||
const ValueT& value() const& { return deref_t::deref(value_); }
|
||||
ValueT& value() & { return deref_t::deref(value_); }
|
||||
ValueT&& value() && { return std::move(deref_t::deref(value_)); }
|
||||
|
||||
private:
|
||||
internal_t value_;
|
||||
bool null_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::remove_reference_t<T> NullOrOr(T&& v) {
|
||||
if (v.isOk()) return v;
|
||||
if (v) return v;
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
|
||||
if (head.isOk()) return head;
|
||||
if (head) return head;
|
||||
return NullOrOr(std::forward<Tail>(tail)...);
|
||||
}
|
||||
|
||||
template <typename Default, typename Wrapped>
|
||||
std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
|
||||
std::remove_reference_t<Wrapped> defaultOr(std::optional<Wrapped>&& optional, Default&& def) {
|
||||
static_assert(std::is_convertible<std::remove_reference_t<Default>,
|
||||
std::remove_reference_t<Wrapped>>::value,
|
||||
"Type of default value must match the type wrapped by NullOr");
|
||||
if (optional.isOk()) return optional.value();
|
||||
"Type of default value must match the type wrapped by std::optional");
|
||||
if (optional) return *optional;
|
||||
return def;
|
||||
}
|
||||
|
||||
template <TagType tag_type, Tag tag>
|
||||
inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
|
||||
TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
|
||||
inline std::optional<
|
||||
std::reference_wrapper<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>>
|
||||
authorizationValue(TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
|
||||
if (TypedTag2ValueType<TypedTag<tag_type, tag>>::unionTag != param.value.getTag()) return {};
|
||||
return accessTagValue(ttag, param);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue