Merge "Revise keymint_tags.h" am: 2528ddcab2

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1533203

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I4a03d4caa6a7641ede077511a3cc6da7e55475bd
This commit is contained in:
Treehugger Robot
2020-12-21 18:41:30 +00:00
committed by Automerger Merge Worker
6 changed files with 122 additions and 117 deletions

View File

@@ -577,8 +577,8 @@ string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode bloc
string ciphertext = EncryptMessage(message, params, &out_params); string ciphertext = EncryptMessage(message, params, &out_params);
EXPECT_EQ(1U, out_params.size()); EXPECT_EQ(1U, out_params.size());
auto ivVal = out_params.GetTagValue(TAG_NONCE); auto ivVal = out_params.GetTagValue(TAG_NONCE);
EXPECT_TRUE(ivVal.isOk()); EXPECT_TRUE(ivVal);
if (ivVal.isOk()) *iv_out = ivVal.value(); if (ivVal) *iv_out = *ivVal;
return ciphertext; return ciphertext;
} }

View File

@@ -80,7 +80,10 @@ namespace {
template <TagType tag_type, Tag tag, typename ValueT> template <TagType tag_type, Tag tag, typename ValueT>
bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) { 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) { 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()); return (it != set.end());
} }
@@ -251,10 +254,10 @@ class NewKeyGenerationTest : public KeyMintAidlTestBase {
EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version())) EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
<< "OS version is " << os_version() << " key reported " << "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())) EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
<< "OS patch level is " << os_patch_level() << " key reported " << "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) { vector<uint8_t> CopyIv(const AuthorizationSet& set) {
auto iv = set.GetTagValue(TAG_NONCE); auto iv = set.GetTagValue(TAG_NONCE);
EXPECT_TRUE(iv.isOk()); EXPECT_TRUE(iv);
return iv.value(); return iv->get();
} }
/* /*
@@ -2459,13 +2462,13 @@ TEST_P(EncryptionOperationsTest, AesIncremental) {
case BlockMode::CBC: case BlockMode::CBC:
case BlockMode::GCM: case BlockMode::GCM:
case BlockMode::CTR: case BlockMode::CTR:
ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode; ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size()); EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
params.push_back(TAG_NONCE, iv.value()); params.push_back(TAG_NONCE, iv->get());
break; break;
case BlockMode::ECB: case BlockMode::ECB:
EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV"; EXPECT_FALSE(iv) << "ECB mode should not generate IV";
break; break;
} }
@@ -2649,9 +2652,9 @@ TEST_P(EncryptionOperationsTest, AesCallerNonce) {
AuthorizationSet out_params; AuthorizationSet out_params;
string ciphertext = EncryptMessage(message, params, &out_params); string ciphertext = EncryptMessage(message, params, &out_params);
EXPECT_EQ(message.size(), ciphertext.size()); 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); string plaintext = DecryptMessage(ciphertext, params);
EXPECT_EQ(message, plaintext); EXPECT_EQ(message, plaintext);
@@ -2697,9 +2700,9 @@ TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
AuthorizationSet out_params; AuthorizationSet out_params;
string ciphertext = EncryptMessage(message, params, &out_params); string ciphertext = EncryptMessage(message, params, &out_params);
EXPECT_EQ(message.size(), ciphertext.size()); 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); string plaintext = DecryptMessage(ciphertext, params);
EXPECT_EQ(message, plaintext); EXPECT_EQ(message, plaintext);
@@ -2893,7 +2896,7 @@ TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
AuthorizationSet begin_out_params; AuthorizationSet begin_out_params;
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params)); EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
EXPECT_EQ(1U, begin_out_params.size()); 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; AuthorizationSet finish_out_params;
string ciphertext; string ciphertext;

View File

@@ -106,10 +106,11 @@ bool AuthorizationSet::erase(int index) {
return false; 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); int pos = find(tag);
if (pos == -1) return {}; if (pos == -1) return {};
return data_[pos]; return std::reference_wrapper(data_[pos]);
} }
AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,

View File

@@ -168,7 +168,7 @@ class AuthorizationSet {
bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const { bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
for (const auto& param : data_) { for (const auto& param : data_) {
auto entry = authorizationValue(ttag, param); 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; return false;
} }
@@ -178,9 +178,9 @@ class AuthorizationSet {
size_t GetTagCount(Tag tag) const; size_t GetTagCount(Tag tag) const;
template <typename T> 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); auto entry = GetEntry(tag);
if (entry.isOk()) return authorizationValue(tag, entry.value()); if (entry) return authorizationValue(tag, *entry);
return {}; return {};
} }
@@ -219,7 +219,7 @@ class AuthorizationSet {
} }
private: private:
NullOr<const KeyParameter&> GetEntry(Tag tag) const; std::optional<std::reference_wrapper<const KeyParameter>> GetEntry(Tag tag) const;
std::vector<KeyParameter> data_; std::vector<KeyParameter> data_;
}; };

View File

@@ -71,7 +71,7 @@ inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) {
} }
template <typename ValueT> 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()) { if (!value.isOk()) {
os << "(value not present)"; os << "(value not present)";
} else { } else {

View File

@@ -58,6 +58,10 @@ struct Tag2TypedTag {
typedef TypedTag<typeFromTag(tag), tag> type; typedef TypedTag<typeFromTag(tag), tag> type;
}; };
#ifdef DECLARE_TYPED_TAG
#undef DECLARE_TYPED_TAG
#endif
#define DECLARE_TYPED_TAG(name) \ #define DECLARE_TYPED_TAG(name) \
typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \ typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
static TAG_##name##_t TAG_##name; 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_CHALLENGE);
DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND); DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND);
DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE); 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_MANUFACTURER);
DECLARE_TYPED_TAG(ATTESTATION_ID_MEID);
DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL); DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL);
DECLARE_TYPED_TAG(ATTESTATION_ID_SERIAL);
DECLARE_TYPED_TAG(AUTH_TIMEOUT); DECLARE_TYPED_TAG(AUTH_TIMEOUT);
DECLARE_TYPED_TAG(BLOCK_MODE); DECLARE_TYPED_TAG(BLOCK_MODE);
DECLARE_TYPED_TAG(BOOTLOADER_ONLY); DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
@@ -118,6 +125,8 @@ DECLARE_TYPED_TAG(USER_ID);
DECLARE_TYPED_TAG(USER_SECURE_ID); DECLARE_TYPED_TAG(USER_SECURE_ID);
DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL); DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL);
#undef DECLARE_TYPED_TAG
template <typename... Elems> template <typename... Elems>
struct MetaList {}; 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_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_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_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_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_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, 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> template <typename TypedTagType>
struct TypedTag2ValueType; struct TypedTag2ValueType;
#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ #ifdef MAKE_TAG_VALUE_ACCESSOR
template <Tag tag> \ #undef MAKE_TAG_VALUE_ACCESSOR
struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \ #endif
using type = std::remove_reference<decltype( \
static_cast<KeyParameterValue*>(nullptr) \ #define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
->get<KeyParameterValue::field_name>())>::type; \ template <Tag tag> \
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \ struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
}; \ using type = std::remove_reference< \
template <Tag tag> \ decltype(static_cast<KeyParameterValue*>(nullptr) \
inline auto& accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) { \ ->get<KeyParameterValue::field_name>())>::type; \
return param.value.get<KeyParameterValue::field_name>(); \ static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \
} \ }; \
template <Tag tag> \ template <Tag tag> \
inline auto& accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) { \ inline std::optional<std::reference_wrapper< \
return param.value.get<KeyParameterValue::field_name>(); \ 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) 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::BYTES, blob)
MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ #undef MAKE_TAG_VALUE_ACCESSOR
template <> \
struct TypedTag2ValueType<decltype(typed_tag)> { \ #ifdef MAKE_TAG_ENUM_VALUE_ACCESSOR
using type = std::remove_reference<decltype( \ #undef MAKE_TAG_ENUM_VALUE_ACCESSOR
static_cast<KeyParameterValue*>(nullptr) \ #endif
->get<KeyParameterValue::field_name>())>::type; \
static constexpr KeyParameterValue::Tag unionTag = KeyParameterValue::field_name; \ #define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \
}; \ template <> \
inline auto& accessTagValue(decltype(typed_tag), const KeyParameter& param) { \ struct TypedTag2ValueType<decltype(typed_tag)> { \
return param.value.get<KeyParameterValue::field_name>(); \ using type = std::remove_reference< \
} \ decltype(static_cast<KeyParameterValue*>(nullptr) \
inline auto& accessTagValue(decltype(typed_tag), KeyParameter& param) { \ ->get<KeyParameterValue::field_name>())>::type; \
return param.value.get<KeyParameterValue::field_name>(); \ 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) 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_USER_AUTH_TYPE, hardwareAuthenticatorType)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, securityLevel) MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, securityLevel)
#undef MAKE_TAG_ENUM_VALUE_ACCESSOR
template <TagType tag_type, Tag tag, typename ValueT> template <TagType tag_type, Tag tag, typename ValueT>
inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) { inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
KeyParameter retval; KeyParameter retval;
@@ -210,6 +260,14 @@ inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
return retval; 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> template <typename... Pack>
struct FirstOrNoneHelper; struct FirstOrNoneHelper;
template <typename First> template <typename First>
@@ -240,88 +298,31 @@ inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args)
return makeKeyParameter(ttag, std::forward<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> template <typename T>
std::remove_reference_t<T> NullOrOr(T&& v) { std::remove_reference_t<T> NullOrOr(T&& v) {
if (v.isOk()) return v; if (v) return v;
return {}; return {};
} }
template <typename Head, typename... Tail> template <typename Head, typename... Tail>
std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... 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)...); return NullOrOr(std::forward<Tail>(tail)...);
} }
template <typename Default, typename Wrapped> 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>, static_assert(std::is_convertible<std::remove_reference_t<Default>,
std::remove_reference_t<Wrapped>>::value, std::remove_reference_t<Wrapped>>::value,
"Type of default value must match the type wrapped by NullOr"); "Type of default value must match the type wrapped by std::optional");
if (optional.isOk()) return optional.value(); if (optional) return *optional;
return def; return def;
} }
template <TagType tag_type, Tag tag> template <TagType tag_type, Tag tag>
inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue( inline std::optional<
TypedTag<tag_type, tag> ttag, const KeyParameter& param) { 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 {}; if (TypedTag2ValueType<TypedTag<tag_type, tag>>::unionTag != param.value.getTag()) return {};
return accessTagValue(ttag, param); return accessTagValue(ttag, param);
} }