From 2e95fa2bdc64effa076181c3a1e7169b5becd798 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Tue, 9 Aug 2022 19:01:49 +0000 Subject: [PATCH] hidl2aidl: conversion of vts confirmationui hidl to aidl Conversion of the vts confirmationui tests from hidl to aidl. Bug: b/205760172 Test: run vts -m VtsHalConfirmationUIV1_0Target Change-Id: I0af2ec46916d629dd3aace20c4858ffc7ad830e3 --- confirmationui/aidl/vts/functional/Android.bp | 45 ++ .../VtsHalConfirmationUITargetTest.cpp | 535 ++++++++++++++++++ 2 files changed, 580 insertions(+) create mode 100644 confirmationui/aidl/vts/functional/Android.bp create mode 100644 confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp diff --git a/confirmationui/aidl/vts/functional/Android.bp b/confirmationui/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..3649c871fa --- /dev/null +++ b/confirmationui/aidl/vts/functional/Android.bp @@ -0,0 +1,45 @@ +// +// Copyright (C) 2022 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. +// + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_test { + name: "VtsHalConfirmationUITargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "keymint_use_latest_hal_aidl_ndk_shared", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "VtsHalConfirmationUITargetTest.cpp", + ], + static_libs: [ + "android.hardware.confirmationui-V1-ndk", + "libcn-cbor", + "android.hardware.confirmationui-support-lib", + ], + shared_libs: [ + "libbinder_ndk", + "libcrypto", + ], + test_suites: [ + "general-tests", + "vts", + ], +} diff --git a/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp new file mode 100644 index 0000000000..bf1f1c890c --- /dev/null +++ b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2022 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. + */ + +#define LOG_TAG "ConfirmationIOAidlHalTest" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +static constexpr int TIMEOUT_PERIOD = 10; + +namespace aidl::android::hardware::confirmationui::test { +using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType; +using ::aidl::android::hardware::security::keymint::HardwareAuthToken; +using ::android::hardware::confirmationui::support::auth_token_key_t; +using ::android::hardware::confirmationui::support::ByteBufferProxy; +using ::android::hardware::confirmationui::support::HMac; +using ::android::hardware::confirmationui::support::hmac_t; +using ::android::hardware::confirmationui::support::hton; +using ::android::hardware::confirmationui::support::NullOr; +using std::shared_ptr; +using std::string; +using std::vector; + +namespace { +const auth_token_key_t testKey(static_cast(IConfirmationUI::TEST_KEY_BYTE)); + +class HMacImplementation { + public: + static NullOr hmac256(const auth_token_key_t& key, + std::initializer_list buffers) { + HMAC_CTX hmacCtx; + HMAC_CTX_init(&hmacCtx); + if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) { + return {}; + } + for (auto& buffer : buffers) { + if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) { + return {}; + } + } + hmac_t result; + if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) { + return {}; + } + return result; + } +}; + +using HMacer = HMac; + +template +vector testHMAC(const Data&... data) { + auto hmac = HMacer::hmac256(testKey, data...); + if (!hmac.isOk()) { + ADD_FAILURE() << "Failed to compute test hmac. This is a self-test error."; + return {}; + } + vector result(hmac.value().size()); + std::copy(hmac.value().data(), hmac.value().data() + hmac.value().size(), result.data()); + return result; +} + +template +auto toBytes(const T& v) -> const uint8_t (&)[sizeof(T)] { + return *reinterpret_cast(&v); +} + +HardwareAuthToken makeTestToken(const TestModeCommands command, uint64_t timestamp = 0) { + HardwareAuthToken auth_token; + auth_token.challenge = static_cast(command); + auth_token.userId = 0; + auth_token.authenticatorId = 0; + auth_token.authenticatorType = HardwareAuthenticatorType::NONE; + auth_token.timestamp = {static_cast(timestamp)}; + + // Canonical form of auth-token v0 + // version (1 byte) + // challenge (8 bytes) + // user_id (8 bytes) + // authenticator_id (8 bytes) + // authenticator_type (4 bytes) + // timestamp (8 bytes) + // total 37 bytes + auth_token.mac = testHMAC("\0", + toBytes(auth_token.challenge), // + toBytes(auth_token.userId), // + toBytes(auth_token.authenticatorId), // + toBytes(hton(auth_token.authenticatorType)), // + toBytes(hton(auth_token.timestamp))); // + + return auth_token; +} + +#define DEBUG_CONFRIMATIONUI_UTILS_TEST + +#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST +std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) { + for (size_t i = 0; i < size; ++i) { + uint8_t byte = data[i]; + out << std::hex << std::setw(2) << std::setfill('0') << (unsigned)byte; + switch (i & 0xf) { + case 0xf: + out << "\n"; + break; + case 7: + out << " "; + break; + default: + out << " "; + break; + } + } + return out; +} +#endif + +constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +std::string hex2str(std::string a) { + std::string b; + size_t num = a.size() / 2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + +int getReturnCode(const ::ndk::ScopedAStatus& result) { + if (result.isOk()) return IConfirmationUI::OK; + + if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) { + return static_cast(result.getServiceSpecificError()); + } + return result.getStatus(); +} + +} // namespace + +class ConfirmationUIAidlTest : public ::testing::TestWithParam { + public: + void TearDown() override { confirmator_->abort(); } + void SetUp() override { + std::string name = GetParam(); + ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name; + ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str())); + ASSERT_NE(binder, nullptr); + confirmator_ = IConfirmationUI::fromBinder(binder); + ASSERT_NE(confirmator_, nullptr); + } + + // Used as a mechanism to inform the test about data/event callback + inline void notify() { + std::unique_lock lock(mtx_); + cv_.notify_one(); + } + + // Test code calls this function to wait for data/event callback + inline std::cv_status wait() { + std::unique_lock lock(mtx_); + auto now = std::chrono::system_clock::now(); + std::cv_status status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + return status; + } + + protected: + shared_ptr confirmator_; + + private: + // synchronization objects + std::mutex mtx_; + std::condition_variable cv_; +}; + +class ConfirmationTestCallback + : public ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback { + public: + ConfirmationTestCallback(ConfirmationUIAidlTest& parent) : parent_(parent){}; + virtual ~ConfirmationTestCallback() = default; + + ::ndk::ScopedAStatus result(int32_t err, const vector& msg, + const vector& confToken) override { + error_ = err; + formattedMessage_ = msg; + confirmationToken_ = confToken; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + + bool verifyConfirmationToken() { + static constexpr char confirmationPrefix[] = "confirmation token"; + EXPECT_EQ(32U, confirmationToken_.size()); + return 32U == confirmationToken_.size() && + !memcmp(confirmationToken_.data(), + testHMAC(confirmationPrefix, formattedMessage_).data(), 32); + } + + int error_; + vector formattedMessage_; + vector confirmationToken_; + + private: + ConfirmationUIAidlTest& parent_; +}; + +struct CnCborDeleter { + void operator()(cn_cbor* ptr) { cn_cbor_free(ptr); } +}; + +typedef std::unique_ptr CnCborPtr; + +// Simulates the User taping Ok +TEST_P(ConfirmationUIAidlTest, UserOkTest) { + static constexpr char test_prompt[] = "Me first, gimme gimme!"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk()); + // Simulate the user taping ok. + ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::OK_EVENT)) + .isOk()); + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::OK, conf_cb->error_); + + ASSERT_TRUE(conf_cb->verifyConfirmationToken()); + + cn_cbor_errback cn_cbor_error; + auto parsed_message = CnCborPtr(cn_cbor_decode( + conf_cb->formattedMessage_.data(), conf_cb->formattedMessage_.size(), &cn_cbor_error)); + // is parsable CBOR + ASSERT_TRUE(parsed_message.get()); + // is a map + ASSERT_EQ(CN_CBOR_MAP, parsed_message->type); + + // the message must have exactly 2 key value pairs. + // cn_cbor holds 2* in the length field + ASSERT_EQ(4, parsed_message->length); + // map has key "prompt" + auto prompt = cn_cbor_mapget_string(parsed_message.get(), "prompt"); + ASSERT_TRUE(prompt); + ASSERT_EQ(CN_CBOR_TEXT, prompt->type); + ASSERT_EQ(22, prompt->length); + ASSERT_EQ(0, memcmp(test_prompt, prompt->v.str, 22)); + // map has key "extra" + auto extra_out = cn_cbor_mapget_string(parsed_message.get(), "extra"); + ASSERT_TRUE(extra_out); + ASSERT_EQ(CN_CBOR_BYTES, extra_out->type); + ASSERT_EQ(3, extra_out->length); + ASSERT_EQ(0, memcmp(test_extra, extra_out->v.bytes, 3)); +} + +// Initiates a confirmation prompt with a message that is too long +TEST_P(ConfirmationUIAidlTest, MessageTooLongTest) { + static constexpr uint8_t test_extra[IConfirmationUI::MAX_MESSAGE_SIZE] = {}; + static constexpr char test_prompt[] = "D\'oh!"; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + sizeof(test_extra)); + auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}); + ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result)); +} + +// If the message gets very long some HAL implementations might fail even before the message +// reaches the trusted app implementation. But the HAL must still diagnose the correct error. +TEST_P(ConfirmationUIAidlTest, MessageWayTooLongTest) { + static constexpr uint8_t test_extra[(IConfirmationUI::MAX_MESSAGE_SIZE)*10] = {}; + static constexpr char test_prompt[] = "D\'oh!"; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + sizeof(test_extra)); + auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}); + ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result)); +} + +// Simulates the User tapping the Cancel +TEST_P(ConfirmationUIAidlTest, UserCancelTest) { + static constexpr char test_prompt[] = "Me first, gimme gimme!"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk()); + + // Simulate the user taping ok. + ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::CANCEL_EVENT)) + .isOk()); + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::CANCELED, conf_cb->error_); + + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Simulates the framework cancelling an ongoing prompt +TEST_P(ConfirmationUIAidlTest, AbortTest) { + static constexpr char test_prompt[] = "Me first, gimme gimme!"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk()); + + confirmator_->abort(); + + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_); + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Tests if the confirmation dialog can successfully render 100 'W' characters as required by +// the design guidelines. +TEST_P(ConfirmationUIAidlTest, PortableMessageTest1) { + static constexpr char test_prompt[] = + "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW" + "WWWWWWWWWWWWWW"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk()); + + confirmator_->abort(); + + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_); + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Tests if the confirmation dialog can successfully render 100 'W' characters as required by +// the design guidelines in magnified mode. +TEST_P(ConfirmationUIAidlTest, PortableMessageTest1Magnified) { + static constexpr char test_prompt[] = + "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW" + "WWWWWWWWWWWWWW"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_ + ->promptUserConfirmation(conf_cb, prompt_text, extra, "en", + {UIOption::ACCESSIBILITY_MAGNIFIED}) + .isOk()); + + confirmator_->abort(); + + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_); + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as +// required by the design guidelines. +TEST_P(ConfirmationUIAidlTest, PortableMessageTest2) { + static constexpr char test_prompt[] = + "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW " + "WWWWWWWWWWWW WWWWWWWWWWWW"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk()); + + confirmator_->abort(); + + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_); + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as +// required by the design guidelines in magnified mode. +TEST_P(ConfirmationUIAidlTest, PortableMessageTest2Magnified) { + static constexpr char test_prompt[] = + "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW " + "WWWWWWWWWWWW WWWWWWWWWWWW"; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + ASSERT_TRUE(confirmator_ + ->promptUserConfirmation(conf_cb, prompt_text, extra, "en", + {UIOption::ACCESSIBILITY_MAGNIFIED}) + .isOk()); + + confirmator_->abort(); + + // Wait for the callback. + EXPECT_EQ(std::cv_status::no_timeout, wait()); + ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_); + ASSERT_EQ(0U, conf_cb->confirmationToken_.size()); + ASSERT_EQ(0U, conf_cb->formattedMessage_.size()); +} + +// Passing malformed UTF-8 to the confirmation UI +// This test passes a string that ends in the middle of a multibyte character +TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test1) { + static constexpr char test_prompt[] = {char(0xc0), 0}; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}); + ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result)); +} + +// Passing malformed UTF-8 to the confirmation UI +// This test passes a string with a 5-byte character. +TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test2) { + static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82), + char(0x82), char(0x82), 0}; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}); + ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result)); +} + +// Passing malformed UTF-8 to the confirmation UI +// This test passes a string with a 2-byte character followed by a stray non UTF-8 character. +TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test3) { + static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0}; + static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3}; + shared_ptr conf_cb = + ::ndk::SharedRefBase::make(*this); + vector prompt_text(test_prompt, test_prompt + sizeof(test_prompt)); + vector extra(test_extra, test_extra + 3); + auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}); + ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result)); +} + +// Test the implementation of HMAC SHA 256 against a golden blob. +TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) { + const char key_str[32] = "keykeykeykeykeykeykeykeykeykeyk"; + const uint8_t(&key)[32] = *reinterpret_cast(key_str); + auto expected = hex2str("2377fbcaa7fb3f6c20cfa1d9ebc60e9922cf58c909e25e300f3cb57f7805c886"); + auto result = HMacer::hmac256(key, "value1", "value2", "value3"); + +#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST + hexdump(std::cout, reinterpret_cast(expected.data()), 32) << std::endl; + hexdump(std::cout, result.value().data(), 32) << std::endl; +#endif + + ByteBufferProxy expected_bytes(expected); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(expected, result.value()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ConfirmationUIAidlTest); +INSTANTIATE_TEST_SUITE_P( + PerInstance, ConfirmationUIAidlTest, + testing::ValuesIn(::android::getAidlHalInstanceNames(IConfirmationUI::descriptor)), + ::android::PrintInstanceNameToString); + +} // namespace aidl::android::hardware::confirmationui::test + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +}