Merge "[VTS] Ignore tests of setting Active Boot Slot."
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml
index 67fcdb6..3793bb5 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV2_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml
index 2084060..f74ca1c 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV4_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml
index 8b01e41..ccbb629 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV5_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
index 05edc0d..f035baf 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml
index b6e720b..36d9324 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV2_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml
index df826c8..091a4dc 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV4_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml
index 14bdf43..14e90a1 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV5_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml
index 23adad0..8b6c08f 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV6_0TargetTest.xml
@@ -17,13 +17,11 @@
<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.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
<option name="run-command" value="setprop vts.native_server.on 1"/>
- <option name="teardown-command" value="start"/>
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
diff --git a/current.txt b/current.txt
index 99da427..f9e36b4 100644
--- a/current.txt
+++ b/current.txt
@@ -304,6 +304,7 @@
fe28829dab10d171783b79ac9cc45412739f8ff275e90228d7c6370ef189b859 android.hardware.audio.effect@4.0::IVisualizerEffect
21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73 android.hardware.audio.effect@4.0::types
a0f93c768c353cecee6237fe479bce47404eb10b629fafe07e32a054fd67f2af android.hardware.automotive.audiocontrol@1.0::IAudioControl
+ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardware.automotive.audiocontrol@1.0::types
f2904a4c108ad1b93eb2fa4e43b82bd01ce1ff26156316e49d1d9fc80dfecaad android.hardware.automotive.evs@1.0::IEvsCamera
94cba6ad04c83aa840de2ed52b74ba2126a26dd960225e61ac36703315279a80 android.hardware.automotive.evs@1.0::IEvsCameraStream
5ea36fb043d9e3b413219de3dfd7b046b48af4fda39f167f3528652e986cb76d android.hardware.automotive.evs@1.0::IEvsDisplay
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index cc34290..237ac42 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -25,6 +25,7 @@
static_libs: [
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
+ "android.hardware.gnss@2.0",
"android.hardware.gnss@common-vts-lib",
],
shared_libs: [
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 503e419..7a7b6af 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -427,6 +427,7 @@
sources.resize(1);
sources[0] = source_to_blacklist;
+ // setBlacklist when location is on.
auto result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 14ae43c..c01e91d 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -221,3 +221,46 @@
capabilities_cbq_.store(capabilities);
return Void();
}
+
+GnssConstellationType_1_0 GnssHalTest::startLocationAndGetNonGpsConstellation() {
+ const int kLocationsToAwait = 3;
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+ const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+ sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+ // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
+ // as blacklisting of this constellation is not supported in gnss@2.0.
+ const int kGnssSvStatusTimeout = 2;
+ GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ if ((sv_info.v1_0.svFlag & IGnssCallback_2_0::GnssSvFlags::USED_IN_FIX) &&
+ (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
+ (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+ (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+ // found a non-GPS V1_0 constellation
+ constellation_to_blacklist = Utils::mapConstellationType(sv_info.constellation);
+ break;
+ }
+ }
+ if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
+ break;
+ }
+ }
+
+ if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
+ ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+ // Proceed functionally to blacklist something.
+ constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
+ }
+ return constellation_to_blacklist;
+}
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 90a7866..5bfcb1f 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -34,6 +34,9 @@
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V2_0::IGnss;
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+
using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
@@ -248,6 +251,16 @@
*/
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+ /*
+ * startLocationAndGetNonGpsConstellation:
+ * 1. Start location
+ * 2. Find and return first non-GPS constellation
+ *
+ * Note that location is not stopped in this method. The client should call
+ * StopAndClearLocations() after the call.
+ */
+ GnssConstellationType_1_0 startLocationAndGetNonGpsConstellation();
+
sp<IGnss> gnss_hal_; // GNSS HAL to call into
sp<GnssCallback> gnss_cb_; // Primary callback interface
};
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 39736cc..b42f432 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -23,8 +23,6 @@
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
-using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
-using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
@@ -480,31 +478,6 @@
}
/*
- * MapConstellationType:
- * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
- * GnssConstellationType_1_0 type constellation. For constellations that do not have
- * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
- */
-GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) {
- switch (constellation) {
- case GnssConstellationType_2_0::GPS:
- return GnssConstellationType_1_0::GPS;
- case GnssConstellationType_2_0::SBAS:
- return GnssConstellationType_1_0::SBAS;
- case GnssConstellationType_2_0::GLONASS:
- return GnssConstellationType_1_0::GLONASS;
- case GnssConstellationType_2_0::QZSS:
- return GnssConstellationType_1_0::QZSS;
- case GnssConstellationType_2_0::BEIDOU:
- return GnssConstellationType_1_0::BEIDOU;
- case GnssConstellationType_2_0::GALILEO:
- return GnssConstellationType_1_0::GALILEO;
- default:
- return GnssConstellationType_1_0::UNKNOWN;
- }
-}
-
-/*
* FindStrongFrequentNonGpsSource:
*
* Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
@@ -543,7 +516,7 @@
(sv_info.constellation != GnssConstellationType_2_0::GPS)) {
ComparableBlacklistedSource source;
source.id.svid = sv_info.v1_0.svid;
- source.id.constellation = MapConstellationType(sv_info.constellation);
+ source.id.constellation = Utils::mapConstellationType(sv_info.constellation);
const auto& itSignal = mapSignals.find(source);
if (itSignal == mapSignals.end()) {
@@ -677,7 +650,7 @@
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
- auto constellation = MapConstellationType(sv_info.constellation);
+ auto constellation = Utils::mapConstellationType(sv_info.constellation);
EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) &&
(constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
@@ -719,7 +692,7 @@
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
- auto constellation = MapConstellationType(sv_info.constellation);
+ auto constellation = Utils::mapConstellationType(sv_info.constellation);
if ((sv_info.v1_0.svid == source_to_blacklist.svid) &&
(constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
@@ -735,7 +708,7 @@
}
/*
- * BlacklistConstellation:
+ * BlacklistConstellationWithLocationOff:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for any non-GPS constellations.
@@ -744,7 +717,7 @@
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
@@ -752,43 +725,12 @@
const int kLocationsToAwait = 3;
- gnss_cb_->location_cbq_.reset();
- StartAndCheckLocations(kLocationsToAwait);
- const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
- // Tolerate 1 less sv status to handle edge cases in reporting.
- int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
- EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
- ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
- sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+ // Turns off location
+ StopAndClearLocations();
- // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
- // as blacklisting of this constellation is not supported in gnss@2.0.
- const int kGnssSvStatusTimeout = 2;
- GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
- for (int i = 0; i < sv_info_list_cbq_size; ++i) {
- hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
- gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
- for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
- if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
- (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
- (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
- (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
- // found a non-GPS V1_0 constellation
- constellation_to_blacklist = MapConstellationType(sv_info.constellation);
- break;
- }
- }
- if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
- break;
- }
- }
-
- if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
- ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
- // Proceed functionally to blacklist something.
- constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
- }
IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
source_to_blacklist.constellation = constellation_to_blacklist;
source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
@@ -802,6 +744,7 @@
sources.resize(1);
sources[0] = source_to_blacklist;
+ // setBlacklist when location is off.
auto result = gnss_configuration_hal->setBlacklist(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
@@ -813,15 +756,88 @@
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
- sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
kLocationsToAwait);
+ const int kGnssSvStatusTimeout = 2;
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
- auto constellation = MapConstellationType(sv_info.constellation);
+ auto constellation = Utils::mapConstellationType(sv_info.constellation);
+ EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
+ (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+ }
+ }
+
+ // clean up
+ StopAndClearLocations();
+ sources.resize(0);
+ result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+}
+
+/*
+ * BlacklistConstellationWithLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellations, and turns off location.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
+ if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+ ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
+ return;
+ }
+
+ const int kLocationsToAwait = 3;
+
+ // Find first non-GPS constellation to blacklist
+ GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+
+ IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
+ source_to_blacklist.constellation = constellation_to_blacklist;
+ source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
+
+ auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+ ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+ sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+ ASSERT_NE(gnss_configuration_hal, nullptr);
+
+ hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+ sources.resize(1);
+ sources[0] = source_to_blacklist;
+
+ // setBlacklist when location is on.
+ auto result = gnss_configuration_hal->setBlacklist(sources);
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ // Turns off location
+ StopAndClearLocations();
+
+ // retry and ensure constellation not used
+ gnss_cb_->sv_info_list_cbq_.reset();
+
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToAwait);
+
+ // Tolerate 1 less sv status to handle edge cases in reporting.
+ int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+ EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+ ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
+ kLocationsToAwait);
+ const int kGnssSvStatusTimeout = 2;
+ for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+ hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+ gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+ for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+ auto constellation = Utils::mapConstellationType(sv_info.constellation);
EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
(sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
}
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 1988171..ed383fc 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -29,6 +29,7 @@
export_include_dirs: ["include"],
shared_libs: [
"android.hardware.gnss@1.0",
+ "android.hardware.gnss@2.0",
"android.hardware.gnss.measurement_corrections@1.0",
],
static_libs: [
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 51d3ea1..4e42f75 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -139,6 +139,31 @@
return mockCorrections;
}
+/*
+ * MapConstellationType:
+ * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
+ * GnssConstellationType_1_0 type constellation. For constellations that do not have
+ * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
+ */
+GnssConstellationType_1_0 Utils::mapConstellationType(GnssConstellationType_2_0 constellation) {
+ switch (constellation) {
+ case GnssConstellationType_2_0::GPS:
+ return GnssConstellationType_1_0::GPS;
+ case GnssConstellationType_2_0::SBAS:
+ return GnssConstellationType_1_0::SBAS;
+ case GnssConstellationType_2_0::GLONASS:
+ return GnssConstellationType_1_0::GLONASS;
+ case GnssConstellationType_2_0::QZSS:
+ return GnssConstellationType_1_0::QZSS;
+ case GnssConstellationType_2_0::BEIDOU:
+ return GnssConstellationType_1_0::BEIDOU;
+ case GnssConstellationType_2_0::GALILEO:
+ return GnssConstellationType_1_0::GALILEO;
+ default:
+ return GnssConstellationType_1_0::UNKNOWN;
+ }
+}
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index dce4c7b..b5f833b 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -18,8 +18,11 @@
#define android_hardware_gnss_common_vts_Utils_H_
#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
using namespace android::hardware::gnss::measurement_corrections::V1_0;
@@ -32,6 +35,8 @@
static void checkLocation(const GnssLocation& location, bool check_speed,
bool check_more_accuracies);
static const MeasurementCorrections getMockMeasurementCorrections();
+
+ static GnssConstellationType_1_0 mapConstellationType(GnssConstellationType_2_0 constellation);
};
} // namespace common
diff --git a/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
index d9b5580..362581e 100644
--- a/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
+++ b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
@@ -55,7 +55,7 @@
void set_charger_online(const HealthInfo& health_info);
private:
- const std::string& instance_name_;
+ std::string instance_name_;
sp<IHealth> service_;
bool charger_online_ = false;
};
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/.hash b/identity/aidl/aidl_api/android.hardware.identity/2/.hash
index 1b2c1b6..036ce84 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/2/.hash
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/.hash
@@ -1 +1 @@
-3b0b10b618dbc4bf283aa2bf78833ad3de0a5928
+194e04be642728623d65ec8321a3764fdea52ae0
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl
index e8e93f8..88104d9 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl
@@ -28,4 +28,5 @@
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
+ void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index e8e93f8..88104d9 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -28,4 +28,5 @@
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
+ void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 7cd25e6..d7f47e8 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -20,6 +20,7 @@
import android.hardware.identity.RequestNamespace;
import android.hardware.identity.SecureAccessControlProfile;
import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.keymaster.VerificationToken;
@VintfStability
interface IIdentityCredential {
@@ -71,10 +72,11 @@
/**
* Creates a challenge value to be used for proving successful user authentication. This
- * is included in the authToken passed to the startRetrieval() method.
+ * is included in the authToken passed to the startRetrieval() method and the
+ * verificationToken passed to the setVerificationToken() method.
*
* This method may only be called once per instance. If called more than once, STATUS_FAILED
- * will be returned.
+ * will be returned. If user authentication is not needed, this method may not be called.
*
* @return challenge, a non-zero number.
*/
@@ -83,7 +85,8 @@
/**
* Start an entry retrieval process.
*
- * The setRequestedNamespaces() method will be called before this method.
+ * The setRequestedNamespaces() and setVerificationToken() methods will be called before
+ * this method is called.
*
* This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
* createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
@@ -96,7 +99,19 @@
* must be identical for each startRetrieval() invocation. If this is not the case, this call
* fails with the STATUS_SESSION_TRANSCRIPT_MISMATCH error.
*
- * If the provided authToken is not valid this method fails with STATUS_INVALID_AUTH_TOKEN.
+ * If either authToken or verificationToken (as passed with setVerificationToken())
+ * is not valid this method fails with STATUS_INVALID_AUTH_TOKEN. Note that valid tokens
+ * are only passed if they are actually needed and available (this can be detected by
+ * the timestamp being set to zero). For example, if no data items with access control
+ * profiles using user authentication are requested, the tokens are not filled in.
+ * It's also possible that no usable auth token is actually available (it could be the user
+ * never unlocked the device within the timeouts in the access control profiles) and
+ * in this case the tokens aren't filled in either.
+ *
+ * For test credentials (identified by the testCredential boolean in the CredentialData
+ * CBOR created at provisioning time), the |mac| field in both the authToken and
+ * verificationToken should not be checked against the shared HMAC key (see IKeyMasterDevice
+ * for details). This is to enable VTS tests to check for correct behavior.
*
* Each of the provided accessControlProfiles is checked in this call. If they are not
* all valid, the call fails with STATUS_INVALID_DATA.
@@ -179,7 +194,8 @@
*
* @param authToken
* The authentication token that proves the user was authenticated, as required
- * by one or more of the provided accessControlProfiles. See above.
+ * by one or more of the provided accessControlProfiles. This token is only valid
+ * if the timestamp field is non-zero. See above.
*
* @param itemsRequest
* If non-empty, contains request data that is signed by the reader. See above.
@@ -358,4 +374,13 @@
* @param requestNamespaces Namespaces and data items which will be requested.
*/
void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
+
+ /**
+ * Sets the VerificationToken. This method must be called before startRetrieval() is
+ * called. This token uses the same challenge as returned by createAuthChallenge().
+ *
+ * @param verificationToken
+ * The verification token. This token is only valid if the timestamp field is non-zero.
+ */
+ void setVerificationToken(in VerificationToken verificationToken);
}
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index ff4107a..381eb84 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -198,15 +198,8 @@
return false;
}
-Timestamp clockGetTime() {
- struct timespec time;
- clock_gettime(CLOCK_MONOTONIC, &time);
- Timestamp ts;
- ts.milliSeconds = time.tv_sec * 1000 + time.tv_nsec / 1000000;
- return ts;
-}
-
bool checkUserAuthentication(const SecureAccessControlProfile& profile,
+ const VerificationToken& verificationToken,
const HardwareAuthToken& authToken, uint64_t authChallenge) {
if (profile.secureUserId != authToken.userId) {
LOG(ERROR) << "secureUserId in profile (" << profile.secureUserId
@@ -214,6 +207,15 @@
return false;
}
+ if (verificationToken.timestamp.milliSeconds == 0) {
+ LOG(ERROR) << "VerificationToken is not set";
+ return false;
+ }
+ if (authToken.timestamp.milliSeconds == 0) {
+ LOG(ERROR) << "AuthToken is not set";
+ return false;
+ }
+
if (profile.timeoutMillis == 0) {
if (authToken.challenge == 0) {
LOG(ERROR) << "No challenge in authToken";
@@ -227,19 +229,11 @@
return true;
}
- // Note that the Epoch for timestamps in HardwareAuthToken is at the
- // discretion of the vendor:
+ // Timeout-based user auth follows. The verification token conveys what the
+ // time is right now in the environment which generated the auth token. This
+ // is what makes it possible to do timeout-based checks.
//
- // "[...] since some starting point (generally the most recent device
- // boot) which all of the applications within one secure environment
- // must agree upon."
- //
- // Therefore, if this software implementation is used on a device which isn't
- // the emulator then the assumption that the epoch is the same as used in
- // clockGetTime above will not hold. This is OK as this software
- // implementation should never be used on a real device.
- //
- Timestamp now = clockGetTime();
+ const Timestamp now = verificationToken.timestamp;
if (authToken.timestamp.milliSeconds > now.milliSeconds) {
LOG(ERROR) << "Timestamp in authToken (" << authToken.timestamp.milliSeconds
<< ") is in the future (now: " << now.milliSeconds << ")";
@@ -261,6 +255,12 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus IdentityCredential::setVerificationToken(
+ const VerificationToken& verificationToken) {
+ verificationToken_ = verificationToken;
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus IdentityCredential::startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
@@ -483,7 +483,8 @@
}
int accessControlCheck = IIdentityCredentialStore::STATUS_OK;
if (profile.userAuthenticationRequired) {
- if (!haveAuthToken || !checkUserAuthentication(profile, authToken, authChallenge_)) {
+ if (!haveAuthToken ||
+ !checkUserAuthentication(profile, verificationToken_, authToken, authChallenge_)) {
accessControlCheck = IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED;
}
} else if (profile.readerCertificate.encodedCertificate.size() > 0) {
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index a8bad88..a82531d 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/identity/BnIdentityCredential.h>
#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
+#include <aidl/android/hardware/keymaster/VerificationToken.h>
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <map>
@@ -31,6 +32,7 @@
namespace aidl::android::hardware::identity {
using ::aidl::android::hardware::keymaster::HardwareAuthToken;
+using ::aidl::android::hardware::keymaster::VerificationToken;
using ::std::map;
using ::std::set;
using ::std::string;
@@ -55,6 +57,7 @@
ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override;
ndk::ScopedAStatus setRequestedNamespaces(
const vector<RequestNamespace>& requestNamespaces) override;
+ ndk::ScopedAStatus setVerificationToken(const VerificationToken& verificationToken) override;
ndk::ScopedAStatus startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
@@ -93,6 +96,9 @@
// Set by setRequestedNamespaces()
vector<RequestNamespace> requestNamespaces_;
+ // Set by setVerificationToken().
+ VerificationToken verificationToken_;
+
// Set at startRetrieval() time.
map<int32_t, int> profileIdToAccessCheckResult_;
vector<uint8_t> signingKeyBlob_;
diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp
index f05c615..bf95df5 100644
--- a/identity/aidl/default/service.cpp
+++ b/identity/aidl/default/service.cpp
@@ -22,9 +22,14 @@
#include "IdentityCredentialStore.h"
+using ::android::base::InitLogging;
+using ::android::base::StderrLogger;
+
using aidl::android::hardware::identity::IdentityCredentialStore;
-int main() {
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, StderrLogger);
+
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<IdentityCredentialStore> store =
ndk::SharedRefBase::make<IdentityCredentialStore>();
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index e4780bf..5b075c6 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -8,10 +8,16 @@
"VtsHalIdentityEndToEndTest.cpp",
"VtsIWritableIdentityCredentialTests.cpp",
"VtsIdentityTestUtils.cpp",
+ "VtsAttestationTests.cpp",
+ "VtsAttestationParserSupport.cpp",
],
shared_libs: [
+ "android.hardware.keymaster@4.0",
"libbinder",
"libcrypto",
+ "libkeymaster_portable",
+ "libsoft_attestation_cert",
+ "libpuresoftkeymasterdevice",
],
static_libs: [
"libcppbor",
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp
new file mode 100644
index 0000000..71fe733
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationParserSupport.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019, 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.
+ */
+
+#include "VtsAttestationParserSupport.h"
+
+#include <aidl/Gtest.h>
+#include <map>
+
+namespace android::hardware::identity::test_utils {
+
+using std::endl;
+using std::map;
+using std::optional;
+using std::string;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::keymaster::ASN1_OBJECT_Ptr;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::EVP_PKEY_Ptr;
+using ::keymaster::kAttestionRecordOid;
+using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
+using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
+using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
+using ::keymaster::TypedTag;
+using ::keymaster::X509_Ptr;
+
+using support::certificateChainSplit;
+
+optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
+ const vector<Certificate>& certificates) {
+ if (certificates.size() <= 0) {
+ return {};
+ }
+
+ keymaster_cert_chain_t kCert;
+ kCert.entry_count = certificates.size();
+ kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);
+
+ int index = 0;
+ for (const auto& c : certificates) {
+ kCert.entries[index].data_length = c.encodedCertificate.size();
+ uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());
+
+ memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
+ kCert.entries[index].data = (const uint8_t*)data;
+ index++;
+ }
+
+ return kCert;
+}
+
+bool AttestationCertificateParser::parse() {
+ optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
+ if (!cert_chain) {
+ return false;
+ }
+
+ if (cert_chain.value().entry_count < 3) {
+ return false;
+ }
+
+ if (!verifyChain(cert_chain.value())) {
+ return false;
+ }
+
+ if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
+ return false;
+ }
+
+ keymaster_free_cert_chain(&cert_chain.value());
+ return true;
+}
+
+ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
+ if (!oid.get()) return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
+ if (location == -1) return nullptr;
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+ if (!attest_rec_ext) return nullptr;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ return attest_rec;
+}
+
+X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
+ const uint8_t* p = blob.data;
+ return d2i_X509(nullptr, &p, blob.data_length);
+}
+
+bool AttestationCertificateParser::verifyAttestationRecord(
+ const keymaster_blob_t& attestation_cert) {
+ X509_Ptr cert(parseCertBlob(attestation_cert));
+ if (!cert.get()) {
+ return false;
+ }
+
+ ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
+ if (!attest_rec) {
+ return false;
+ }
+
+ keymaster_blob_t att_unique_id = {};
+ keymaster_blob_t att_challenge;
+ keymaster_error_t ret = parse_attestation_record(
+ attest_rec->data, attest_rec->length, &att_attestation_version_,
+ &att_attestation_security_level_, &att_keymaster_version_,
+ &att_keymaster_security_level_, &att_challenge, &att_sw_enforced_, &att_hw_enforced_,
+ &att_unique_id);
+ if (ret) {
+ return false;
+ }
+
+ att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
+ return true;
+}
+
+uint32_t AttestationCertificateParser::getKeymasterVersion() {
+ return att_keymaster_version_;
+}
+
+uint32_t AttestationCertificateParser::getAttestationVersion() {
+ return att_attestation_version_;
+}
+
+vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
+ return att_challenge_;
+}
+
+keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
+ return att_keymaster_security_level_;
+}
+
+keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
+ return att_attestation_security_level_;
+}
+
+// Verify the Attestation certificates are correctly chained.
+bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
+ for (size_t i = 0; i < chain.entry_count - 1; ++i) {
+ keymaster_blob_t& key_cert_blob = chain.entries[i];
+ keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
+
+ X509_Ptr key_cert(parseCertBlob(key_cert_blob));
+ X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
+ if (!key_cert.get() || !signing_cert.get()) {
+ return false;
+ }
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ if (!signing_pubkey.get()) return false;
+
+ if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
+ return false;
+ }
+
+ if (i + 1 == chain.entry_count - 1) {
+ // Last entry is self-signed.
+ if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h
new file mode 100644
index 0000000..7c7e1b6
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationParserSupport.h
@@ -0,0 +1,122 @@
+
+/*
+ * Copyright 2019, 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.
+ */
+
+#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H
+#define VTS_ATTESTATION_PARSER_SUPPORT_H
+
+//#include <aidl/Gtest.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+#include <vector>
+
+namespace android::hardware::identity::test_utils {
+
+using ::std::optional;
+using ::std::string;
+using ::std::vector;
+
+using ::keymaster::AuthorizationSet;
+using ::keymaster::TypedTag;
+
+class AttestationCertificateParser {
+ public:
+ AttestationCertificateParser(const vector<Certificate>& certChain)
+ : origCertChain_(certChain) {}
+
+ bool parse();
+
+ uint32_t getKeymasterVersion();
+ uint32_t getAttestationVersion();
+ vector<uint8_t> getAttestationChallenge();
+ keymaster_security_level_t getKeymasterSecurityLevel();
+ keymaster_security_level_t getAttestationSecurityLevel();
+
+ template <keymaster_tag_t Tag>
+ bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
+ if (att_sw_enforced_.GetTagValue(tag)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ template <keymaster_tag_t Tag>
+ bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
+ if (att_hw_enforced_.GetTagValue(tag)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ template <keymaster_tag_t Tag>
+ optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
+ keymaster_blob_t blob;
+ if (att_hw_enforced_.GetTagValue(tag, &blob)) {
+ return {};
+ }
+
+ vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
+ return ret;
+ }
+
+ template <keymaster_tag_t Tag>
+ optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
+ keymaster_blob_t blob;
+ if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
+ return {};
+ }
+
+ vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
+ return ret;
+ }
+
+ private:
+ // Helper functions.
+ bool verifyChain(const keymaster_cert_chain_t& chain);
+
+ ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);
+
+ X509* parseCertBlob(const keymaster_blob_t& blob);
+
+ bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);
+
+ optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
+ const vector<Certificate>& certificates);
+
+ // Private variables.
+ vector<Certificate> origCertChain_;
+ AuthorizationSet att_sw_enforced_;
+ AuthorizationSet att_hw_enforced_;
+ uint32_t att_attestation_version_;
+ uint32_t att_keymaster_version_;
+ keymaster_security_level_t att_attestation_security_level_;
+ keymaster_security_level_t att_keymaster_security_level_;
+ vector<uint8_t> att_challenge_;
+};
+
+} // namespace android::hardware::identity::test_utils
+
+#endif // VTS_ATTESTATION_PARSER_SUPPORT_H
diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp
new file mode 100644
index 0000000..00b5893
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationTests.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 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 "VtsAttestationTests"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
+#include <gtest/gtest.h>
+#include <future>
+#include <map>
+
+#include "VtsAttestationParserSupport.h"
+#include "VtsIdentityTestUtils.h"
+
+namespace android::hardware::identity {
+
+using std::endl;
+using std::map;
+using std::optional;
+using std::string;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using test_utils::AttestationCertificateParser;
+using test_utils::setupWritableCredential;
+using test_utils::validateAttestationCertificate;
+
+// This file verifies the Identity Credential VTS Attestation Certificate
+// generated.
+class VtsAttestationTests : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
+ String16(GetParam().c_str()));
+ ASSERT_NE(credentialStore_, nullptr);
+ }
+
+ sp<IIdentityCredentialStore> credentialStore_;
+};
+
+TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeEmptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+
+ vector<uint8_t> attestationChallenge;
+ vector<Certificate> attestationCertificate;
+ vector<uint8_t> attestationApplicationId = {};
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeNonemptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ vector<uint8_t> attestationChallenge;
+ vector<Certificate> attestationCertificate;
+ string applicationId = "Attestation Verification";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "NotSoRandomChallenge";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ vector<uint8_t> attestationApplicationId = {};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ string applicationId = "Attestation Verification";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "c";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ string applicationId = "i";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ Identity, VtsAttestationTests,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
+ android::PrintInstanceNameToString);
+
+} // namespace android::hardware::identity
diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
index 807feab..464ab0c 100644
--- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "VtsHalIdentityTargetTest"
+#define LOG_TAG "VtsHalIdentityEndToEndTest"
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
@@ -43,6 +43,9 @@
using ::android::binder::Status;
using ::android::hardware::keymaster::HardwareAuthToken;
+using ::android::hardware::keymaster::VerificationToken;
+
+using test_utils::validateAttestationCertificate;
class IdentityAidl : public testing::TestWithParam<std::string> {
public:
@@ -68,13 +71,13 @@
// part of the request data.
vector<uint8_t> readerKey;
optional<vector<uint8_t>> readerCertificate =
- test_utils::GenerateReaderCertificate("1234", readerKey);
+ test_utils::generateReaderCertificate("1234", &readerKey);
ASSERT_TRUE(readerCertificate);
// Make the portrait image really big (just shy of 256 KiB) to ensure that
// the chunking code gets exercised.
vector<uint8_t> portraitImage;
- test_utils::SetImageData(portraitImage);
+ test_utils::setImageData(portraitImage);
// Access control profiles:
const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
@@ -82,7 +85,20 @@
// Profile 1 (no authentication)
{1, {}, false, 0}};
+ // It doesn't matter since no user auth is needed in this particular test,
+ // but for good measure, clear out the tokens we pass to the HAL.
HardwareAuthToken authToken;
+ VerificationToken verificationToken;
+ authToken.challenge = 0;
+ authToken.userId = 0;
+ authToken.authenticatorId = 0;
+ authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
+ authToken.timestamp.milliSeconds = 0;
+ authToken.mac.clear();
+ verificationToken.challenge = 0;
+ verificationToken.timestamp.milliSeconds = 0;
+ verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
+ verificationToken.mac.clear();
// Here's the actual test data:
const vector<test_utils::TestEntryData> testEntries = {
@@ -100,17 +116,16 @@
string cborPretty;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "attestationChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- ASSERT_EQ(binder::Status::EX_NONE, attData.result.exceptionCode());
- ASSERT_EQ(IIdentityCredentialStore::STATUS_OK, attData.result.serviceSpecificErrorCode());
- // TODO: set it to something random and check it's in the cert chain
- ASSERT_GE(attData.attestationCertificate.size(), 2);
+ EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
+ attData.attestationChallenge,
+ attData.attestationApplicationId, hwInfo));
// This is kinda of a hack but we need to give the size of
// ProofOfProvisioning that we'll expect to receive.
@@ -122,7 +137,7 @@
.isOk());
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
// Uses TestEntryData* pointer as key and values are the encrypted blobs. This
@@ -130,7 +145,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries) {
- ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -274,7 +289,10 @@
ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
- ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk());
+ // OK to fail, not available in v1 HAL
+ credential->setRequestedNamespaces(requestedNamespaces).isOk();
+ // OK to fail, not available in v1 HAL
+ credential->setVerificationToken(verificationToken);
ASSERT_TRUE(credential
->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
signingKeyBlob, sessionTranscriptBytes,
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index 724aaa1..8b0c050 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -56,8 +56,12 @@
TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
vector<uint8_t> attestationChallenge;
vector<Certificate> attestationCertificate;
@@ -68,13 +72,18 @@
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate));
+ EXPECT_TRUE(test_utils::validateAttestationCertificate(
+ attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
}
TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -87,17 +96,24 @@
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate));
+ EXPECT_TRUE(test_utils::validateAttestationCertificate(
+ attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
}
TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1";
test_utils::AttestationData attData(writableCredential, challenge, {});
- ASSERT_TRUE(test_utils::ValidateAttestationCertificate(attData.attestationCertificate));
+ ASSERT_TRUE(test_utils::validateAttestationCertificate(
+ attData.attestationCertificate, attData.attestationChallenge,
+ attData.attestationApplicationId, hwInfo));
string challenge2 = "NotSoRandomChallenge2";
test_utils::AttestationData attData2(writableCredential, challenge2, {});
@@ -110,7 +126,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// First call should go through
const vector<int32_t> entryCounts = {2, 4};
@@ -131,7 +147,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1, 1};
@@ -143,7 +159,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {0};
writableCredential->startPersonalization(0, entryCounts);
@@ -154,7 +170,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1};
@@ -166,7 +182,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify set a large number of profile count and entry count is ok
const vector<int32_t> entryCounts = {3000};
@@ -178,7 +194,7 @@
TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Enter mismatched entry and profile numbers
const vector<int32_t> entryCounts = {5, 6};
@@ -186,7 +202,7 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- optional<vector<uint8_t>> readerCertificate = test_utils::GenerateReaderCertificate("12345");
+ optional<vector<uint8_t>> readerCertificate = test_utils::generateReaderCertificate("12345");
ASSERT_TRUE(readerCertificate);
const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
@@ -196,7 +212,7 @@
{4, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
vector<uint8_t> credentialData;
@@ -205,7 +221,7 @@
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
// finishAddingEntries should fail because the number of addAccessControlProfile mismatched with
- // startPersonalization, and begintest_utils::AddEntry was not called.
+ // startPersonalization, and begintest_utils::addEntry was not called.
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
@@ -215,7 +231,7 @@
TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {3, 6};
writableCredential->startPersonalization(3, entryCounts);
@@ -272,14 +288,14 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1";
test_utils::AttestationData attData(writableCredential, challenge, {});
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
const vector<int32_t> entryCounts = {1u};
@@ -293,7 +309,7 @@
const vector<test_utils::TestProfile> testProfiles = {{1, readerCertificate1.value(), true, 1}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -302,7 +318,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -359,17 +375,17 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
- optional<vector<uint8_t>> readerCertificate2 = test_utils::GenerateReaderCertificate("1256");
+ optional<vector<uint8_t>> readerCertificate2 = test_utils::generateReaderCertificate("1256");
ASSERT_TRUE(readerCertificate2);
const vector<test_utils::TestProfile> testProfiles = {
@@ -386,14 +402,14 @@
<< endl;
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
vector<uint8_t> portraitImage1;
- test_utils::SetImageData(portraitImage1);
+ test_utils::setImageData(portraitImage1);
vector<uint8_t> portraitImage2;
- test_utils::SetImageData(portraitImage2);
+ test_utils::setImageData(portraitImage2);
const vector<test_utils::TestEntryData> testEntries1 = {
{"Name Space 1", "Last name", string("Turing"), vector<int32_t>{1, 2}},
@@ -411,7 +427,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -518,18 +534,18 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
optional<vector<uint8_t>> readerCertificate2 =
- test_utils::GenerateReaderCertificate("123456987987987987987987");
+ test_utils::generateReaderCertificate("123456987987987987987987");
ASSERT_TRUE(readerCertificate2);
const vector<int32_t> entryCounts = {2u, 2u};
@@ -547,7 +563,7 @@
{2, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -560,7 +576,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -580,7 +596,7 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
@@ -596,11 +612,11 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
optional<vector<uint8_t>> readerCertificate2 =
- test_utils::GenerateReaderCertificate("123456987987987987987987");
+ test_utils::generateReaderCertificate("123456987987987987987987");
ASSERT_TRUE(readerCertificate2);
const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0},
@@ -608,7 +624,7 @@
{2, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -619,13 +635,13 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
const test_utils::TestEntryData testEntry2 = {"Image", "Portrait image", string("asdfs"),
vector<int32_t>{0, 1}};
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, testEntry2, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, testEntry2, hwInfo.dataChunkSize,
encryptedBlobs, true));
// We expect this to fail because the namespace is out of order, all "Name Space"
@@ -637,7 +653,7 @@
};
for (const auto& entry : testEntries3) {
- EXPECT_FALSE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_FALSE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, false));
}
@@ -646,7 +662,7 @@
result =
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
- // should fail because test_utils::AddEntry should have failed earlier.
+ // should fail because test_utils::addEntry should have failed earlier.
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
@@ -655,7 +671,7 @@
TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {1};
Status result = writableCredential->startPersonalization(1, entryCounts);
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp
index 48e47dc..aaebcbe 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.cpp
+++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp
@@ -19,6 +19,8 @@
#include <aidl/Gtest.h>
#include <map>
+#include "VtsAttestationParserSupport.h"
+
namespace android::hardware::identity::test_utils {
using std::endl;
@@ -31,7 +33,7 @@
using ::android::String16;
using ::android::binder::Status;
-bool SetupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
+bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
sp<IIdentityCredentialStore>& credentialStore) {
if (credentialStore == nullptr) {
return false;
@@ -48,13 +50,13 @@
}
}
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal) {
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) {
vector<uint8_t> privKey;
- return GenerateReaderCertificate(serialDecimal, privKey);
+ return generateReaderCertificate(serialDecimal, &privKey);
}
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal,
- vector<uint8_t>& readerPrivateKey) {
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
+ vector<uint8_t>* outReaderPrivateKey) {
optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair();
if (!readerKeyPKCS8) {
return {};
@@ -67,7 +69,11 @@
return {};
}
- readerPrivateKey = readerKey.value();
+ if (outReaderPrivateKey == nullptr) {
+ return {};
+ }
+
+ *outReaderPrivateKey = readerKey.value();
string issuer = "Android Open Source Project";
string subject = "Android IdentityCredential VTS Test";
@@ -79,7 +85,7 @@
validityNotBefore, validityNotAfter);
}
-optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles(
+optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
sp<IWritableIdentityCredential>& writableCredential,
const vector<TestProfile>& testProfiles) {
Status result;
@@ -120,7 +126,7 @@
// Most test expects this function to pass. So we will print out additional
// value if failed so more debug data can be provided.
-bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
+bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
bool expectSuccess) {
Status result;
@@ -164,18 +170,70 @@
return true;
}
-bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates) {
- return (inputCertificates.size() >= 2);
- // TODO: add parsing of the certificate and make sure it is genuine.
-}
-
-void SetImageData(vector<uint8_t>& image) {
+void setImageData(vector<uint8_t>& image) {
image.resize(256 * 1024 - 10);
for (size_t n = 0; n < image.size(); n++) {
image[n] = (uint8_t)n;
}
}
+bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+ const vector<uint8_t>& expectedChallenge,
+ const vector<uint8_t>& expectedAppId,
+ const HardwareInformation& hwInfo) {
+ AttestationCertificateParser certParser_(inputCertificates);
+ bool ret = certParser_.parse();
+ EXPECT_TRUE(ret);
+ if (!ret) {
+ return false;
+ }
+
+ // As per the IC HAL, the version of the Identity
+ // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
+ // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
+ // and integers greater or equal than 41 (for KM starting with 4.1).
+ //
+ // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
+ // version isn't errornously returned.
+ EXPECT_LE(10, certParser_.getKeymasterVersion());
+ EXPECT_GT(40, certParser_.getKeymasterVersion());
+ EXPECT_LE(3, certParser_.getAttestationVersion());
+
+ // Verify the app id matches to whatever we set it to be.
+ optional<vector<uint8_t>> appId =
+ certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
+ if (appId) {
+ EXPECT_EQ(expectedAppId.size(), appId.value().size());
+ EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
+ } else {
+ // app id not found
+ EXPECT_EQ(0, expectedAppId.size());
+ }
+
+ EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+ EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
+
+ // Verify the challenge always matches in size and data of what is passed
+ // in.
+ vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
+ EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
+ EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
+
+ // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
+ // for the reference implementation which cannot be implemented in secure hardware).
+ if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
+ hwInfo.credentialStoreAuthorName == "Google") {
+ EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
+ EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
+
+ } else {
+ // Actual devices should use TrustedEnvironment or StrongBox.
+ EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
+ EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
+ }
+ return true;
+}
+
vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
vector<RequestNamespace> ret;
RequestNamespace curNs;
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h
index 9e1f352..673b736 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.h
+++ b/identity/aidl/vts/VtsIdentityTestUtils.h
@@ -93,25 +93,28 @@
uint64_t timeoutMillis;
};
-bool SetupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
+bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
sp<IIdentityCredentialStore>& credentialStore);
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal);
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal,
- vector<uint8_t>& readerPrivateKey);
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
+ vector<uint8_t>* outReaderPrivateKey);
-optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles(
+optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
sp<IWritableIdentityCredential>& writableCredential,
const vector<TestProfile>& testProfiles);
-bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
+bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
bool expectSuccess);
-bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates);
+void setImageData(vector<uint8_t>& image);
-void SetImageData(vector<uint8_t>& image);
+bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+ const vector<uint8_t>& expectedChallenge,
+ const vector<uint8_t>& expectedAppId,
+ const HardwareInformation& hwInfo);
vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries);
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 61645f8..f585d62 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
+#include <optional>
+#include <vector>
namespace android {
namespace hardware {
@@ -52,6 +54,15 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+// Serializes and deserializes a verification token. This format is private and
+// not stable between releases and should not be persisted to disk.
+//
+// Currently doesn't support the |parametersVerified| field, will fail if set.
+//
+std::optional<VerificationToken> deserializeVerificationToken(
+ const std::vector<uint8_t>& serializedToken);
+std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token);
+
uint32_t getOsVersion();
uint32_t getOsPatchlevel();
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index 850a776..366cd0e 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -16,6 +16,7 @@
#include <regex.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
@@ -110,6 +111,80 @@
return token;
}
+void appendUint64(std::vector<uint8_t>& vec, uint64_t value) {
+ for (size_t n = 0; n < sizeof(uint64_t); n++) {
+ uint8_t byte = (value >> (n * 8)) & 0xff;
+ vec.push_back(byte);
+ }
+}
+
+uint64_t extractUint64(const std::vector<uint8_t>& data, size_t offset) {
+ uint64_t value = 0;
+ for (size_t n = 0; n < sizeof(uint64_t); n++) {
+ uint8_t byte = data[offset + n];
+ value |= byte << (n * 8);
+ }
+ return value;
+}
+
+void appendUint32(std::vector<uint8_t>& vec, uint32_t value) {
+ for (size_t n = 0; n < sizeof(uint32_t); n++) {
+ uint8_t byte = (value >> (n * 8)) & 0xff;
+ vec.push_back(byte);
+ }
+}
+
+uint32_t extractUint32(const std::vector<uint8_t>& data, size_t offset) {
+ uint32_t value = 0;
+ for (size_t n = 0; n < sizeof(uint32_t); n++) {
+ uint8_t byte = data[offset + n];
+ value |= byte << (n * 8);
+ }
+ return value;
+}
+
+std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token) {
+ if (token.parametersVerified.size() > 0) {
+ LOG(ERROR) << "Serializing verification tokens with parametersVerified is not supported";
+ return {};
+ }
+ if (!(token.mac.size() == 0 || token.mac.size() == 32)) {
+ LOG(ERROR) << "Unexpected MAC size " << token.mac.size() << ", expected 0 or 32";
+ return {};
+ }
+ std::vector<uint8_t> serializedToken;
+ appendUint64(serializedToken, token.challenge);
+ appendUint64(serializedToken, token.timestamp);
+ appendUint32(serializedToken, uint32_t(token.securityLevel));
+ appendUint32(serializedToken, token.mac.size());
+ serializedToken.insert(serializedToken.end(), token.mac.begin(), token.mac.end());
+ return serializedToken;
+}
+
+std::optional<VerificationToken> deserializeVerificationToken(
+ const std::vector<uint8_t>& serializedToken) {
+ if (serializedToken.size() < 24) {
+ LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
+ << ", expected at least 24 bytes";
+ return {};
+ }
+ VerificationToken token;
+ token.challenge = extractUint64(serializedToken, 0);
+ token.timestamp = extractUint64(serializedToken, 8);
+ token.securityLevel = SecurityLevel(extractUint32(serializedToken, 16));
+ size_t macSize = extractUint32(serializedToken, 20);
+ size_t expectedSerializedSize = 24 + macSize;
+ if (serializedToken.size() != expectedSerializedSize) {
+ LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
+ << ", expected " << expectedSerializedSize;
+ return {};
+ }
+ if (macSize > 0) {
+ token.mac = std::vector<uint8_t>(serializedToken.begin() + 24, serializedToken.end());
+ }
+ return token;
+}
+
namespace {
constexpr char kPlatformVersionProp[] = "ro.build.version.release";
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 3011da6..5206721 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -15,5 +15,17 @@
},
},
},
- versions: ["1"],
+ versions: [
+ "1",
+ "2",
+ ],
+}
+
+// This is a reminder that the next version of keymaster should be frozen at
+// version "5" to avoid confusion with other versions of this interface.
+cc_library {
+ name: "android.hardware.keymaster-V3-java",
+}
+cc_library {
+ name: "android.hardware.keymaster-V4-java",
}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash
new file mode 100644
index 0000000..9d5974e
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash
@@ -0,0 +1 @@
+91ab0be1887410935f564e3938ff12c5f5f8c59d
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl
new file mode 100644
index 0000000..db1df2b
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable HardwareAuthToken {
+ long challenge;
+ long userId;
+ long authenticatorId;
+ android.hardware.keymaster.HardwareAuthenticatorType authenticatorType;
+ android.hardware.keymaster.Timestamp timestamp;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..924567f
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum HardwareAuthenticatorType {
+ NONE = 0,
+ PASSWORD = 1,
+ FINGERPRINT = 2,
+ ANY = -1,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..127c1bf
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl
new file mode 100644
index 0000000..45fa1ae
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable Timestamp {
+ long milliSeconds;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..0633765
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable VerificationToken {
+ long challenge;
+ android.hardware.keymaster.Timestamp timestamp;
+ android.hardware.keymaster.SecurityLevel securityLevel;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..127c1bf
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..0633765
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable VerificationToken {
+ long challenge;
+ android.hardware.keymaster.Timestamp timestamp;
+ android.hardware.keymaster.SecurityLevel securityLevel;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..f129783
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.hardware.keymaster;
+
+/**
+ * Device security levels.
+ */
+@VintfStability
+@Backing(type="int")
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ /**
+ * STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD
+ * 9.11.2.
+ */
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..eff9ca6
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package android.hardware.keymaster;
+
+import android.hardware.keymaster.SecurityLevel;
+import android.hardware.keymaster.Timestamp;
+import android.hardware.keymaster.HardwareAuthenticatorType;
+
+/**
+ * VerificationToken instances are used for secure environments to authenticate one another.
+ *
+ * This version of the parcelable currently don't use the parametersVerified field since it's not
+ * needed for time-based verification. This can be added in a later version, if needed.
+ */
+@VintfStability
+parcelable VerificationToken {
+ /**
+ * The operation handle, used to ensure freshness.
+ */
+ long challenge;
+
+ /**
+ * The current time of the secure environment that generates the VerificationToken. This can be
+ * checked against auth tokens generated by the same secure environment, which avoids needing to
+ * synchronize clocks.
+ */
+ Timestamp timestamp;
+
+ /**
+ * SecurityLevel of the secure environment that generated the token.
+ */
+ SecurityLevel securityLevel;
+
+ /**
+ * 32-byte HMAC-SHA256 of the above values, computed as:
+ *
+ * HMAC(H,
+ * "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified)
+ *
+ * where:
+ *
+ * ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeymaster).
+ *
+ * ``||'' 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.
+ *
+ * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
+ * encoded representation of the values. The ASN.1 schema used is the AuthorizationList schema
+ * from the Keystore attestation documentation. If parametersVerified is empty, it is simply
+ * omitted from the HMAC computation.
+ */
+ byte[] mac;
+}
diff --git a/sensors/1.0/vts/functional/AndroidTest.xml b/sensors/1.0/vts/functional/AndroidTest.xml
index fb0d64c..5011f09 100644
--- a/sensors/1.0/vts/functional/AndroidTest.xml
+++ b/sensors/1.0/vts/functional/AndroidTest.xml
@@ -17,13 +17,8 @@
<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.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
- <option name="teardown-command" value="start"/>
- </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
diff --git a/sensors/2.0/vts/functional/AndroidTest.xml b/sensors/2.0/vts/functional/AndroidTest.xml
index b710ed0..b7658a9 100644
--- a/sensors/2.0/vts/functional/AndroidTest.xml
+++ b/sensors/2.0/vts/functional/AndroidTest.xml
@@ -17,13 +17,8 @@
<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.RunCommandTargetPreparer">
- <option name="run-command" value="stop"/>
- <option name="teardown-command" value="start"/>
- </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />