diff options
author | Scott Lobdell <slobdell@google.com> | 2021-02-23 11:55:14 -0800 |
---|---|---|
committer | Scott Lobdell <slobdell@google.com> | 2021-02-23 11:55:14 -0800 |
commit | 86bfa300dfbcf500ad04bede19a2b5f0e6d418b9 (patch) | |
tree | 0b635f8b37f8adf728064d7615f4bba25b51e418 /security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp | |
parent | 7b82a0f697d0cf832803a80f7ed2128002b54dec (diff) | |
parent | f6fd33b5fdc12948537d800af8695ff6767039c2 (diff) |
Merge SP1A.210222.001
Change-Id: I49bafb9c4e7adcb330e0e4c01111788b6ed84a00
Diffstat (limited to 'security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp')
-rw-r--r-- | security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp new file mode 100644 index 0000000000..9ca1ee8af1 --- /dev/null +++ b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020 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 "secureclock_test" +#include <android-base/logging.h> + +#include <aidl/Gtest.h> +#include <aidl/Vintf.h> +#include <aidl/android/hardware/security/keymint/ErrorCode.h> +#include <aidl/android/hardware/security/secureclock/ISecureClock.h> +#include <android/binder_manager.h> +#include <binder/ProcessState.h> +#include <gtest/gtest.h> +#include <vector> + +namespace aidl::android::hardware::security::secureclock::test { +using Status = ::ndk::ScopedAStatus; +using ::aidl::android::hardware::security::keymint::ErrorCode; +using ::std::shared_ptr; +using ::std::string; +using ::std::vector; + +class SecureClockAidlTest : public ::testing::TestWithParam<string> { + public: + struct TimestampTokenResult { + ErrorCode error; + TimeStampToken token; + }; + + TimestampTokenResult getTimestampToken(int64_t in_challenge) { + TimestampTokenResult result; + result.error = + GetReturnErrorCode(secureClock_->generateTimeStamp(in_challenge, &result.token)); + return result; + } + + uint64_t getTime() { + struct timespec timespec; + EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, ×pec)); + return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000; + } + + int sleep_ms(uint32_t milliseconds) { + struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000), + static_cast<long>(milliseconds % 1000) * 1000000}; + while (sleep_time.tv_sec || sleep_time.tv_nsec) { + if (nanosleep(&sleep_time /* to wait */, + &sleep_time /* remaining (on interrruption) */) == 0) { + sleep_time = {}; + } else { + if (errno != EINTR) return errno; + } + } + return 0; + } + + ErrorCode GetReturnErrorCode(const Status& result) { + if (result.isOk()) return ErrorCode::OK; + + if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) { + return static_cast<ErrorCode>(result.getServiceSpecificError()); + } + + return ErrorCode::UNKNOWN_ERROR; + } + + void InitializeSecureClock(std::shared_ptr<ISecureClock> secureClock) { + ASSERT_NE(secureClock, nullptr); + secureClock_ = secureClock; + } + + ISecureClock& secureClock() { return *secureClock_; } + + static vector<string> build_params() { + auto params = ::android::getAidlHalInstanceNames(ISecureClock::descriptor); + return params; + } + + void SetUp() override { + if (AServiceManager_isDeclared(GetParam().c_str())) { + ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str())); + InitializeSecureClock(ISecureClock::fromBinder(binder)); + } else { + InitializeSecureClock(nullptr); + } + } + + void TearDown() override {} + + private: + std::shared_ptr<ISecureClock> secureClock_; +}; + +/* + * The precise capabilities required to generate TimeStampToken will vary depending on the specific + * vendor implementations. The only thing we really can test is that tokens can be created by + * secureclock services, and that the timestamps increase as expected. + */ +TEST_P(SecureClockAidlTest, TestCreation) { + auto result1 = getTimestampToken(1 /* challenge */); + auto result1_time = getTime(); + EXPECT_EQ(ErrorCode::OK, result1.error); + EXPECT_EQ(1U, result1.token.challenge); + EXPECT_GT(result1.token.timestamp.milliSeconds, 0U); + + unsigned long time_to_sleep = 200; + sleep_ms(time_to_sleep); + + auto result2 = getTimestampToken(2 /* challenge */); + auto result2_time = getTime(); + EXPECT_EQ(ErrorCode::OK, result2.error); + EXPECT_EQ(2U, result2.token.challenge); + EXPECT_GT(result2.token.timestamp.milliSeconds, 0U); + + auto host_time_delta = result2_time - result1_time; + + EXPECT_GE(host_time_delta, time_to_sleep) + << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much"; + EXPECT_LE(host_time_delta, time_to_sleep + 100) + << "The getTimestampToken call took " << (host_time_delta - time_to_sleep) + << " ms? That's awful!"; + EXPECT_GE(result2.token.timestamp.milliSeconds, result1.token.timestamp.milliSeconds); + unsigned long km_time_delta = + result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds; + // 20 ms of slop just to avoid test flakiness. + EXPECT_LE(host_time_delta, km_time_delta + 20); + EXPECT_LE(km_time_delta, host_time_delta + 20); + ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size()); + ASSERT_NE(0, + memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size())); +} + +/* + * Test that the mac changes when the time stamp changes. This is does not guarantee that the time + * stamp is included in the mac but on failure we know that it is not. Other than in the test + * case above we call getTimestampToken with the exact same set of parameters. + */ +TEST_P(SecureClockAidlTest, MacChangesOnChangingTimestamp) { + auto result1 = getTimestampToken(0 /* challenge */); + auto result1_time = getTime(); + EXPECT_EQ(ErrorCode::OK, result1.error); + EXPECT_EQ(0U, result1.token.challenge); + EXPECT_GT(result1.token.timestamp.milliSeconds, 0U); + + unsigned long time_to_sleep = 200; + sleep_ms(time_to_sleep); + + auto result2 = getTimestampToken(1 /* challenge */); + auto result2_time = getTime(); + EXPECT_EQ(ErrorCode::OK, result2.error); + EXPECT_EQ(1U, result2.token.challenge); + EXPECT_GT(result2.token.timestamp.milliSeconds, 0U); + + auto host_time_delta = result2_time - result1_time; + + EXPECT_GE(host_time_delta, time_to_sleep) + << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much"; + EXPECT_LE(host_time_delta, time_to_sleep + 100) + << "The getTimestampToken call took " << (host_time_delta - time_to_sleep) + << " ms? That's awful!"; + + EXPECT_GE(result2.token.timestamp.milliSeconds, result1.token.timestamp.milliSeconds); + unsigned long km_time_delta = + result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds; + + EXPECT_LE(host_time_delta, km_time_delta + 20); + EXPECT_LE(km_time_delta, host_time_delta + 20); + ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size()); + ASSERT_NE(0, + memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size())); +} + +INSTANTIATE_TEST_SUITE_P(PerInstance, SecureClockAidlTest, + testing::ValuesIn(SecureClockAidlTest::build_params()), + ::android::PrintInstanceNameToString); +} // namespace aidl::android::hardware::security::secureclock::test + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}
\ No newline at end of file |