Merge "The implementation of vts and default implementation to support ISecureClock and ISharedSecret AIDLs. Test: atest VtsAidlSecureClockTargetTest, atest VtsAidlSharedSecretTargetTest Bug: b/175136979, b/175141176"
This commit is contained in:
commit
9717a37b6a
15 changed files with 707 additions and 18 deletions
|
@ -2,7 +2,11 @@ cc_binary {
|
|||
name: "android.hardware.security.keymint-service",
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["android.hardware.security.keymint-service.rc"],
|
||||
vintf_fragments: ["android.hardware.security.keymint-service.xml"],
|
||||
vintf_fragments: [
|
||||
"android.hardware.security.keymint-service.xml",
|
||||
"android.hardware.security.sharedsecret-service.xml",
|
||||
"android.hardware.security.secureclock-service.xml",
|
||||
],
|
||||
vendor: true,
|
||||
cflags: [
|
||||
"-Wall",
|
||||
|
@ -10,6 +14,8 @@ cc_binary {
|
|||
],
|
||||
shared_libs: [
|
||||
"android.hardware.security.keymint-V1-ndk_platform",
|
||||
"android.hardware.security.sharedsecret-unstable-ndk_platform",
|
||||
"android.hardware.security.secureclock-unstable-ndk_platform",
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libcppbor",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.security.secureclock</name>
|
||||
<fqname>ISecureClock/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
|
@ -0,0 +1,6 @@
|
|||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.security.sharedsecret</name>
|
||||
<fqname>ISharedSecret/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
|
@ -21,25 +21,38 @@
|
|||
#include <android/binder_process.h>
|
||||
|
||||
#include <AndroidKeyMintDevice.h>
|
||||
#include <AndroidSecureClock.h>
|
||||
#include <AndroidSharedSecret.h>
|
||||
#include <keymaster/soft_keymaster_logger.h>
|
||||
|
||||
using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
|
||||
using aidl::android::hardware::security::keymint::SecurityLevel;
|
||||
using aidl::android::hardware::security::secureclock::AndroidSecureClock;
|
||||
using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;
|
||||
|
||||
template <typename T, class... Args>
|
||||
std::shared_ptr<T> addService(Args&&... args) {
|
||||
std::shared_ptr<T> ser = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
|
||||
auto instanceName = std::string(T::descriptor) + "/default";
|
||||
LOG(INFO) << "adding keymint service instance: " << instanceName;
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
|
||||
CHECK(status == STATUS_OK);
|
||||
return ser;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
|
||||
// the pool size to 1.
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
|
||||
// Add Keymint Service
|
||||
std::shared_ptr<AndroidKeyMintDevice> keyMint =
|
||||
ndk::SharedRefBase::make<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
|
||||
|
||||
keymaster::SoftKeymasterLogger logger;
|
||||
const auto instanceName = std::string(AndroidKeyMintDevice::descriptor) + "/default";
|
||||
LOG(INFO) << "instance: " << instanceName;
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(keyMint->asBinder().get(), instanceName.c_str());
|
||||
CHECK(status == STATUS_OK);
|
||||
|
||||
addService<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
|
||||
// Add Secure Clock Service
|
||||
addService<AndroidSecureClock>(keyMint);
|
||||
// Add Shared Secret Service
|
||||
addService<AndroidSharedSecret>(keyMint);
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* 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.
|
||||
* limitations under the License.
|
||||
*////////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -20,5 +33,5 @@ package android.hardware.security.secureclock;
|
|||
@VintfStability
|
||||
interface ISecureClock {
|
||||
android.hardware.security.secureclock.TimeStampToken generateTimeStamp(in long challenge);
|
||||
const String TIME_STAMP_MAC_LABEL = "Time Verification";
|
||||
const String TIME_STAMP_MAC_LABEL = "Auth Verification";
|
||||
}
|
||||
|
|
|
@ -1,4 +1,18 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* 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.
|
||||
*////////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -1,4 +1,18 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* Copyright 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.
|
||||
*////////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ interface ISecureClock {
|
|||
* String used as context in the HMAC computation signing the generated time stamp.
|
||||
* See TimeStampToken.mac for details.
|
||||
*/
|
||||
const String TIME_STAMP_MAC_LABEL = "Time Verification";
|
||||
const String TIME_STAMP_MAC_LABEL = "Auth Verification";
|
||||
|
||||
/**
|
||||
* Generates an authenticated timestamp.
|
||||
|
|
|
@ -39,18 +39,20 @@ parcelable TimeStampToken {
|
|||
* 32-byte HMAC-SHA256 of the above values, computed as:
|
||||
*
|
||||
* HMAC(H,
|
||||
* ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp)
|
||||
* ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp || securityLevel )
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* ``ISecureClock.TIME_STAMP_MAC_LABEL'' is a sting constant defined in ISecureClock.aidl.
|
||||
*
|
||||
* ``H'' is the shared HMAC key (see computeSharedHmac() in ISharedHmacSecret).
|
||||
* ``H'' is the shared HMAC key (see computeSharedHmac() in ISharedSecret).
|
||||
*
|
||||
* ``||'' represents concatenation
|
||||
*
|
||||
* The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
|
||||
* order. securityLevel is represented as a 32-bit unsigned integer in big-endian order.
|
||||
* order. SecurityLevel is represented as a 32-bit unsigned integer in big-endian order as
|
||||
* described in android.hardware.security.keymint.SecurityLevel. It represents the security
|
||||
* level of the secure clock environment.
|
||||
*/
|
||||
byte[] mac;
|
||||
}
|
||||
|
|
43
security/secureclock/aidl/vts/functional/Android.bp
Normal file
43
security/secureclock/aidl/vts/functional/Android.bp
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
cc_test {
|
||||
name: "VtsAidlSecureClockTargetTest",
|
||||
defaults: [
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
],
|
||||
srcs: [
|
||||
"SecureClockAidlTest.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libcrypto",
|
||||
"libkeymint",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.security.keymint-unstable-ndk_platform",
|
||||
"android.hardware.security.secureclock-unstable-ndk_platform",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
34
security/secureclock/aidl/vts/functional/AndroidTest.xml
Normal file
34
security/secureclock/aidl/vts/functional/AndroidTest.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<configuration description="Runs VtsAidlSecureClockTargetTest.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-native" />
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
|
||||
</target_preparer>
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push"
|
||||
value="VtsAidlSecureClockTargetTest->/data/local/tmp/VtsAidlSecureClockTargetTest" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||
<option name="module-name" value="VtsAidlSecureClockTargetTest" />
|
||||
<option name="native-test-timeout" value="900000"/>
|
||||
</test>
|
||||
</configuration>
|
193
security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
Normal file
193
security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
Normal file
|
@ -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();
|
||||
}
|
43
security/sharedsecret/aidl/vts/functional/Android.bp
Normal file
43
security/sharedsecret/aidl/vts/functional/Android.bp
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
cc_test {
|
||||
name: "VtsAidlSharedSecretTargetTest",
|
||||
defaults: [
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
srcs: [
|
||||
"SharedSecretAidlTest.cpp",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libcrypto",
|
||||
"libkeymint",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.security.keymint-unstable-ndk_platform",
|
||||
"android.hardware.security.sharedsecret-unstable-ndk_platform",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
34
security/sharedsecret/aidl/vts/functional/AndroidTest.xml
Normal file
34
security/sharedsecret/aidl/vts/functional/AndroidTest.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<configuration description="Runs VtsAidlSharedSecretTargetTest.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-native" />
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
|
||||
</target_preparer>
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push"
|
||||
value="VtsAidlSharedSecretTargetTest->/data/local/tmp/VtsAidlSharedSecretTargetTest" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||
<option name="module-name" value="VtsAidlSharedSecretTargetTest" />
|
||||
<option name="native-test-timeout" value="900000"/>
|
||||
</test>
|
||||
</configuration>
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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 "sharedsecret_test"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <aidl/Vintf.h>
|
||||
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
|
||||
#include <aidl/android/hardware/security/sharedsecret/ISharedSecret.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
|
||||
namespace aidl::android::hardware::security::sharedsecret::test {
|
||||
using ::aidl::android::hardware::security::keymint::ErrorCode;
|
||||
using ::std::shared_ptr;
|
||||
using ::std::vector;
|
||||
using Status = ::ndk::ScopedAStatus;
|
||||
|
||||
class SharedSecretAidlTest : public ::testing::Test {
|
||||
public:
|
||||
struct GetParamsResult {
|
||||
ErrorCode error;
|
||||
SharedSecretParameters params;
|
||||
auto tie() { return std::tie(error, params); }
|
||||
};
|
||||
|
||||
struct ComputeResult {
|
||||
ErrorCode error;
|
||||
vector<uint8_t> sharing_check;
|
||||
auto tie() { return std::tie(error, sharing_check); }
|
||||
};
|
||||
|
||||
GetParamsResult getSharedSecretParameters(shared_ptr<ISharedSecret>& sharedSecret) {
|
||||
SharedSecretParameters params;
|
||||
auto error = GetReturnErrorCode(sharedSecret->getSharedSecretParameters(¶ms));
|
||||
EXPECT_EQ(ErrorCode::OK, error);
|
||||
GetParamsResult result;
|
||||
result.tie() = std::tie(error, params);
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<SharedSecretParameters> getAllSharedSecretParameters() {
|
||||
vector<SharedSecretParameters> paramsVec;
|
||||
for (auto& sharedSecret : allSharedSecrets_) {
|
||||
auto result = getSharedSecretParameters(sharedSecret);
|
||||
EXPECT_EQ(ErrorCode::OK, result.error);
|
||||
if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
|
||||
}
|
||||
return paramsVec;
|
||||
}
|
||||
|
||||
ComputeResult computeSharedSecret(shared_ptr<ISharedSecret>& sharedSecret,
|
||||
const vector<SharedSecretParameters>& params) {
|
||||
std::vector<uint8_t> sharingCheck;
|
||||
auto error = GetReturnErrorCode(sharedSecret->computeSharedSecret(params, &sharingCheck));
|
||||
ComputeResult result;
|
||||
result.tie() = std::tie(error, sharingCheck);
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<ComputeResult> computeAllSharedSecrets(const vector<SharedSecretParameters>& params) {
|
||||
vector<ComputeResult> result;
|
||||
for (auto& sharedSecret : allSharedSecrets_) {
|
||||
result.push_back(computeSharedSecret(sharedSecret, params));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<vector<uint8_t>> copyNonces(const vector<SharedSecretParameters>& paramsVec) {
|
||||
vector<vector<uint8_t>> nonces;
|
||||
for (auto& param : paramsVec) {
|
||||
nonces.push_back(param.nonce);
|
||||
}
|
||||
return nonces;
|
||||
}
|
||||
|
||||
void verifyResponses(const vector<uint8_t>& expected, const vector<ComputeResult>& responses) {
|
||||
for (auto& response : responses) {
|
||||
EXPECT_EQ(ErrorCode::OK, response.error);
|
||||
EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static shared_ptr<ISharedSecret> getSharedSecretService(const char* name) {
|
||||
if (AServiceManager_isDeclared(name)) {
|
||||
::ndk::SpAIBinder binder(AServiceManager_waitForService(name));
|
||||
return ISharedSecret::fromBinder(binder);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const vector<shared_ptr<ISharedSecret>>& allSharedSecrets() { return allSharedSecrets_; }
|
||||
|
||||
static void SetUpTestCase() {
|
||||
if (allSharedSecrets_.empty()) {
|
||||
auto names = ::android::getAidlHalInstanceNames(ISharedSecret::descriptor);
|
||||
for (const auto& name : names) {
|
||||
auto servicePtr = getSharedSecretService(name.c_str());
|
||||
if (servicePtr != nullptr) allSharedSecrets_.push_back(std::move(servicePtr));
|
||||
}
|
||||
}
|
||||
}
|
||||
static void TearDownTestCase() {}
|
||||
void SetUp() override {}
|
||||
void TearDown() override {}
|
||||
|
||||
private:
|
||||
static vector<shared_ptr<ISharedSecret>> allSharedSecrets_;
|
||||
};
|
||||
|
||||
vector<shared_ptr<ISharedSecret>> SharedSecretAidlTest::allSharedSecrets_;
|
||||
|
||||
TEST_F(SharedSecretAidlTest, GetParameters) {
|
||||
auto sharedSecrets = allSharedSecrets();
|
||||
for (auto sharedSecret : sharedSecrets) {
|
||||
auto result1 = getSharedSecretParameters(sharedSecret);
|
||||
EXPECT_EQ(ErrorCode::OK, result1.error);
|
||||
auto result2 = getSharedSecretParameters(sharedSecret);
|
||||
EXPECT_EQ(ErrorCode::OK, result2.error);
|
||||
ASSERT_EQ(result1.params.seed, result2.params.seed)
|
||||
<< "A given shared secret service should always return the same seed.";
|
||||
ASSERT_EQ(result1.params.nonce, result2.params.nonce)
|
||||
<< "A given shared secret service should always return the same nonce until "
|
||||
"restart.";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SharedSecretAidlTest, ComputeSharedSecret) {
|
||||
auto params = getAllSharedSecretParameters();
|
||||
ASSERT_EQ(allSharedSecrets().size(), params.size())
|
||||
<< "One or more shared secret services failed to provide parameters.";
|
||||
auto nonces = copyNonces(params);
|
||||
EXPECT_EQ(allSharedSecrets().size(), nonces.size());
|
||||
std::sort(nonces.begin(), nonces.end());
|
||||
std::unique(nonces.begin(), nonces.end());
|
||||
EXPECT_EQ(allSharedSecrets().size(), nonces.size());
|
||||
|
||||
auto responses = computeAllSharedSecrets(params);
|
||||
ASSERT_GT(responses.size(), 0U);
|
||||
verifyResponses(responses[0].sharing_check, responses);
|
||||
|
||||
// Do it a second time. Should get the same answers.
|
||||
params = getAllSharedSecretParameters();
|
||||
ASSERT_EQ(allSharedSecrets().size(), params.size())
|
||||
<< "One or more shared secret services failed to provide parameters.";
|
||||
|
||||
responses = computeAllSharedSecrets(params);
|
||||
ASSERT_GT(responses.size(), 0U);
|
||||
ASSERT_EQ(32U, responses[0].sharing_check.size());
|
||||
verifyResponses(responses[0].sharing_check, responses);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
class final_action {
|
||||
public:
|
||||
explicit final_action(F f) : f_(std::move(f)) {}
|
||||
~final_action() { f_(); }
|
||||
|
||||
private:
|
||||
F f_;
|
||||
};
|
||||
|
||||
template <class F>
|
||||
inline final_action<F> finally(const F& f) {
|
||||
return final_action<F>(f);
|
||||
}
|
||||
|
||||
TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptNonce) {
|
||||
auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
|
||||
|
||||
auto params = getAllSharedSecretParameters();
|
||||
ASSERT_EQ(allSharedSecrets().size(), params.size())
|
||||
<< "One or more shared secret services failed to provide parameters.";
|
||||
|
||||
// All should be well in the normal case
|
||||
auto responses = computeAllSharedSecrets(params);
|
||||
|
||||
ASSERT_GT(responses.size(), 0U);
|
||||
vector<uint8_t> correct_response = responses[0].sharing_check;
|
||||
verifyResponses(correct_response, responses);
|
||||
|
||||
// Pick a random param, a random byte within the param's nonce, and a random bit within
|
||||
// the byte. Flip that bit.
|
||||
size_t param_to_tweak = rand() % params.size();
|
||||
uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
|
||||
uint8_t bit_to_tweak = rand() % 8;
|
||||
params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
|
||||
|
||||
responses = computeAllSharedSecrets(params);
|
||||
for (size_t i = 0; i < responses.size(); ++i) {
|
||||
if (i == param_to_tweak) {
|
||||
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
|
||||
<< "Shared secret service that provided tweaked param should fail to compute "
|
||||
"shared secret";
|
||||
} else {
|
||||
EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
|
||||
EXPECT_NE(correct_response, responses[i].sharing_check)
|
||||
<< "Others should calculate a different shared secret, due to the tweaked "
|
||||
"nonce.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
|
||||
auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
|
||||
auto params = getAllSharedSecretParameters();
|
||||
ASSERT_EQ(allSharedSecrets().size(), params.size())
|
||||
<< "One or more shared secret service failed to provide parameters.";
|
||||
|
||||
// All should be well in the normal case
|
||||
auto responses = computeAllSharedSecrets(params);
|
||||
|
||||
ASSERT_GT(responses.size(), 0U);
|
||||
vector<uint8_t> correct_response = responses[0].sharing_check;
|
||||
verifyResponses(correct_response, responses);
|
||||
|
||||
// Pick a random param and modify the seed. We just increase the seed length by 1. It doesn't
|
||||
// matter what value is in the additional byte; it changes the seed regardless.
|
||||
auto param_to_tweak = rand() % params.size();
|
||||
auto& to_tweak = params[param_to_tweak].seed;
|
||||
ASSERT_TRUE(to_tweak.size() == 32 || to_tweak.size() == 0);
|
||||
if (!to_tweak.size()) {
|
||||
to_tweak.resize(32); // Contents don't matter; a little randomization is nice.
|
||||
}
|
||||
to_tweak[0]++;
|
||||
|
||||
responses = computeAllSharedSecrets(params);
|
||||
for (size_t i = 0; i < responses.size(); ++i) {
|
||||
if (i == param_to_tweak) {
|
||||
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
|
||||
<< "Shared secret service that provided tweaked param should fail to compute "
|
||||
"shared secret";
|
||||
} else {
|
||||
EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
|
||||
EXPECT_NE(correct_response, responses[i].sharing_check)
|
||||
<< "Others should calculate a different shared secret, due to the tweaked "
|
||||
"nonce.";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace aidl::android::hardware::security::sharedsecret::test
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in a new issue