Merge "power/stats: Add more energy consumer types"
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
index 99c2e5a..bea0705 100644
--- a/audio/common/7.0/types.hal
+++ b/audio/common/7.0/types.hal
@@ -61,6 +61,8 @@
* Audio stream type describing the intended use case of a stream.
* See 'audioStreamType' in audio_policy_configuration.xsd for the
* list of allowed values.
+ *
+ * An empty string is used to specify the "default" stream type.
*/
typedef string AudioStreamType;
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index bb3a596..2949fac 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -335,25 +335,35 @@
return BAD_VALUE;
}
+// The "default" value of audio_stream_type_t is represented by an empty string.
status_t HidlUtils::audioStreamTypeFromHal(audio_stream_type_t halStreamType,
AudioStreamType* streamType) {
- *streamType = audio_stream_type_to_string(halStreamType);
- if (!streamType->empty() && !xsd::isUnknownAudioStreamType(*streamType)) {
+ if (halStreamType != AUDIO_STREAM_DEFAULT) {
+ *streamType = audio_stream_type_to_string(halStreamType);
+ if (!streamType->empty() && !xsd::isUnknownAudioStreamType(*streamType)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio stream type value 0x%X", halStreamType);
+ return BAD_VALUE;
+ } else {
+ *streamType = "";
return NO_ERROR;
}
- ALOGE("Unknown audio stream type value 0x%X", halStreamType);
- return BAD_VALUE;
}
status_t HidlUtils::audioStreamTypeToHal(const AudioStreamType& streamType,
audio_stream_type_t* halStreamType) {
- if (!xsd::isUnknownAudioStreamType(streamType) &&
- audio_stream_type_from_string(streamType.c_str(), halStreamType)) {
+ if (!streamType.empty()) {
+ if (!xsd::isUnknownAudioStreamType(streamType) &&
+ audio_stream_type_from_string(streamType.c_str(), halStreamType)) {
+ return NO_ERROR;
+ }
+ ALOGE("Unknown audio stream type \"%s\"", streamType.c_str());
+ return BAD_VALUE;
+ } else {
+ *halStreamType = AUDIO_STREAM_DEFAULT;
return NO_ERROR;
}
- ALOGE("Unknown audio stream type \"%s\"", streamType.c_str());
- *halStreamType = AUDIO_STREAM_DEFAULT;
- return BAD_VALUE;
}
status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, bool isInput,
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index 45f0b8f..29a3d6f 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -114,7 +114,7 @@
],
}
-cc_library_shared {
+cc_library {
name: "android.hardware.audio.common@6.0-util",
defaults: ["android.hardware.audio.common-util_default"],
srcs: [":android.hardware.audio.common-util@2-6"],
@@ -152,6 +152,32 @@
// Note: this isn't a VTS test, but rather a unit test
// to verify correctness of conversion utilities.
cc_test {
+ name: "android.hardware.audio.common@6.0-util_tests",
+ defaults: ["android.hardware.audio.common-util_default"],
+
+ srcs: ["tests/hidlutils6_tests.cpp"],
+
+ // Use static linking to allow running in presubmit on
+ // targets that don't have HAL V6.
+ static_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ],
+
+ test_suites: ["device-tests"],
+}
+
+// Note: this isn't a VTS test, but rather a unit test
+// to verify correctness of conversion utilities.
+cc_test {
name: "android.hardware.audio.common@7.0-util_tests",
defaults: ["android.hardware.audio.common-util_default"],
diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h
index 22b7152..dd4ca4d 100644
--- a/audio/common/all-versions/default/HidlUtils.h
+++ b/audio/common/all-versions/default/HidlUtils.h
@@ -210,6 +210,9 @@
*halDeviceType == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s",
device.rSubmixAddress.c_str());
+ } else {
+ // Fall back to bus address for other device types, e.g. for microphones.
+ snprintf(halDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s", device.busAddress.c_str());
}
return NO_ERROR;
}
@@ -249,6 +252,7 @@
device->rSubmixAddress = halDeviceAddress;
return OK;
}
+ // Fall back to bus address for other device types, e.g. for microphones.
device->busAddress = halDeviceAddress;
return NO_ERROR;
}
diff --git a/audio/common/all-versions/default/TEST_MAPPING b/audio/common/all-versions/default/TEST_MAPPING
index 4316ccf..c965113 100644
--- a/audio/common/all-versions/default/TEST_MAPPING
+++ b/audio/common/all-versions/default/TEST_MAPPING
@@ -1,6 +1,9 @@
{
"presubmit": [
{
+ "name": "android.hardware.audio.common@6.0-util_tests"
+ },
+ {
"name": "android.hardware.audio.common@7.0-util_tests"
}
]
diff --git a/audio/common/all-versions/default/tests/hidlutils6_tests.cpp b/audio/common/all-versions/default/tests/hidlutils6_tests.cpp
new file mode 100644
index 0000000..3a24e75
--- /dev/null
+++ b/audio/common/all-versions/default/tests/hidlutils6_tests.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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 <gtest/gtest.h>
+
+#define LOG_TAG "HidlUtils_Test"
+#include <log/log.h>
+
+#include <HidlUtils.h>
+#include <system/audio.h>
+
+using namespace android;
+using namespace ::android::hardware::audio::common::CPP_VERSION;
+using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
+
+// Not generated automatically because DeviceAddress contains
+// an union.
+//
+// operator== must be defined in the same namespace as the data type.
+namespace android::hardware::audio::common::CPP_VERSION {
+
+inline bool operator==(const DeviceAddress& lhs, const DeviceAddress& rhs) {
+ if (lhs.device != rhs.device) return false;
+ audio_devices_t halDeviceType = static_cast<audio_devices_t>(lhs.device);
+ if (audio_is_a2dp_out_device(halDeviceType) || audio_is_a2dp_in_device(halDeviceType)) {
+ return lhs.address.mac == rhs.address.mac;
+ } else if (halDeviceType == AUDIO_DEVICE_OUT_IP || halDeviceType == AUDIO_DEVICE_IN_IP) {
+ return lhs.address.ipv4 == rhs.address.ipv4;
+ } else if (audio_is_usb_out_device(halDeviceType) || audio_is_usb_in_device(halDeviceType)) {
+ return lhs.address.alsa == rhs.address.alsa;
+ } else if (halDeviceType == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+ halDeviceType == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ return lhs.rSubmixAddress == rhs.rSubmixAddress;
+ }
+ // busAddress field can be used for types other than bus, e.g. for microphones.
+ return lhs.busAddress == rhs.busAddress;
+}
+
+} // namespace android::hardware::audio::common::CPP_VERSION
+
+static void ConvertDeviceAddress(const DeviceAddress& device) {
+ audio_devices_t halDeviceType;
+ char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN] = {};
+ EXPECT_EQ(NO_ERROR, HidlUtils::deviceAddressToHal(device, &halDeviceType, halDeviceAddress));
+ DeviceAddress deviceBack;
+ EXPECT_EQ(NO_ERROR,
+ HidlUtils::deviceAddressFromHal(halDeviceType, halDeviceAddress, &deviceBack));
+ EXPECT_EQ(device, deviceBack);
+}
+
+TEST(HidlUtils6, ConvertUniqueDeviceAddress) {
+ DeviceAddress speaker;
+ speaker.device = AudioDevice::OUT_SPEAKER;
+ ConvertDeviceAddress(speaker);
+
+ DeviceAddress micWithAddress;
+ micWithAddress.device = AudioDevice::IN_BUILTIN_MIC;
+ micWithAddress.busAddress = "bottom";
+ ConvertDeviceAddress(micWithAddress);
+}
+
+TEST(HidlUtils6, ConvertA2dpDeviceAddress) {
+ DeviceAddress a2dpSpeaker;
+ a2dpSpeaker.device = AudioDevice::OUT_BLUETOOTH_A2DP_SPEAKER;
+ a2dpSpeaker.address.mac = std::array<uint8_t, 6>{1, 2, 3, 4, 5, 6};
+ ConvertDeviceAddress(a2dpSpeaker);
+}
+
+TEST(HidlUtils6, ConvertIpv4DeviceAddress) {
+ DeviceAddress ipv4;
+ ipv4.device = AudioDevice::OUT_IP;
+ ipv4.address.ipv4 = std::array<uint8_t, 4>{1, 2, 3, 4};
+ ConvertDeviceAddress(ipv4);
+}
+
+TEST(HidlUtils6, ConvertUsbDeviceAddress) {
+ DeviceAddress usbHeadset;
+ usbHeadset.device = AudioDevice::OUT_USB_HEADSET;
+ usbHeadset.address.alsa = {1, 2};
+ ConvertDeviceAddress(usbHeadset);
+}
+
+TEST(HidlUtils6, ConvertBusDeviceAddress) {
+ DeviceAddress bus;
+ bus.device = AudioDevice::OUT_BUS;
+ bus.busAddress = "bus_device";
+ ConvertDeviceAddress(bus);
+}
+
+TEST(HidlUtils6, ConvertRSubmixDeviceAddress) {
+ DeviceAddress rSubmix;
+ rSubmix.device = AudioDevice::OUT_REMOTE_SUBMIX;
+ rSubmix.rSubmixAddress = AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
+ ConvertDeviceAddress(rSubmix);
+}
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
index 40fc5c8..ec6bdf3 100644
--- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -44,8 +44,8 @@
static_cast<audio_gain_mode_t>(0xFFFFFFFFU);
// AUDIO_SOURCE_INVALID is framework-only.
static constexpr audio_source_t kInvalidHalSource = static_cast<audio_source_t>(-1);
-static constexpr audio_stream_type_t kInvalidHalStreamType =
- static_cast<audio_stream_type_t>(0xFFFFFFFFU);
+// AUDIO_STREAM_DEFAULT is framework-only
+static constexpr audio_stream_type_t kInvalidHalStreamType = static_cast<audio_stream_type_t>(-2);
static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(0xFFFFFFFFU);
TEST(HidlUtils, ConvertInvalidChannelMask) {
@@ -476,6 +476,11 @@
DeviceAddress speaker;
speaker.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER);
ConvertDeviceAddress(speaker);
+
+ DeviceAddress micWithAddress;
+ micWithAddress.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC);
+ micWithAddress.address.id("bottom");
+ ConvertDeviceAddress(micWithAddress);
}
TEST(HidlUtils, ConvertA2dpDeviceAddress) {
@@ -660,10 +665,18 @@
AudioStreamType invalid;
EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeFromHal(kInvalidHalStreamType, &invalid));
audio_stream_type_t halInvalid;
- EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeToHal("", &halInvalid));
EXPECT_EQ(BAD_VALUE, HidlUtils::audioStreamTypeToHal("random string", &halInvalid));
}
+TEST(HidlUtils, ConvertDefaultStreamType) {
+ AudioStreamType streamDefault = "";
+ audio_stream_type_t halStreamDefault;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeToHal(streamDefault, &halStreamDefault));
+ AudioStreamType streamDefaultBack;
+ EXPECT_EQ(NO_ERROR, HidlUtils::audioStreamTypeFromHal(halStreamDefault, &streamDefaultBack));
+ EXPECT_EQ(streamDefault, streamDefaultBack);
+}
+
TEST(HidlUtils, ConvertStreamType) {
for (const auto enumVal : xsdc_enum_range<xsd::AudioStreamType>{}) {
const AudioStreamType streamType = toString(enumVal);
diff --git a/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
index 95903d1..57fa07b 100644
--- a/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
+++ b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
@@ -1032,7 +1032,7 @@
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareHidlTest,
- StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
+ DISABLED_StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
bool is_codec_config_valid;
std::unique_ptr<DataMQ> tempDataMQ;
auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
@@ -1126,7 +1126,7 @@
* stopped with different PCM config
*/
TEST_P(BluetoothAudioProviderLeAudioInputSoftwareHidlTest,
- StartAndEndLeAudioInputSessionWithPossiblePcmConfig) {
+ DISABLED_StartAndEndLeAudioInputSessionWithPossiblePcmConfig) {
bool is_codec_config_valid;
std::unique_ptr<DataMQ> tempDataMQ;
auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f1078cd..5b411d2 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -9,7 +9,6 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
- <!-- TODO(b/142480271): remove 6.0 when implemented on reference device. -->
<version>6.0</version>
<version>7.0</version>
<interface>
@@ -19,7 +18,6 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.audio.effect</name>
- <!-- TODO(b/142480271): remove 6.0 when implemented on reference device. -->
<version>6.0</version>
<version>7.0</version>
<interface>
@@ -326,6 +324,13 @@
</interface>
</hal>
<hal format="aidl" optional="true">
+ <name>android.hardware.security.keymint</name>
+ <interface>
+ <name>IRemotelyProvisionedComponent</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="aidl" optional="true">
<name>android.hardware.light</name>
<version>1</version>
<interface>
diff --git a/health/utils/libhealth2impl/Health.cpp b/health/utils/libhealth2impl/Health.cpp
index f4684ae..035b36f 100644
--- a/health/utils/libhealth2impl/Health.cpp
+++ b/health/utils/libhealth2impl/Health.cpp
@@ -80,14 +80,14 @@
Return<Result> Health::update() {
Result result = Result::UNKNOWN;
- getHealthInfo_2_1([&](auto res, const auto& /* health_info */) {
+ getHealthInfo_2_1([&](auto res, const auto& health_info) {
result = res;
if (res != Result::SUCCESS) {
LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
return;
}
- battery_monitor_.logValues();
+ BatteryMonitor::logValues(health_info, *healthd_config_);
});
return result;
}
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 38348ac..6418028 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -833,9 +833,16 @@
optional<vector<vector<uint8_t>>> createAttestation(
const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+ // Pretend to be implemented in a trusted environment just so we can pass
+ // the VTS tests. Of course, this is a pretend-only game since hopefully no
+ // relying party is ever going to trust our batch key and those keys above
+ // it.
+ ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+ KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
keymaster_error_t error;
::keymaster::CertificateChain attestation_chain =
- ::keymaster::getAttestationChain(KM_ALGORITHM_EC, &error);
+ context.GetAttestationChain(KM_ALGORITHM_EC, &error);
if (KM_ERROR_OK != error) {
LOG(ERROR) << "Error getting attestation chain " << error;
return {};
@@ -855,12 +862,6 @@
}
expireTimeMilliSeconds = bcNotAfter * 1000;
}
- const keymaster_key_blob_t* attestation_signing_key =
- ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
- if (attestation_signing_key == nullptr) {
- LOG(ERROR) << "Error getting attestation key";
- return {};
- }
::keymaster::X509_NAME_Ptr subjectName;
if (KM_ERROR_OK !=
@@ -874,8 +875,11 @@
i2d_X509_NAME(subjectName.get(), &subjectPtr);
+ uint64_t nowMilliSeconds = time(nullptr) * 1000;
::keymaster::AuthorizationSet auth_set(
::keymaster::AuthorizationSetBuilder()
+ .Authorization(::keymaster::TAG_CERTIFICATE_NOT_BEFORE, nowMilliSeconds)
+ .Authorization(::keymaster::TAG_CERTIFICATE_NOT_AFTER, expireTimeMilliSeconds)
.Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
challenge.size())
.Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds)
@@ -914,19 +918,11 @@
}
::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
- // Pretend to be implemented in a trusted environment just so we can pass
- // the VTS tests. Of course, this is a pretend-only game since hopefully no
- // relying party is ever going to trust our batch key and those keys above
- // it.
- ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
- KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
-
- ::keymaster::CertificateChain cert_chain_out = generate_attestation_from_EVP(
- key, swEnforced, hwEnforced, auth_set, context, move(attestation_chain),
- *attestation_signing_key, &error);
+ ::keymaster::CertificateChain cert_chain_out = generate_attestation(
+ key, swEnforced, hwEnforced, auth_set, {} /* attest_key */, context, &error);
if (KM_ERROR_OK != error) {
- LOG(ERROR) << "Error generate attestation from EVP key" << error;
+ LOG(ERROR) << "Error generating attestation from EVP key: " << error;
return {};
}
diff --git a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/DeviceInfo.aidl b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/DeviceInfo.aidl
index 00abff9..3e25c56 100644
--- a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/DeviceInfo.aidl
+++ b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/DeviceInfo.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/IMemtrack.aidl b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/IMemtrack.aidl
index 844a1bb..2e2b68e 100644
--- a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/IMemtrack.aidl
+++ b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/IMemtrack.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackRecord.aidl b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackRecord.aidl
index 09ecefc..0e15ce3 100644
--- a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackRecord.aidl
+++ b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackRecord.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackType.aidl b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackType.aidl
index 7f3f939..b19869e 100644
--- a/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackType.aidl
+++ b/memtrack/aidl/aidl_api/android.hardware.memtrack/current/android/hardware/memtrack/MemtrackType.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
@@ -23,5 +38,4 @@
GRAPHICS = 2,
MULTIMEDIA = 3,
CAMERA = 4,
- NUM_TYPES = 5,
}
diff --git a/memtrack/aidl/android/hardware/memtrack/MemtrackType.aidl b/memtrack/aidl/android/hardware/memtrack/MemtrackType.aidl
index 715c6bf..5db735a 100644
--- a/memtrack/aidl/android/hardware/memtrack/MemtrackType.aidl
+++ b/memtrack/aidl/android/hardware/memtrack/MemtrackType.aidl
@@ -27,5 +27,4 @@
GRAPHICS = 2,
MULTIMEDIA = 3,
CAMERA = 4,
- NUM_TYPES,
}
diff --git a/memtrack/aidl/default/Memtrack.cpp b/memtrack/aidl/default/Memtrack.cpp
index 000b25c..49a6582 100644
--- a/memtrack/aidl/default/Memtrack.cpp
+++ b/memtrack/aidl/default/Memtrack.cpp
@@ -26,7 +26,8 @@
if (pid < 0) {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
- if (type < MemtrackType::OTHER || type >= MemtrackType::NUM_TYPES) {
+ if (type != MemtrackType::OTHER && type != MemtrackType::GL && type != MemtrackType::GRAPHICS &&
+ type != MemtrackType::MULTIMEDIA && type != MemtrackType::CAMERA) {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
_aidl_return->clear();
diff --git a/memtrack/aidl/vts/Android.bp b/memtrack/aidl/vts/Android.bp
index df87db8..eff2a56 100644
--- a/memtrack/aidl/vts/Android.bp
+++ b/memtrack/aidl/vts/Android.bp
@@ -13,6 +13,6 @@
"android.hardware.memtrack-V1-ndk_platform",
],
test_suites: [
- "vts-core",
+ "vts",
],
}
diff --git a/memtrack/aidl/vts/VtsHalMemtrackTargetTest.cpp b/memtrack/aidl/vts/VtsHalMemtrackTargetTest.cpp
index d5f4612..8905f50 100644
--- a/memtrack/aidl/vts/VtsHalMemtrackTargetTest.cpp
+++ b/memtrack/aidl/vts/VtsHalMemtrackTargetTest.cpp
@@ -46,17 +46,19 @@
TEST_P(MemtrackAidlTest, GetMemoryInvalidPid) {
int pid = -1;
- MemtrackType type = MemtrackType::OTHER;
- std::vector<MemtrackRecord> records;
- auto status = memtrack_->getMemory(pid, type, &records);
+ for (MemtrackType type : ndk::enum_range<MemtrackType>()) {
+ std::vector<MemtrackRecord> records;
- EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ auto status = memtrack_->getMemory(pid, type, &records);
+
+ EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ }
}
TEST_P(MemtrackAidlTest, GetMemoryInvalidType) {
int pid = 1;
- MemtrackType type = MemtrackType::NUM_TYPES;
+ MemtrackType type = static_cast<MemtrackType>(-1);
std::vector<MemtrackRecord> records;
auto status = memtrack_->getMemory(pid, type, &records);
@@ -66,12 +68,13 @@
TEST_P(MemtrackAidlTest, GetMemory) {
int pid = 1;
- MemtrackType type = MemtrackType::OTHER;
- std::vector<MemtrackRecord> records;
+ for (MemtrackType type : ndk::enum_range<MemtrackType>()) {
+ std::vector<MemtrackRecord> records;
- auto status = memtrack_->getMemory(pid, type, &records);
+ auto status = memtrack_->getMemory(pid, type, &records);
- EXPECT_TRUE(status.isOk());
+ EXPECT_TRUE(status.isOk());
+ }
}
TEST_P(MemtrackAidlTest, GetGpuDeviceInfo) {
@@ -87,7 +90,7 @@
->getRuntimeInfo(RuntimeInfo::FetchFlag::CPU_VERSION)
->kernelVersion();
EXPECT_LT(kernel_version, min_kernel_version)
- << "Devices with 5.10 or later kernels must implement getGpuDeviceInfo()";
+ << "Devices with 5.4 or later kernels must implement getGpuDeviceInfo()";
return;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferDesc.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferDesc.aidl
index 2074a2a..71b7758 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferDesc.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferDesc.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
index 97f748b..c2d636c 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Capabilities.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Capabilities.aidl
index 31afafc..01cc753 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Capabilities.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Capabilities.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DataLocation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DataLocation.aidl
index 5b03ba0..074cc09 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DataLocation.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DataLocation.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceBuffer.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceBuffer.aidl
index 9cff6db..7bc8aa7 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceBuffer.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceBuffer.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceType.aidl
index dd4dae7..1abacc8 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceType.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/DeviceType.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ErrorStatus.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ErrorStatus.aidl
index ba18c38..873c584 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ErrorStatus.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ErrorStatus.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionPreference.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionPreference.aidl
index cccae54..c4badc0 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionPreference.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionPreference.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionResult.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionResult.aidl
index c17ddb9..b99bb31 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionResult.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExecutionResult.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Extension.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Extension.aidl
index 9eb8896..a7ae942 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Extension.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Extension.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
index a271a63..4c25538 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
index d1c3f09..b32b217 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/FusedActivationFunc.aidl
index ddd3c2a..2fee136 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/FusedActivationFunc.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBuffer.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBuffer.aidl
index a297a6b..2860692 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBuffer.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBuffer.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
index 38fda16..4c5fd2f 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
index a7cf906..abe67b8 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
index 8767712..3ca1550 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelCallback.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
index d1ae2eb..8eaaab6 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelParcel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
index 048251a..8388fda 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
index aa735c0..3b2f240 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Model.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Model.aidl
index 944bd7f..9d12e58 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Model.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Model.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl
index ca5f917..c1e87da 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/NumberOfCacheFiles.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
index 6615b9b..bb78caa 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandExtraParams.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandExtraParams.aidl
index 20317c7..3f6d93b 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandExtraParams.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandExtraParams.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandLifeTime.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandLifeTime.aidl
index 1082f9e..d581ced 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandLifeTime.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandLifeTime.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
index 9232b4c..87fd3a6 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandType.aidl
index bd95fab..186c13d 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandType.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandType.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
index 383eba4..fec83a8 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
index f786829..ad42b02 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OutputShape.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OutputShape.aidl
index 1300c49..09a43f7 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OutputShape.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OutputShape.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PerformanceInfo.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PerformanceInfo.aidl
index b5dc179..178946c 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PerformanceInfo.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/PerformanceInfo.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Priority.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Priority.aidl
index 980bee3..d9b77fa 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Priority.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Priority.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Request.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Request.aidl
index 6f77066..599b3f4 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Request.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Request.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestArgument.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestArgument.aidl
index c9560ef..91b9aa7 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestArgument.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestArgument.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestMemoryPool.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestMemoryPool.aidl
index 123e4b0..3813b51 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestMemoryPool.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/RequestMemoryPool.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Subgraph.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Subgraph.aidl
index 771d15a..dec976f 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Subgraph.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Subgraph.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
index 2282feb..66fdfe7 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
index b08d34a..d0de34a 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
@@ -1,14 +1,29 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferDesc.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferDesc.aidl
index 1b92ebc..bec7e86 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferDesc.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferDesc.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
index 7877bc0..0d7f678 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Capabilities.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Capabilities.aidl
index 5ce78ee..3802f1f 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Capabilities.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Capabilities.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperandPerformance;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/DataLocation.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/DataLocation.aidl
index 57e3f4a..f6b5e0d 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/DataLocation.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/DataLocation.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceBuffer.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceBuffer.aidl
index d51e1b2..07930a6 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceBuffer.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceBuffer.aidl
@@ -14,15 +14,15 @@
* limitations under the License.
*/
- package android.hardware.neuralnetworks;
+package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.IBuffer;
/**
* A type that is used to represent a driver allocated buffer and token that corresponds to it.
*/
- @VintfStability
- parcelable DeviceBuffer {
+@VintfStability
+parcelable DeviceBuffer {
/**
* An IBuffer object used to interact with the device allocated buffer.
*/
@@ -33,4 +33,4 @@
* with the tokens of other IBuffer objects that are currently alive in the same driver service.
*/
int token;
- }
\ No newline at end of file
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceType.aidl
index 8399d50..815be64 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/DeviceType.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ErrorStatus.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ErrorStatus.aidl
index 860f86a..c2752d9 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ErrorStatus.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ErrorStatus.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionPreference.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionPreference.aidl
index 901cb38..a3e3ce3 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionPreference.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionPreference.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionResult.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionResult.aidl
index 403fe09..1f88207 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionResult.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExecutionResult.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
@@ -44,4 +43,3 @@
*/
Timing timing;
}
-
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
index 159e3c1..20109bd 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Extension.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ExtensionOperandTypeInformation;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
index 76074bf..29be93f 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionNameAndPrefix.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
index d7f93c1..b8e3449 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/ExtensionOperandTypeInformation.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
@@ -35,4 +34,3 @@
*/
int byteSize;
}
-
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
index 40f1053..861b6f0 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBuffer.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBuffer.aidl
index eb3dec6..2915a22 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBuffer.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBuffer.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Memory;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
index 0c4954c..e17e0cd 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.BufferDesc;
@@ -114,7 +113,7 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
DeviceBuffer allocate(in BufferDesc desc, in IPreparedModelParcel[] preparedModels,
- in BufferRole[] inputRoles, in BufferRole[] outputRoles);
+ in BufferRole[] inputRoles, in BufferRole[] outputRoles);
/**
* Gets the capabilities of a driver.
@@ -345,8 +344,9 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
void prepareModel(in Model model, in ExecutionPreference preference, in Priority priority,
- in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache,
- in byte[] token, in IPreparedModelCallback callback);
+ in long deadline, in ParcelFileDescriptor[] modelCache,
+ in ParcelFileDescriptor[] dataCache, in byte[] token,
+ in IPreparedModelCallback callback);
/**
* Creates a prepared model from cache files for execution.
@@ -427,5 +427,6 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache,
- in ParcelFileDescriptor[] dataCache, in byte[] token, in IPreparedModelCallback callback);
+ in ParcelFileDescriptor[] dataCache, in byte[] token,
+ in IPreparedModelCallback callback);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
index 47e5916..cb6db11 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IFencedExecutionCallback.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
index c1b2992..2414a4a 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.common.NativeHandle;
@@ -95,7 +94,7 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
ExecutionResult executeSynchronously(in Request request, in boolean measureTiming,
- in long deadline, in long loopTimeoutDuration);
+ in long deadline, in long loopTimeoutDuration);
/**
* Launch a fenced asynchronous execution on a prepared model.
@@ -168,6 +167,6 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
IFencedExecutionCallback executeFenced(in Request request, in ParcelFileDescriptor[] waitFor,
- in boolean measureTiming, in long deadline, in long loopTimeoutDuration, in long duration,
- out @nullable ParcelFileDescriptor syncFence);
+ in boolean measureTiming, in long deadline, in long loopTimeoutDuration,
+ in long duration, out @nullable ParcelFileDescriptor syncFence);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelCallback.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
index adb4218..29cca6d 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelCallback.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ErrorStatus;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelParcel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
index f198c3f..878b0ad 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModelParcel.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.IPreparedModel;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
index 8ecb067..870f0ae 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
@@ -16,7 +16,6 @@
package android.hardware.neuralnetworks;
import android.hardware.common.NativeHandle;
-
import android.os.ParcelFileDescriptor;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Model.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Model.aidl
index 3bb7318..2f11dec 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Model.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Model.aidl
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.ExtensionNameAndPrefix;
-import android.hardware.neuralnetworks.Subgraph;
import android.hardware.neuralnetworks.Memory;
+import android.hardware.neuralnetworks.Subgraph;
/**
* A Neural Network Model.
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
index 243a89d..4d2260f 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.DataLocation;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandExtraParams.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandExtraParams.aidl
index b0112ae..229754a 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandExtraParams.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandExtraParams.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.SymmPerChannelQuantParams;
@@ -37,4 +36,4 @@
* The format is up to individual extensions.
*/
byte[] extension;
-}
\ No newline at end of file
+}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandLifeTime.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandLifeTime.aidl
index 63d1971..1d18149 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandLifeTime.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandLifeTime.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
index 9a8c2cc..7fd86f9 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperandType;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandType.aidl
index 9274b6f..12edc0f 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandType.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
index acfb4b7..0c6032f 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.OperationType;
@@ -43,4 +42,3 @@
*/
int[] outputs;
}
-
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
index fd9da67..3f49154 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OutputShape.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OutputShape.aidl
index d206a25..f90a613 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OutputShape.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OutputShape.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/PerformanceInfo.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/PerformanceInfo.aidl
index 6ee29c2..6915c67 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/PerformanceInfo.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/PerformanceInfo.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Priority.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Priority.aidl
index fe87598..7dbf8e9 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Priority.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Priority.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Request.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Request.aidl
index 396ff30..dc138ba 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Request.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Request.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.RequestArgument;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestArgument.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestArgument.aidl
index e615fa6..8dc9252 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestArgument.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestArgument.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.DataLocation;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestMemoryPool.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestMemoryPool.aidl
index 166746d..faca2fe 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestMemoryPool.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/RequestMemoryPool.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Memory;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Subgraph.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Subgraph.aidl
index 0a76285..2e9c450 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Subgraph.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Subgraph.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
import android.hardware.neuralnetworks.Operand;
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
index 8ae41a4..eb47df0 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/SymmPerChannelQuantParams.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
index b04f74e..8130e08 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.hardware.neuralnetworks;
/**
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..893b016
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.security.keymint;
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable AttestationKey {
+ byte[] keyBlob;
+ android.hardware.security.keymint.KeyParameter[] attestKeyParams;
+ byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
index a35b46c..3faba48 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -113,6 +113,8 @@
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
+ MISSING_ISSUER_SUBJECT = -82,
+ INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
UNKNOWN_ERROR = -1000,
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 132135b..d3c6910 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -35,13 +35,15 @@
interface IKeyMintDevice {
android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
void addRngEntropy(in byte[] data);
- android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams);
- android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData);
+ android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
+ android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
android.hardware.security.keymint.KeyCreationResult importWrappedKey(in byte[] wrappedKeyData, in byte[] wrappingKeyBlob, in byte[] maskingKey, in android.hardware.security.keymint.KeyParameter[] unwrappingParams, in long passwordSid, in long biometricSid);
- byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] inUpgradeParams);
- void deleteKey(in byte[] inKeyBlob);
+ byte[] upgradeKey(in byte[] keyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] upgradeParams);
+ void deleteKey(in byte[] keyBlob);
void deleteAllKeys();
void destroyAttestationIds();
- android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.security.keymint.KeyParameter[] inParams, in android.hardware.security.keymint.HardwareAuthToken inAuthToken);
+ android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
+ void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
+ void earlyBootEnded();
const int AUTH_TOKEN_MAC_LENGTH = 32;
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..a864c3c
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.security.keymint;
+@VintfStability
+interface IRemotelyProvisionedComponent {
+ byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
+ void generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac, out android.hardware.security.keymint.ProtectedData protectedData);
+ const int STATUS_FAILED = 1;
+ const int STATUS_INVALID_MAC = 2;
+ const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+ const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+ const int STATUS_INVALID_EEK = 5;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
index 93966ea..d06312a 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -37,4 +37,5 @@
android.hardware.security.keymint.SecurityLevel securityLevel;
@utf8InCpp String keyMintName;
@utf8InCpp String keyMintAuthorName;
+ boolean timestampTokenRequired;
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
index c1e92af..61bb7e4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
@@ -39,4 +39,5 @@
VERIFY = 3,
WRAP_KEY = 5,
AGREE_KEY = 6,
+ ATTEST_KEY = 7,
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
new file mode 100644
index 0000000..b4caeed
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.security.keymint;
+@VintfStability
+parcelable MacedPublicKey {
+ byte[] macedKey;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
new file mode 100644
index 0000000..46f602f
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.security.keymint;
+@VintfStability
+parcelable ProtectedData {
+ byte[] protectedData;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..8167ceb
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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.security.keymint;
+
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * Contains a key blob with Tag::ATTEST_KEY that can be used to sign an attestation certificate,
+ * and the DER-encoded X.501 Subject Name that will be placed in the Issuer field of the attestation
+ * certificate.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable AttestationKey {
+ byte[] keyBlob;
+ KeyParameter[] attestKeyParams;
+ byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
index 35e3827..5765130 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -103,6 +103,8 @@
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
+ MISSING_ISSUER_SUBJECT = -82,
+ INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 0120a30..13e98af 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -16,16 +16,18 @@
package android.hardware.security.keymint;
+import android.hardware.security.keymint.AttestationKey;
import android.hardware.security.keymint.BeginResult;
import android.hardware.security.keymint.ByteArray;
import android.hardware.security.keymint.HardwareAuthToken;
import android.hardware.security.keymint.IKeyMintOperation;
import android.hardware.security.keymint.KeyCreationResult;
import android.hardware.security.keymint.KeyFormat;
-import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyMintHardwareInfo;
+import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyPurpose;
import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.secureclock.TimeStampToken;
/**
* KeyMint device definition.
@@ -314,9 +316,18 @@
* provided in params. See above for detailed specifications of which tags are required
* for which types of keys.
*
+ * @param attestationKey, if provided, specifies the key that must be used to sign the
+ * attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+ * but `attestationKey` is non-null, the IKeyMintDevice must return
+ * ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
+ * blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+ * return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
+ * subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
- KeyCreationResult generateKey(in KeyParameter[] keyParams);
+ KeyCreationResult generateKey(
+ in KeyParameter[] keyParams, in @nullable AttestationKey attestationKey);
/**
* Imports key material into an IKeyMintDevice. Key definition parameters and return values
@@ -344,10 +355,18 @@
*
* @param inKeyData The key material to import, in the format specified in keyFormat.
*
+ * @param attestationKey, if provided, specifies the key that must be used to sign the
+ * attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+ * but `attestationKey` is non-null, the IKeyMintDevice must return
+ * ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
+ * blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+ * return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
+ * subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
KeyCreationResult importKey(in KeyParameter[] keyParams, in KeyFormat keyFormat,
- in byte[] keyData);
+ in byte[] keyData, in @nullable AttestationKey attestationKey);
/**
* Securely imports a key, or key pair, returning a key blob and a description of the imported
@@ -429,12 +448,9 @@
*
* @return The result of key creation. See KeyCreationResult.aidl.
*/
- KeyCreationResult importWrappedKey(in byte[] wrappedKeyData,
- in byte[] wrappingKeyBlob,
- in byte[] maskingKey,
- in KeyParameter[] unwrappingParams,
- in long passwordSid,
- in long biometricSid);
+ KeyCreationResult importWrappedKey(in byte[] wrappedKeyData, in byte[] wrappingKeyBlob,
+ in byte[] maskingKey, in KeyParameter[] unwrappingParams, in long passwordSid,
+ in long biometricSid);
/**
* Upgrades an old key blob. Keys can become "old" in two ways: IKeyMintDevice can be
@@ -469,7 +485,7 @@
* @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
* format, or has the new version data.
*/
- byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
+ byte[] upgradeKey(in byte[] keyBlobToUpgrade, in KeyParameter[] upgradeParams);
/**
* Deletes the key, or key pair, associated with the key blob. Calling this function on
@@ -479,7 +495,7 @@
*
* @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
*/
- void deleteKey(in byte[] inKeyBlob);
+ void deleteKey(in byte[] keyBlob);
/**
* Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
@@ -705,8 +721,44 @@
* from operations that generate an IV or nonce, and IKeyMintOperation object pointer
* which is used to perform update(), finish() or abort() operations.
*/
- BeginResult begin(in KeyPurpose inPurpose,
- in byte[] inKeyBlob,
- in KeyParameter[] inParams,
- in HardwareAuthToken inAuthToken);
+ BeginResult begin(in KeyPurpose purpose, in byte[] keyBlob, in KeyParameter[] params,
+ in HardwareAuthToken authToken);
+
+ /**
+ * Called by client to notify the IKeyMintDevice that the device is now locked, and keys with
+ * the UNLOCKED_DEVICE_REQUIRED tag should no longer be usable. When this function is called,
+ * the IKeyMintDevice should note the current timestamp, and attempts to use
+ * UNLOCKED_DEVICE_REQUIRED keys must be rejected with Error::DEVICE_LOCKED until an
+ * authentication token with a later timestamp is presented. If the `passwordOnly' argument is
+ * set to true the sufficiently-recent authentication token must indicate that the user
+ * authenticated with a password, not a biometric.
+ *
+ * Note that the IKeyMintDevice UNLOCKED_DEVICE_REQUIRED semantics are slightly different from
+ * the UNLOCKED_DEVICE_REQUIRED semantics enforced by keystore. Keystore handles device locking
+ * on a per-user basis. Because auth tokens do not contain an Android user ID, it's not
+ * possible to replicate the keystore enformcement logic in IKeyMintDevice. So from the
+ * IKeyMintDevice perspective, any user unlock unlocks all UNLOCKED_DEVICE_REQUIRED keys.
+ * Keystore will continue enforcing the per-user device locking.
+ *
+ * @param passwordOnly specifies whether the device must be unlocked with a password, rather
+ * than a biometric, before UNLOCKED_DEVICE_REQUIRED keys can be used.
+ *
+ * @param timestampToken is used by StrongBox implementations of IKeyMintDevice. It
+ * provides the StrongBox IKeyMintDevice with a fresh, MACed timestamp which it can use as the
+ * device-lock time, for future comparison against auth tokens when operations using
+ * UNLOCKED_DEVICE_REQUIRED keys are attempted. Unless the auth token timestamp is newer than
+ * the timestamp in the timestampToken, the device is still considered to be locked.
+ * Crucially, if a StrongBox IKeyMintDevice receives a deviceLocked() call with a timestampToken
+ * timestamp that is less than the timestamp in the last deviceLocked() call, it must ignore the
+ * new timestamp. TEE IKeyMintDevice implementations will receive an empty timestampToken (zero
+ * values and empty vectors) and should use their own clock as the device-lock time.
+ */
+ void deviceLocked(in boolean passwordOnly, in @nullable TimeStampToken timestampToken);
+
+ /**
+ * Called by client to notify the IKeyMintDevice that the device has left the early boot
+ * state, and that keys with the EARLY_BOOT_ONLY tag may no longer be used. All attempts to use
+ * an EARLY_BOOT_ONLY key after this method is called must fail with Error::INVALID_KEY_BLOB.
+ */
+ void earlyBootEnded();
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..1b09e9d
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.MacedPublicKey;
+import android.hardware.security.keymint.ProtectedData;
+
+/**
+ * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
+ * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
+ * creating a CertificateRequest that contains the generated public keys, plus other information to
+ * authenticate the request origin. The CertificateRequest can be sent to a server, which can
+ * validate the request and create certificates.
+ *
+ * This interface does not provide any way to use the generated and certified key pairs. It's
+ * intended to be implemented by a HAL service that does other things with keys (e.g. Keymint).
+ *
+ * The root of trust for secure provisioning is something called the "Boot Certificate Chain", or
+ * BCC. The BCC is a chain of public key certificates, represented as COSE_Sign1 objects containing
+ * COSE_Key representations of the public keys. The "root" of the BCC is a self-signed certificate
+ * for a device-unique public key, denoted DK_pub. All public keys in the BCC are device-unique. The
+ * public key from each certificate in the chain is used to sign the next certificate in the
+ * chain. The final, "leaf" certificate contains a public key, denoted KM_pub, whose corresponding
+ * private key, denoted KM_priv, is available for use by the IRemotelyProvisionedComponent.
+ *
+ * BCC Design
+ * ==========
+ *
+ * The BCC is designed to mirror the boot stages of a device, and to prove the content and integrity
+ * of each firmware image. In a proper BCC, each boot stage hashes its own private key with the code
+ * and any relevant configuration parameters of the next stage to produce a key pair for the next
+ * stage. Each stage also uses its own private key to sign the public key of the next stage,
+ * including in the certificate the hash of the next firmware stage, then loads the next stage,
+ * passing the private key and certificate to it in a manner that does not leak the private key to
+ * later boot stages. The BCC root key pair is generated by immutable code (e.g. ROM), from a
+ * device-unique secret. After the device-unique secret is used, it must be made unavailable to any
+ * later boot stage.
+ *
+ * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
+ * validates the integrity of every stage and (b) contains a set of public keys that correspond to
+ * private keys, one known to each stage. Any stage can compute the secrets of all later stages
+ * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
+ * the firmware or configuration of any stage changes the key pair of that stage, and of all
+ * subsequent stages, and no attacker who compromised the previous version of the updated firmware
+ * can know or predict the post-update key pairs.
+ *
+ * The first BCC certificate is special because its contained public key, DK_pub, will never change,
+ * making it a permanent, device-unique identifier. Although the remaining keys in the BCC are also
+ * device-unique, they are not necessarily permanent, since they can change when the device software
+ * is updated.
+ *
+ * When the provisioning server receives a message signed by KM_priv and containing a BCC that
+ * chains from DK_pub to KM_pub, it can be certain that (barring vulnerabilities in some boot
+ * stage), the CertificateRequest came from the device associated with DK_pub, running the specific
+ * software identified by the certificates in the BCC. If the server has some mechanism for knowing
+ * which the DK_pub values of "valid" devices, it can determine whether signing certificates is
+ * appropriate.
+ *
+ * Degenerate BCCs
+ * ===============
+ *
+ * While a proper BCC, as described above, reflects the complete boot sequence from boot ROM to the
+ * secure area image of the IRemotelyProvisionedComponent, it's also possible to use a "degenerate"
+ * BCC which consists only of a single, self-signed certificate containing the public key of a
+ * hardware-bound key pair. This is an appopriate solution for devices which haven't implemented
+ * everything necessary to produce a proper BCC, but can derive a unique key pair in the secure
+ * area. In this degenerate case, DK_pub is the same as KM_pub.
+ *
+ * BCC Privacy
+ * ===========
+ *
+ * Because the BCC constitutes an unspoofable, device-unique identifier, special care is taken to
+ * prevent its availability to entities who may wish to track devices. Two precautions are taken:
+ *
+ * 1. The BCC is never exported from the IRemotelyProvisionedComponent except in encrypted
+ * form. The portion of the CertificateRequest that contains the BCC is encrypted using an
+ * Endpoint Encryption Key (EEK). The EEK is provided in the form of a certificate chain whose
+ * root must be pre-provisioned into the secure area (hardcoding the roots into the secure area
+ * firmware image is a recommended approach). Multiple roots may be provisioned. If the provided
+ * EEK does not chain back to this already-known root, the IRemotelyProvisionedComponent must
+ * reject it.
+ *
+ * 2. Precaution 1 above ensures that only an entity with a valid EEK private key can decrypt the
+ * BCC. To make it feasible to build a provisioning server which cannot use the BCC to track
+ * devices, the CertificateRequest is structured so that the server can be partitioned into two
+ * components. The "decrypter" decrypts the BCC, verifies DK_pub and the device's right to
+ * receive provisioned certificates, but does not see the public keys to be signed or the
+ * resulting certificates. The "certifier" gets informed of the results of the decrypter's
+ * validation and sees the public keys to be signed and resulting certificates, but does not see
+ * the BCC.
+ *
+ * Test Mode
+ * =========
+ *
+ * The IRemotelyProvisionedComponent supports a test mode, allowing the generation of test key pairs
+ * and test CertificateRequests. Test keys/requests are annotated as such, and the BCC used for test
+ * CertificateRequests must contain freshly-generated keys, not the real BCC key pairs.
+ */
+@VintfStability
+interface IRemotelyProvisionedComponent {
+ const int STATUS_FAILED = 1;
+ const int STATUS_INVALID_MAC = 2;
+ const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+ const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+ const int STATUS_INVALID_EEK = 5;
+
+ /**
+ * generateKeyPair generates a new ECDSA P-256 key pair that can be certified. Note that this
+ * method only generates ECDSA P-256 key pairs, but the interface can be extended to add methods
+ * for generating keys for other algorithms, if necessary.
+ *
+ * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
+ * are marked (see the definition of PublicKey in the MacedPublicKey structure) to
+ * prevent them from being confused with production keys.
+ *
+ * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
+ * MACed so that generateCertificateRequest can easily verify, without the
+ * privateKeyHandle, that the contained public key is for remote certification.
+ *
+ * @return data representing a handle to the private key. The format is implementation-defined,
+ * but note that specific services may define a required format.
+ */
+ byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
+
+ /**
+ * generateCertificateRequest creates a certificate request to be sent to the provisioning
+ * server.
+ *
+ * @param in boolean testMode indicates whether the generated certificate request is for testing
+ * only.
+ *
+ * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
+ * IRemotelyProvisionedComponent must validate the MACs on each key. If any entry in the
+ * array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
+ *
+ * If testMode is true, the keysToCertify array must contain only keys flagged as test
+ * keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+ *
+ * If testMode is false, the keysToCertify array must not contain any keys flagged as
+ * test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ *
+ * @param in endpointEncryptionKey contains an X25519 public key which will be used to encrypt
+ * the BCC. For flexibility, this is represented as a certificate chain, represented as a
+ * CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
+ * X25519 encryption key, each other element is an Ed25519 key signing the next in the
+ * chain. The root is self-signed.
+ *
+ * EekChain = [ + SignedSignatureKey, SignedEek ]
+ *
+ * SignedSignatureKey = [ // COSE_Sign1
+ * protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * unprotected: bstr .size 0
+ * payload: bstr .cbor SignatureKey,
+ * signature: bstr PureEd25519(.cbor SignatureKeySignatureInput)
+ * ]
+ *
+ * SignatureKey = { // COSE_Key
+ * 1 : 1, // Key type : Octet Key Pair
+ * 3 : -8, // Algorithm : EdDSA
+ * -1 : 6, // Curve : Ed25519
+ * -2 : bstr // Ed25519 public key
+ * }
+ *
+ * SignatureKeySignatureInput = [
+ * context: "Signature1",
+ * body_protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor SignatureKey
+ * ]
+ *
+ * SignedEek = [ // COSE_Sign1
+ * protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * unprotected: bstr .size 0
+ * payload: bstr .cbor Eek,
+ * signature: bstr PureEd25519(.cbor EekSignatureInput)
+ * ]
+ *
+ * Eek = { // COSE_Key
+ * 1 : 1, // Key type : Octet Key Pair
+ * 2 : bstr // KID : EEK ID
+ * 3 : -25, // Algorithm : ECDH-ES + HKDF-256
+ * -1 : 4, // Curve : X25519
+ * -2 : bstr // Ed25519 public key
+ * }
+ *
+ * EekSignatureInput = [
+ * context: "Signature1",
+ * body_protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor Eek
+ * ]
+ *
+ * If the contents of endpointEncryptionKey do not match the SignedEek structure above,
+ * the method must return STATUS_INVALID_EEK.
+ *
+ * If testMode is true, the method must ignore the length and content of the signatures
+ * in the chain, which implies that it must not attempt to validate the signature.
+ *
+ * If testMode is false, the method must validate the chain signatures, and must verify
+ * that the public key in the root certifictate is in its pre-configured set of
+ * authorized EEK root keys. If the public key is not in the database, or if signature
+ * verification fails, the method must return STATUS_INVALID_EEK.
+ *
+ * @param in challenge contains a byte string from the provisioning server that must be signed
+ * by the secure area. See the description of the 'signature' output parameter for
+ * details.
+ *
+ * @param out keysToSignMac contains the MAC of KeysToSign in the CertificateRequest
+ * structure. Specifically, it contains:
+ *
+ * HMAC-256(EK_mac, .cbor KeysToMacStructure)
+ *
+ * Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below). The MACed
+ * data is the "tag" field of a COSE_Mac0 structure like:
+ *
+ * MacedKeys = [ // COSE_Mac0
+ * protected : bstr .cbor {
+ * 1 : 5, // Algorithm : HMAC-256
+ * },
+ * unprotected : bstr .size 0,
+ * // Payload is PublicKeys from keysToSign argument, in provided order.
+ * payload: bstr .cbor [ * PublicKey ],
+ * tag: bstr
+ * ]
+ *
+ * KeysToMacStructure = [
+ * context : "MAC0",
+ * protected : bstr .cbor { 1 : 5 }, // Algorithm : HMAC-256
+ * external_aad : bstr .size 0,
+ * // Payload is PublicKeys from keysToSign argument, in provided order.
+ * payload : bstr .cbor [ * PublicKey ]
+ * ]
+ *
+ * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument).
+ */
+ void generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
+ in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac,
+ out ProtectedData protectedData);
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
index 1a107ba..2fcaf4c 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -45,4 +45,11 @@
* same author.
*/
@utf8InCpp String keyMintAuthorName;
+
+ /* The timestampTokenRequired is a boolean flag, which when true reflects that IKeyMintDevice
+ * instance will expect a valid TimeStampToken with various operations. This will typically
+ * required by the StrongBox implementations that generally don't have secure clock hardware to
+ * generate timestamp tokens.
+ */
+ boolean timestampTokenRequired;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index 68c1740..978a027 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -16,12 +16,11 @@
package android.hardware.security.keymint;
-
/**
* Possible purposes of a key (or pair).
*/
@VintfStability
-@Backing(type = "int")
+@Backing(type="int")
enum KeyPurpose {
/* Usable with RSA, EC and AES keys. */
ENCRYPT = 0,
@@ -42,5 +41,7 @@
/* Key Agreement, usable with EC keys. */
AGREE_KEY = 6,
- /* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/
+ /* Usable as an attestation signing key. Keys with this purpose must not have any other
+ * purpose. */
+ ATTEST_KEY = 7,
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
new file mode 100644
index 0000000..da85a50
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * MacedPublicKey contains a CBOR-encoded public key, MACed by an IRemotelyProvisionedComponent, to
+ * prove that the key pair was generated by that component.
+ */
+@VintfStability
+parcelable MacedPublicKey {
+ /**
+ * key is a COSE_Mac0 structure containing the new public key. It's MACed by a key available
+ * only to the secure environment, as proof that the public key was generated by that
+ * environment. In CDDL, assuming the contained key is an Ed25519 public key:
+ *
+ * MacedPublicKey = [ // COSE_Mac0
+ * protected: bstr .cbor { 1 : 5}, // Algorithm : HMAC-256
+ * unprotected: bstr .size 0,
+ * payload : bstr .cbor PublicKey,
+ * tag : bstr HMAC-256(K_mac, MAC_structure)
+ * ]
+ *
+ * PublicKey = { // COSE_Key
+ * 1 : 1, // Key type : octet key pair
+ * 3 : -8 // Algorithm : EdDSA
+ * -1 : 6, // Curve : Ed25519
+ * -2 : bstr // X coordinate, little-endian
+ * ? -70000 : nil // Presence indicates this is a test key. If set, K_mac is
+ * // all zeros.
+ * },
+ *
+ * MAC_structure = [
+ * context : "MAC0",
+ * protected : bstr .cbor { 1 : 5 },
+ * external_aad : bstr .size 0,
+ * payload : bstr .cbor PublicKey
+ * ]
+ *
+ * if a non-Ed25519 public key were contained, the contents of the PublicKey map would change a
+ * little; see RFC 8152 for details.
+ */
+ byte[] macedKey;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
new file mode 100644
index 0000000..1ec3bf0
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 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.security.keymint;
+
+/**
+ * ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument).
+ */
+@VintfStability
+parcelable ProtectedData {
+ /**
+ * ProtectedData is a COSE_Encrypt structure, specified by the following CDDL
+ *
+ * ProtectedData = [ // COSE_Encrypt
+ * protected: bstr .cbor {
+ * 1 : 3 // Algorithm : AES-GCM 256
+ * },
+ * unprotected: {
+ * 5 : bstr .size 12 // IV
+ * },
+ * ciphertext: bstr, // AES-GCM-128(K, .cbor ProtectedDataPayload)
+ * recipients : [
+ * [ // COSE_Recipient
+ * protected : bstr .cbor {
+ * 1 : -25 // Algorithm : ECDH-ES + HKDF-256
+ * },
+ * unprotected : {
+ * -1 : { // COSE_Key
+ * 1 : 1, // Key type : Octet Key Pair
+ * -1 : 4, // Curve : X25519
+ * -2 : bstr // Sender X25519 public key
+ * }
+ * 4 : bstr, // KID : EEK ID
+ * },
+ * ciphertext : nil
+ * ]
+ * ]
+ * ]
+ *
+ * K = HKDF-256(ECDH(EEK_pub, Ephemeral_priv), Context)
+ *
+ * Context = [ // COSE_KDF_Context
+ * AlgorithmID : 3 // AES-GCM 256
+ * PartyUInfo : [
+ * identity : bstr "client"
+ * nonce : bstr .size 0,
+ * other : bstr // Ephemeral pubkey
+ * ],
+ * PartyVInfo : [
+ * identity : bstr "server",
+ * nonce : bstr .size 0,
+ * other : bstr // EEK pubkey
+ * ],
+ * SuppPubInfo : [
+ * 128, // Output key length
+ * protected : bstr .size 0
+ * ]
+ * ]
+ *
+ * ProtectedDataPayload [
+ * SignedMac,
+ * Bcc,
+ * ]
+ *
+ * SignedMac = [ // COSE_Sign1
+ * bstr .cbor { // Protected params
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * bstr .size 0, // Unprotected params
+ * bstr .size 32, // MAC key
+ * bstr PureEd25519(DK_priv, .cbor SignedMac_structure)
+ * ]
+ *
+ * SignedMac_structure = [
+ * "Signature1",
+ * bstr .cbor { // Protected params
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * bstr .cbor SignedMacAad
+ * bstr .size 32 // MAC key
+ * ]
+ *
+ * SignedMacAad = [
+ * challenge : bstr,
+ * DeviceInfo
+ * ]
+ *
+ * Bcc = [
+ * PubKey, // DK_pub
+ * + BccEntry, // Root -> leaf (KM_pub)
+ * ]
+ *
+ * BccPayload = { // CWT
+ * 1 : tstr, // Issuer
+ * 2 : tstr, // Subject
+ * // See the Open Profile for DICE for details on these fields.
+ * ? -4670545 : bstr, // Code Hash
+ * ? -4670546 : bstr, // Code Descriptor
+ * ? -4670547 : bstr, // Configuration Hash
+ * ? -4670548 : bstr .cbor { // Configuration Descriptor
+ * ? -70002 : tstr, // Component name
+ * ? -70003 : int, // Firmware version
+ * ? -70004 : null, // Resettable
+ * },
+ * ? -4670549 : bstr, // Authority Hash
+ * ? -4670550 : bstr, // Authority Descriptor
+ * ? -4670551 : bstr, // Mode
+ * -4670552 : bstr .cbor PubKey // Subject Public Key
+ * -4670553 : bstr // Key Usage
+ * }
+ *
+ * BccEntry = [ // COSE_Sign1
+ * protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * unprotected: bstr .size 0,
+ * payload: bstr .cbor BccPayload,
+ * // First entry in the chain is signed by DK_pub, the others are each signed by their
+ * // immediate predecessor. See RFC 8032 for signature representation.
+ * signature: bstr .cbor PureEd25519(SigningKey, bstr .cbor BccEntryInput)
+ * ]
+ *
+ * PubKey = { // COSE_Key
+ * 1 : 1, // Key type : octet key pair
+ * 3 : -8, // Algorithm : EdDSA
+ * 4 : 2, // Ops: Verify
+ * -1 : 6, // Curve : Ed25519
+ * -2 : bstr // X coordinate, little-endian
+ * }
+ *
+ * BccEntryInput = [
+ * context: "Signature1",
+ * protected: bstr .cbor {
+ * 1 : -8, // Algorithm : EdDSA
+ * },
+ * external_aad: bstr .size 0,
+ * payload: bstr .cbor BccPayload
+ * ]
+ *
+ * DeviceInfo = {
+ * ? "brand" : tstr,
+ * ? "manufacturer" : tstr,
+ * ? "product" : tstr,
+ * ? "model" : tstr,
+ * ? "board" : tstr,
+ * ? "vb_state" : "green" / "yellow" / "orange",
+ * ? "bootloader_state" : "locked" / "unlocked",
+ * ? "os_version" : tstr,
+ * ? "system_patch_level" : uint, // YYYYMMDD
+ * ? "boot_patch_level" : uint, // YYYYMMDD
+ * ? "vendor_patch_level" : uint, // YYYYMMDD
+ * }
+ */
+ byte[] protectedData;
+}
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index b2758ad..e9f3be0 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -2,7 +2,11 @@
name: "android.hardware.security.keymint-service",
relative_install_path: "hw",
init_rc: ["android.hardware.security.keymint-service.rc"],
- vintf_fragments: ["android.hardware.security.keymint-service.xml"],
+ vintf_fragments: [
+ "android.hardware.security.keymint-service.xml",
+ "android.hardware.security.sharedsecret-service.xml",
+ "android.hardware.security.secureclock-service.xml",
+ ],
vendor: true,
cflags: [
"-Wall",
@@ -10,17 +14,45 @@
],
shared_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.sharedsecret-unstable-ndk_platform",
+ "android.hardware.security.secureclock-unstable-ndk_platform",
"libbase",
"libbinder_ndk",
- "libcppbor",
+ "libcppbor_external",
"libcrypto",
"libkeymaster_portable",
"libkeymint",
"liblog",
"libpuresoftkeymasterdevice",
+ "libremote_provisioner",
"libutils",
],
srcs: [
"service.cpp",
],
}
+
+cc_library {
+ name: "libremote_provisioner",
+ vendor_available: true,
+ static_libs: [
+ "libkeymint_remote_prov_support",
+ ],
+ shared_libs: [
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ "libbinder_ndk",
+ "libcppbor_external",
+ "libcppcose",
+ "libcrypto",
+ "libkeymaster_portable",
+ "libkeymint",
+ "liblog",
+ "libpuresoftkeymasterdevice",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ srcs: [
+ "RemotelyProvisionedComponent.cpp",
+ ],
+}
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
new file mode 100644
index 0000000..f2651fb
--- /dev/null
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2021 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 "RemotelyProvisionedComponent.h"
+
+#include <assert.h>
+#include <variant>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <KeyMintUtils.h>
+#include <cppcose/cppcose.h>
+#include <keymaster/keymaster_configuration.h>
+#include <remote_prov/remote_prov_utils.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::std::string;
+using ::std::tuple;
+using ::std::unique_ptr;
+using ::std::variant;
+using ::std::vector;
+using bytevec = ::std::vector<uint8_t>;
+
+using namespace cppcose;
+using namespace keymaster;
+
+namespace {
+
+constexpr auto STATUS_FAILED = RemotelyProvisionedComponent::STATUS_FAILED;
+constexpr auto STATUS_INVALID_EEK = RemotelyProvisionedComponent::STATUS_INVALID_EEK;
+constexpr auto STATUS_INVALID_MAC = RemotelyProvisionedComponent::STATUS_INVALID_MAC;
+constexpr uint32_t kAffinePointLength = 32;
+struct AStatusDeleter {
+ void operator()(AStatus* p) { AStatus_delete(p); }
+};
+
+// TODO(swillden): Remove the dependency on AStatus stuff. The COSE lib should use something like
+// StatusOr, but it shouldn't depend on AStatus.
+class Status {
+ public:
+ Status() {}
+ Status(int32_t errCode, const std::string& errMsg)
+ : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
+ explicit Status(const std::string& errMsg)
+ : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
+ Status(AStatus* status) : status_(status) {}
+ Status(Status&&) = default;
+ Status(const Status&) = delete;
+
+ operator ::ndk::ScopedAStatus() && { return ndk::ScopedAStatus(status_.release()); }
+
+ bool isOk() { return !status_; }
+
+ // Don't call getMessage() unless isOk() returns false;
+ const char* getMessage() const { return AStatus_getMessage(status_.get()); }
+
+ private:
+ std::unique_ptr<AStatus, AStatusDeleter> status_;
+};
+
+template <typename T>
+class StatusOr {
+ public:
+ StatusOr(AStatus* status) : status_(status) {}
+ StatusOr(Status status) : status_(std::move(status)) {}
+ StatusOr(T val) : value_(std::move(val)) {}
+
+ bool isOk() { return status_.isOk(); }
+
+ T* operator->() & {
+ assert(isOk());
+ return &value_.value();
+ }
+ T& operator*() & {
+ assert(isOk());
+ return value_.value();
+ }
+ T&& operator*() && {
+ assert(isOk());
+ return std::move(value_).value();
+ }
+
+ const char* getMessage() const {
+ assert(!isOk());
+ return status_.getMessage();
+ }
+
+ Status moveError() {
+ assert(!isOk());
+ return std::move(status_);
+ }
+
+ T moveValue() { return std::move(value_).value(); }
+
+ private:
+ Status status_;
+ std::optional<T> value_;
+};
+
+StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtractEekPubAndId(
+ bool testMode, const bytevec& endpointEncryptionCertChain) {
+ auto [item, newPos, errMsg] = cppbor::parse(endpointEncryptionCertChain);
+
+ if (!item || !item->asArray()) {
+ return Status("Error parsing EEK chain" + errMsg);
+ }
+
+ const cppbor::Array* certArr = item->asArray();
+ bytevec lastPubKey;
+ for (int i = 0; i < certArr->size(); ++i) {
+ auto cosePubKey = verifyAndParseCoseSign1(testMode, certArr->get(i)->asArray(),
+ std::move(lastPubKey), bytevec{} /* AAD */);
+ if (!cosePubKey) {
+ return Status(STATUS_INVALID_EEK,
+ "Failed to validate EEK chain: " + cosePubKey.moveMessage());
+ }
+ lastPubKey = *std::move(cosePubKey);
+ }
+
+ auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
+ if (!eek) return Status(STATUS_INVALID_EEK, "Failed to get EEK: " + eek.moveMessage());
+
+ return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
+ eek->getBstrValue(CoseKey::KEY_ID).value());
+}
+
+StatusOr<bytevec /* pubkeys */> validateAndExtractPubkeys(bool testMode,
+ const vector<MacedPublicKey>& keysToSign,
+ const bytevec& macKey) {
+ auto pubKeysToMac = cppbor::Array();
+ for (auto& keyToSign : keysToSign) {
+ auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(keyToSign.macedKey);
+ if (!macedKeyItem || !macedKeyItem->asArray() ||
+ macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
+ return Status("Invalid COSE_Mac0 structure");
+ }
+
+ auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+ auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+ auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
+ auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
+ if (!protectedParms || !unprotectedParms || !payload || !tag) {
+ return Status("Invalid COSE_Mac0 contents");
+ }
+
+ auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
+ if (!protectedMap || !protectedMap->asMap()) {
+ return Status("Invalid Mac0 protected: " + errMsg);
+ }
+ auto& algo = protectedMap->asMap()->get(ALGORITHM);
+ if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+ return Status("Unsupported Mac0 algorithm");
+ }
+
+ auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
+ if (!pubKey) return Status(pubKey.moveMessage());
+
+ bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
+ if (testMode && !testKey) {
+ return Status(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST,
+ "Production key in test request");
+ } else if (!testMode && testKey) {
+ return Status(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST,
+ "Test key in production request");
+ }
+
+ auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
+ if (!macTag) return Status(STATUS_INVALID_MAC, macTag.moveMessage());
+ if (macTag->size() != tag->value().size() ||
+ CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+ return Status(STATUS_INVALID_MAC, "MAC tag mismatch");
+ }
+
+ pubKeysToMac.add(pubKey->moveMap());
+ }
+
+ return pubKeysToMac.encode();
+}
+
+StatusOr<std::pair<bytevec, bytevec>> buildCosePublicKeyFromKmCert(
+ const keymaster_blob_t* km_cert) {
+ if (km_cert == nullptr) {
+ return Status(STATUS_FAILED, "km_cert is a nullptr");
+ }
+ const uint8_t* temp = km_cert->data;
+ X509* cert = d2i_X509(NULL, &temp, km_cert->data_length);
+ if (cert == nullptr) {
+ return Status(STATUS_FAILED, "d2i_X509 returned null when attempting to get the cert.");
+ }
+ EVP_PKEY* pubKey = X509_get_pubkey(cert);
+ if (pubKey == nullptr) {
+ return Status(STATUS_FAILED, "Boringssl failed to get the public key from the cert");
+ }
+ EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey);
+ if (ecKey == nullptr) {
+ return Status(STATUS_FAILED,
+ "The key in the certificate returned from GenerateKey is not "
+ "an EC key.");
+ }
+ const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey);
+ BIGNUM x;
+ BIGNUM y;
+ BN_CTX* ctx = BN_CTX_new();
+ if (ctx == nullptr) {
+ return Status(STATUS_FAILED, "Memory allocation failure for BN_CTX");
+ }
+ if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, &x, &y,
+ ctx)) {
+ return Status(STATUS_FAILED, "Failed to get affine coordinates");
+ }
+ bytevec x_bytestring(kAffinePointLength);
+ bytevec y_bytestring(kAffinePointLength);
+ if (BN_bn2binpad(&x, x_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
+ return Status(STATUS_FAILED, "Wrote incorrect number of bytes for x coordinate");
+ }
+ if (BN_bn2binpad(&y, y_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
+ return Status(STATUS_FAILED, "Wrote incorrect number of bytes for y coordinate");
+ }
+ BN_CTX_free(ctx);
+ return std::make_pair(x_bytestring, y_bytestring);
+}
+
+cppbor::Array buildCertReqRecipients(const bytevec& pubkey, const bytevec& kid) {
+ return cppbor::Array() // Array of recipients
+ .add(cppbor::Array() // Recipient
+ .add(cppbor::Map() // Protected
+ .add(ALGORITHM, ECDH_ES_HKDF_256)
+ .canonicalize()
+ .encode())
+ .add(cppbor::Map() // Unprotected
+ .add(COSE_KEY, cppbor::Map()
+ .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+ .add(CoseKey::CURVE, cppcose::X25519)
+ .add(CoseKey::PUBKEY_X, pubkey)
+ .canonicalize())
+ .add(KEY_ID, kid)
+ .canonicalize())
+ .add(cppbor::Null())); // No ciphertext
+}
+
+static keymaster_key_param_t kKeyMintEcdsaP256Params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC),
+ Authorization(TAG_KEY_SIZE, 256), Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256),
+ Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256), Authorization(TAG_NO_AUTH_REQUIRED),
+ // The certificate generated by KM will be discarded, these values don't matter.
+ Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)};
+
+} // namespace
+
+RemotelyProvisionedComponent::RemotelyProvisionedComponent(
+ std::shared_ptr<keymint::AndroidKeyMintDevice> keymint) {
+ std::tie(devicePrivKey_, bcc_) = generateBcc();
+ impl_ = keymint->getKeymasterImpl();
+}
+
+RemotelyProvisionedComponent::~RemotelyProvisionedComponent() {}
+
+ScopedAStatus RemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool testMode,
+ MacedPublicKey* macedPublicKey,
+ bytevec* privateKeyHandle) {
+ // TODO(jbires): The following should move from ->GenerateKey to ->GenerateRKPKey and everything
+ // after the GenerateKey call should basically be moved into that new function call
+ // as well once the issue with libcppbor in system/keymaster is sorted out
+ GenerateKeyRequest request(impl_->message_version());
+ request.key_description.Reinitialize(kKeyMintEcdsaP256Params,
+ array_length(kKeyMintEcdsaP256Params));
+ GenerateKeyResponse response(impl_->message_version());
+ impl_->GenerateKey(request, &response);
+ if (response.error != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(response.error);
+ }
+
+ if (response.certificate_chain.entry_count != 1) {
+ // Error: Need the single non-signed certificate with the public key in it.
+ return Status(STATUS_FAILED,
+ "Expected to receive a single certificate from GenerateKey. Instead got: " +
+ std::to_string(response.certificate_chain.entry_count));
+ }
+ auto affineCoords = buildCosePublicKeyFromKmCert(response.certificate_chain.begin());
+ if (!affineCoords.isOk()) return affineCoords.moveError();
+ cppbor::Map cosePublicKeyMap = cppbor::Map()
+ .add(CoseKey::KEY_TYPE, EC2)
+ .add(CoseKey::ALGORITHM, ES256)
+ .add(CoseKey::CURVE, cppcose::P256)
+ .add(CoseKey::PUBKEY_X, affineCoords->first)
+ .add(CoseKey::PUBKEY_Y, affineCoords->second);
+ if (testMode) {
+ cosePublicKeyMap.add(CoseKey::TEST_KEY, cppbor::Null());
+ }
+
+ bytevec cosePublicKey = cosePublicKeyMap.canonicalize().encode();
+
+ auto macedKey = constructCoseMac0(testMode ? remote_prov::kTestMacKey : macKey_,
+ {} /* externalAad */, cosePublicKey);
+ if (!macedKey) return Status(macedKey.moveMessage());
+
+ macedPublicKey->macedKey = macedKey->encode();
+ *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest(
+ bool testMode, const vector<MacedPublicKey>& keysToSign,
+ const bytevec& endpointEncCertChain, const bytevec& challenge, bytevec* keysToSignMac,
+ ProtectedData* protectedData) {
+ auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign,
+ testMode ? remote_prov::kTestMacKey : macKey_);
+ if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError();
+
+ bytevec ephemeralMacKey = remote_prov::randomBytes(SHA256_DIGEST_LENGTH);
+
+ auto pubKeysToSignMac = generateCoseMac0Mac(ephemeralMacKey, bytevec{}, *pubKeysToSign);
+ if (!pubKeysToSignMac) return Status(pubKeysToSignMac.moveMessage());
+ *keysToSignMac = *std::move(pubKeysToSignMac);
+
+ bytevec devicePrivKey;
+ cppbor::Array bcc;
+ if (testMode) {
+ std::tie(devicePrivKey, bcc) = generateBcc();
+ } else {
+ devicePrivKey = devicePrivKey_;
+ bcc = bcc_.clone();
+ }
+
+ auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */, //
+ ephemeralMacKey /* Payload */,
+ cppbor::Array() /* AAD */
+ .add(challenge)
+ .add(createDeviceInfo())
+ .encode());
+ if (!signedMac) return Status(signedMac.moveMessage());
+
+ bytevec ephemeralPrivKey(X25519_PRIVATE_KEY_LEN);
+ bytevec ephemeralPubKey(X25519_PUBLIC_VALUE_LEN);
+ X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data());
+
+ auto eek = validateAndExtractEekPubAndId(testMode, endpointEncCertChain);
+ if (!eek.isOk()) return eek.moveError();
+
+ auto sessionKey = x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first,
+ true /* senderIsA */);
+ if (!sessionKey) return Status(sessionKey.moveMessage());
+
+ auto coseEncrypted =
+ constructCoseEncrypt(*sessionKey, remote_prov::randomBytes(kAesGcmNonceLength),
+ cppbor::Array() // payload
+ .add(signedMac.moveValue())
+ .add(std::move(bcc))
+ .encode(),
+ {}, // aad
+ buildCertReqRecipients(ephemeralPubKey, eek->second));
+
+ if (!coseEncrypted) return Status(coseEncrypted.moveMessage());
+ protectedData->protectedData = coseEncrypted->encode();
+
+ return ScopedAStatus::ok();
+}
+
+bytevec RemotelyProvisionedComponent::deriveBytesFromHbk(const string& context,
+ size_t numBytes) const {
+ bytevec fakeHbk(32, 0);
+ bytevec result(numBytes);
+
+ // TODO(swillden): Figure out if HKDF can fail. It doesn't seem like it should be able to,
+ // but the function does return an error code.
+ HKDF(result.data(), numBytes, //
+ EVP_sha256(), //
+ fakeHbk.data(), fakeHbk.size(), //
+ nullptr /* salt */, 0 /* salt len */, //
+ reinterpret_cast<const uint8_t*>(context.data()), context.size());
+
+ return result;
+}
+
+bytevec RemotelyProvisionedComponent::createDeviceInfo() const {
+ return cppbor::Map().encode();
+}
+
+std::pair<bytevec /* privKey */, cppbor::Array /* BCC */>
+RemotelyProvisionedComponent::generateBcc() {
+ bytevec privKey(ED25519_PRIVATE_KEY_LEN);
+ bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
+
+ ED25519_keypair(pubKey.data(), privKey.data());
+
+ auto coseKey = cppbor::Map()
+ .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+ .add(CoseKey::ALGORITHM, EDDSA)
+ .add(CoseKey::CURVE, ED25519)
+ .add(CoseKey::KEY_OPS, VERIFY)
+ .add(CoseKey::PUBKEY_X, pubKey)
+ .canonicalize()
+ .encode();
+ auto sign1Payload = cppbor::Map()
+ .add(1 /* Issuer */, "Issuer")
+ .add(2 /* Subject */, "Subject")
+ .add(-4670552 /* Subject Pub Key */, coseKey)
+ .add(-4670553 /* Key Usage */,
+ std::vector<uint8_t>(0x05) /* Big endian order */)
+ .canonicalize()
+ .encode();
+ auto coseSign1 = constructCoseSign1(privKey, /* signing key */
+ cppbor::Map(), /* extra protected */
+ sign1Payload, {} /* AAD */);
+ assert(coseSign1);
+
+ return {privKey, cppbor::Array().add(coseKey).add(coseSign1.moveValue())};
+}
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
new file mode 100644
index 0000000..e8d2343
--- /dev/null
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AndroidKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <cppbor.h>
+#include <keymaster/UniquePtr.h>
+#include <keymaster/android_keymaster.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::ndk::ScopedAStatus;
+
+class RemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
+ public:
+ explicit RemotelyProvisionedComponent(std::shared_ptr<keymint::AndroidKeyMintDevice> keymint);
+ virtual ~RemotelyProvisionedComponent();
+
+ ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+ std::vector<uint8_t>* privateKeyHandle) override;
+
+ ScopedAStatus generateCertificateRequest(bool testMode,
+ const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& endpointEncCertChain,
+ const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* keysToSignMac,
+ ProtectedData* protectedData) override;
+
+ private:
+ // TODO(swillden): Move these into an appropriate Context class.
+ std::vector<uint8_t> deriveBytesFromHbk(const std::string& context, size_t numBytes) const;
+ std::vector<uint8_t> createDeviceInfo() const;
+ std::pair<std::vector<uint8_t>, cppbor::Array> generateBcc();
+
+ std::vector<uint8_t> macKey_ = deriveBytesFromHbk("Key to MAC public keys", 32);
+ std::vector<uint8_t> devicePrivKey_;
+ cppbor::Array bcc_;
+ std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
+};
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
index 73d15a8..4aa05ef 100644
--- a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -3,4 +3,8 @@
<name>android.hardware.security.keymint</name>
<fqname>IKeyMintDevice/default</fqname>
</hal>
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IRemotelyProvisionedComponent/default</fqname>
+ </hal>
</manifest>
diff --git a/security/keymint/aidl/default/android.hardware.security.secureclock-service.xml b/security/keymint/aidl/default/android.hardware.security.secureclock-service.xml
new file mode 100644
index 0000000..c0ff775
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.security.secureclock-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.secureclock</name>
+ <fqname>ISecureClock/default</fqname>
+ </hal>
+</manifest>
diff --git a/security/keymint/aidl/default/android.hardware.security.sharedsecret-service.xml b/security/keymint/aidl/default/android.hardware.security.sharedsecret-service.xml
new file mode 100644
index 0000000..d37981f
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.security.sharedsecret-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.sharedsecret</name>
+ <fqname>ISharedSecret/default</fqname>
+ </hal>
+</manifest>
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
index a710535..bcebbaf 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -21,25 +21,42 @@
#include <android/binder_process.h>
#include <AndroidKeyMintDevice.h>
+#include <AndroidSecureClock.h>
+#include <AndroidSharedSecret.h>
#include <keymaster/soft_keymaster_logger.h>
+#include "RemotelyProvisionedComponent.h"
+
using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
+using aidl::android::hardware::security::keymint::RemotelyProvisionedComponent;
using aidl::android::hardware::security::keymint::SecurityLevel;
+using aidl::android::hardware::security::secureclock::AndroidSecureClock;
+using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;
+
+template <typename T, class... Args>
+std::shared_ptr<T> addService(Args&&... args) {
+ std::shared_ptr<T> ser = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+ auto instanceName = std::string(T::descriptor) + "/default";
+ LOG(INFO) << "adding keymint service instance: " << instanceName;
+ binder_status_t status =
+ AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
+ CHECK(status == STATUS_OK);
+ return ser;
+}
int main() {
// Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
// the pool size to 1.
ABinderProcess_setThreadPoolMaxThreadCount(0);
+ // Add Keymint Service
std::shared_ptr<AndroidKeyMintDevice> keyMint =
- ndk::SharedRefBase::make<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
-
- keymaster::SoftKeymasterLogger logger;
- const auto instanceName = std::string(AndroidKeyMintDevice::descriptor) + "/default";
- LOG(INFO) << "instance: " << instanceName;
- binder_status_t status =
- AServiceManager_addService(keyMint->asBinder().get(), instanceName.c_str());
- CHECK(status == STATUS_OK);
-
+ addService<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
+ // Add Secure Clock Service
+ addService<AndroidSecureClock>(keyMint);
+ // Add Shared Secret Service
+ addService<AndroidSharedSecret>(keyMint);
+ // Add Remotely Provisioned Component Service
+ addService<RemotelyProvisionedComponent>(keyMint);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index f4ba9e7..7e78c45 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -21,6 +21,7 @@
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
+ "AttestKeyTest.cpp",
"KeyMintTest.cpp",
],
shared_libs: [
@@ -62,6 +63,36 @@
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
- "libcppbor",
+ "libcppbor_external",
+ ],
+}
+
+cc_test {
+ name: "VtsHalRemotelyProvisionedComponentTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsRemotelyProvisionedComponentTests.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcppbor_external",
+ "libcrypto",
+ "libkeymaster_portable",
+ "libpuresoftkeymasterdevice",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ "libcppcose",
+ "libgmock_ndk",
+ "libremote_provisioner",
+ "libkeymint",
+ "libkeymint_remote_prov_support",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
],
}
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
new file mode 100644
index 0000000..7e7a466
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2021 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 "keymint_1_attest_key_test"
+#include <cutils/log.h>
+
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+vector<uint8_t> make_name_from_str(const string& name) {
+ X509_NAME_Ptr x509_name(X509_NAME_new());
+ EXPECT_TRUE(x509_name.get() != nullptr);
+ if (!x509_name) return {};
+
+ EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), //
+ "CN", //
+ MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>(name.c_str()),
+ -1, // len
+ -1, // loc
+ 0 /* set */));
+
+ int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
+ EXPECT_GT(len, 0);
+
+ vector<uint8_t> retval(len);
+ uint8_t* p = retval.data();
+ i2d_X509_NAME(x509_name.get(), &p);
+
+ return retval;
+}
+
+bool IsSelfSigned(const vector<Certificate>& chain) {
+ if (chain.size() != 1) return false;
+ return ChainSignaturesAreValid(chain);
+}
+
+} // namespace
+
+using AttestKeyTest = KeyMintAidlTestBase;
+
+TEST_P(AttestKeyTest, AllRsaSizes) {
+ for (auto size : ValidKeySizes(Algorithm::RSA)) {
+ /*
+ * Create attestaton key.
+ */
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(size, 65537)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
+
+ /*
+ * Use attestation key to sign RSA key
+ */
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ /*
+ * Use attestation key to sign EC key
+ */
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+ CheckedDeleteKey(&attest_key.keyBlob);
+
+ hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Bail early if anything failed.
+ if (HasFailure()) return;
+ }
+}
+
+TEST_P(AttestKeyTest, AllEcCurves) {
+ for (auto curve : ValidCurves()) {
+ /*
+ * Create attestaton key.
+ */
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(curve)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation siging key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on curve " << curve;
+
+ /*
+ * Use attestation key to sign RSA key
+ */
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ /*
+ * Use attestation key to sign EC key
+ */
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+ CheckedDeleteKey(&attest_key.keyBlob);
+
+ hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Bail early if anything failed.
+ if (HasFailure()) return;
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
+
+} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 6555157..d61a081 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,15 +22,23 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <cutils/properties.h>
+#include <openssl/mem.h>
+#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
+#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
using namespace std::literals::chrono_literals;
using std::endl;
using std::optional;
+using std::unique_ptr;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
if (set.size() == 0)
@@ -45,7 +53,7 @@
namespace test {
namespace {
-
+typedef KeyMintAidlTestBase::KeyData KeyData;
// Predicate for testing basic characteristics validity in generation or import.
bool KeyCharacteristicsBasicallyValid(SecurityLevel secLevel,
const vector<KeyCharacteristics>& key_characteristics) {
@@ -73,8 +81,67 @@
return true;
}
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ EXPECT_TRUE(!!oid.get());
+ if (!oid.get()) return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+ if (location == -1) return nullptr;
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+ EXPECT_TRUE(!!attest_rec_ext)
+ << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
+ if (!attest_rec_ext) return nullptr;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+ return attest_rec;
+}
+
+bool avb_verification_enabled() {
+ char value[PROPERTY_VALUE_MAX];
+ return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
+}
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+// Attestations don't contain everything in key authorization lists, so we need to filter the key
+// lists to produce the lists that we expect to match the attestations.
+auto kTagsToFilter = {
+ Tag::BLOB_USAGE_REQUIREMENTS, //
+ Tag::CREATION_DATETIME, //
+ Tag::EC_CURVE,
+ Tag::HARDWARE_TYPE,
+ Tag::INCLUDE_UNIQUE_ID,
+};
+
+AuthorizationSet filtered_tags(const AuthorizationSet& set) {
+ AuthorizationSet filtered;
+ std::remove_copy_if(
+ set.begin(), set.end(), std::back_inserter(filtered), [](const auto& entry) -> bool {
+ return std::find(kTagsToFilter.begin(), kTagsToFilter.end(), entry.tag) !=
+ kTagsToFilter.end();
+ });
+ return filtered;
+}
+
+string x509NameToStr(X509_NAME* name) {
+ char* s = X509_NAME_oneline(name, nullptr, 0);
+ string retval(s);
+ OPENSSL_free(s);
+ return retval;
+}
+
} // namespace
+bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
+bool KeyMintAidlTestBase::dump_Attestations = false;
+
ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
if (result.isOk()) return ErrorCode::OK;
@@ -110,48 +177,48 @@
}
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key,
vector<uint8_t>* key_blob,
- vector<KeyCharacteristics>* key_characteristics) {
+ vector<KeyCharacteristics>* key_characteristics,
+ vector<Certificate>* cert_chain) {
EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
EXPECT_NE(key_characteristics, nullptr)
<< "Previous characteristics not deleted before generating key. Test bug.";
- // Aidl does not clear these output parameters if the function returns
- // error. This is different from hal where output parameter is always
- // cleared due to hal returning void. So now we need to do our own clearing
- // of the output variables prior to calling keyMint aidl libraries.
- key_blob->clear();
- key_characteristics->clear();
- cert_chain_.clear();
-
KeyCreationResult creationResult;
- Status result = keymint_->generateKey(key_desc.vector_data(), &creationResult);
-
+ Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_GT(creationResult.keyBlob.size(), 0);
*key_blob = std::move(creationResult.keyBlob);
*key_characteristics = std::move(creationResult.keyCharacteristics);
- cert_chain_ = std::move(creationResult.certificateChain);
+ *cert_chain = std::move(creationResult.certificateChain);
auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
EXPECT_TRUE(algorithm);
if (algorithm &&
(algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
- EXPECT_GE(cert_chain_.size(), 1);
- if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1);
+ EXPECT_GE(cert_chain->size(), 1);
+ if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
+ if (attest_key) {
+ EXPECT_EQ(cert_chain->size(), 1);
+ } else {
+ EXPECT_GT(cert_chain->size(), 1);
+ }
+ }
} else {
// For symmetric keys there should be no certificates.
- EXPECT_EQ(cert_chain_.size(), 0);
+ EXPECT_EQ(cert_chain->size(), 0);
}
}
return GetReturnErrorCode(result);
}
-ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
- return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key) {
+ return GenerateKey(key_desc, attest_key, &key_blob_, &key_characteristics_, &cert_chain_);
}
ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
@@ -166,7 +233,7 @@
KeyCreationResult creationResult;
result = keymint_->importKey(key_desc.vector_data(), format,
vector<uint8_t>(key_material.begin(), key_material.end()),
- &creationResult);
+ {} /* attestationSigningKeyBlob */, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
@@ -461,6 +528,34 @@
}
}
+auto KeyMintAidlTestBase::ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params)
+ -> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
+ AuthorizationSet begin_out_params;
+ ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params);
+ AuthorizationSet out_params(std::move(begin_out_params));
+ if (result != ErrorCode::OK) {
+ return {result, {}, out_params};
+ }
+
+ string output;
+ int32_t consumed = 0;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ result = Update(update_params, message, &update_out_params, &output, &consumed);
+ out_params.push_back(update_out_params);
+ if (result != ErrorCode::OK) {
+ return {result, output, out_params};
+ }
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ result = Finish(finish_params, message.substr(consumed), unused, &finish_out_params, &output);
+ out_params.push_back(finish_out_params);
+ return {result, output, out_params};
+}
+
string KeyMintAidlTestBase::ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
const string& message, const AuthorizationSet& in_params,
AuthorizationSet* out_params) {
@@ -859,6 +954,269 @@
return authList;
}
+ErrorCode KeyMintAidlTestBase::UseAesKey(const vector<uint8_t>& aesKeyBlob) {
+ auto [result, ciphertext, out_params] = ProcessMessage(
+ aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::UseHmacKey(const vector<uint8_t>& hmacKeyBlob) {
+ auto [result, mac, out_params] = ProcessMessage(
+ hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
+ AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128).Digest(Digest::SHA_2_256));
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::UseRsaKey(const vector<uint8_t>& rsaKeyBlob) {
+ std::string message(2048 / 8, 'a');
+ auto [result, signature, out_params] = ProcessMessage(
+ rsaKeyBlob, KeyPurpose::SIGN, message,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ return result;
+}
+
+ErrorCode KeyMintAidlTestBase::UseEcdsaKey(const vector<uint8_t>& ecdsaKeyBlob) {
+ auto [result, signature, out_params] =
+ ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ return result;
+}
+
+bool verify_attestation_record(const string& challenge, //
+ const string& app_id, //
+ AuthorizationSet expected_sw_enforced, //
+ AuthorizationSet expected_hw_enforced, //
+ SecurityLevel security_level,
+ const vector<uint8_t>& attestation_cert) {
+ X509_Ptr cert(parse_cert_blob(attestation_cert));
+ EXPECT_TRUE(!!cert.get());
+ if (!cert.get()) return false;
+
+ ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+ EXPECT_TRUE(!!attest_rec);
+ if (!attest_rec) return false;
+
+ AuthorizationSet att_sw_enforced;
+ AuthorizationSet att_hw_enforced;
+ uint32_t att_attestation_version;
+ uint32_t att_keymaster_version;
+ SecurityLevel att_attestation_security_level;
+ SecurityLevel att_keymaster_security_level;
+ vector<uint8_t> att_challenge;
+ vector<uint8_t> att_unique_id;
+ vector<uint8_t> att_app_id;
+
+ auto error = 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);
+ EXPECT_EQ(ErrorCode::OK, error);
+ if (error != ErrorCode::OK) return false;
+
+ EXPECT_GE(att_attestation_version, 3U);
+
+ expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
+ vector<uint8_t>(app_id.begin(), app_id.end()));
+
+ EXPECT_GE(att_keymaster_version, 4U);
+ EXPECT_EQ(security_level, att_keymaster_security_level);
+ EXPECT_EQ(security_level, att_attestation_security_level);
+
+ EXPECT_EQ(challenge.length(), att_challenge.size());
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+ char property_value[PROPERTY_VALUE_MAX] = {};
+ // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
+ // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
+ // for the BOOT_PATCH_LEVEL.
+ if (avb_verification_enabled()) {
+ for (int i = 0; i < att_hw_enforced.size(); i++) {
+ if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
+ att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
+ std::string date =
+ std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
+ // strptime seems to require delimiters, but the tag value will
+ // be YYYYMMDD
+ date.insert(6, "-");
+ date.insert(4, "-");
+ EXPECT_EQ(date.size(), 10);
+ struct tm time;
+ strptime(date.c_str(), "%Y-%m-%d", &time);
+
+ // Day of the month (0-31)
+ EXPECT_GE(time.tm_mday, 0);
+ EXPECT_LT(time.tm_mday, 32);
+ // Months since Jan (0-11)
+ EXPECT_GE(time.tm_mon, 0);
+ EXPECT_LT(time.tm_mon, 12);
+ // Years since 1900
+ EXPECT_GT(time.tm_year, 110);
+ EXPECT_LT(time.tm_year, 200);
+ }
+ }
+ }
+
+ // Check to make sure boolean values are properly encoded. Presence of a boolean tag
+ // indicates true. A provided boolean tag that can be pulled back out of the certificate
+ // indicates correct encoding. No need to check if it's in both lists, since the
+ // AuthorizationSet compare below will handle mismatches of tags.
+ if (security_level == SecurityLevel::SOFTWARE) {
+ EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ } else {
+ EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ }
+
+ // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
+ // the authorization list during key generation) isn't being attested to in the certificate.
+ EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+
+ if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
+ // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
+ EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
+ att_hw_enforced.Contains(TAG_KEY_SIZE));
+ }
+
+ // Test root of trust elements
+ vector<uint8_t> verified_boot_key;
+ VerifiedBoot verified_boot_state;
+ bool device_locked;
+ vector<uint8_t> verified_boot_hash;
+ error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
+ &verified_boot_state, &device_locked, &verified_boot_hash);
+ EXPECT_EQ(ErrorCode::OK, error);
+
+ if (avb_verification_enabled()) {
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+ string prop_string(property_value);
+ EXPECT_EQ(prop_string.size(), 64);
+ EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+ if (!strcmp(property_value, "unlocked")) {
+ EXPECT_FALSE(device_locked);
+ } else {
+ EXPECT_TRUE(device_locked);
+ }
+
+ // Check that the device is locked if not debuggable, e.g., user build
+ // images in CTS. For VTS, debuggable images are used to allow adb root
+ // and the device is unlocked.
+ if (!property_get_bool("ro.debuggable", false)) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
+ }
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ std::string empty_boot_key(32, '\0');
+ std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+ verified_boot_key.size());
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+ if (!strcmp(property_value, "green")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "yellow")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "orange")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "red")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ }
+
+ att_sw_enforced.Sort();
+ expected_sw_enforced.Sort();
+ auto a = filtered_tags(expected_sw_enforced);
+ auto b = filtered_tags(att_sw_enforced);
+ EXPECT_EQ(a, b);
+
+ att_hw_enforced.Sort();
+ expected_hw_enforced.Sort();
+ EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
+
+ return true;
+}
+
+string bin2hex(const vector<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
+ std::stringstream cert_data;
+
+ for (size_t i = 0; i < chain.size(); ++i) {
+ cert_data << bin2hex(chain[i].encodedCertificate) << std::endl;
+
+ X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
+ X509_Ptr signing_cert;
+ if (i < chain.size() - 1) {
+ signing_cert = parse_cert_blob(chain[i + 1].encodedCertificate);
+ } else {
+ signing_cert = parse_cert_blob(chain[i].encodedCertificate);
+ }
+ if (!key_cert.get() || !signing_cert.get()) return AssertionFailure() << cert_data.str();
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ if (!signing_pubkey.get()) return AssertionFailure() << cert_data.str();
+
+ if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+ return AssertionFailure()
+ << "Verification of certificate " << i << " failed "
+ << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL) << '\n'
+ << cert_data.str();
+ }
+
+ string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
+ string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
+ if (cert_issuer != signer_subj) {
+ return AssertionFailure() << "Cert " << i << " has wrong issuer.\n" << cert_data.str();
+ }
+
+ if (i == 0) {
+ string cert_sub = x509NameToStr(X509_get_subject_name(key_cert.get()));
+ if ("/CN=Android Keystore Key" != cert_sub) {
+ return AssertionFailure()
+ << "Leaf cert has wrong subject, should be CN=Android Keystore Key, was "
+ << cert_sub << '\n'
+ << cert_data.str();
+ }
+ }
+ }
+
+ if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
+ return AssertionSuccess();
+}
+
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 780971d..452d2b6 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -21,20 +21,27 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
+#include <openssl/x509.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+inline bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
namespace test {
using ::android::sp;
using Status = ::ndk::ScopedAStatus;
+using ::std::optional;
using ::std::shared_ptr;
using ::std::string;
using ::std::vector;
@@ -43,6 +50,14 @@
class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
public:
+ struct KeyData {
+ vector<uint8_t> blob;
+ vector<KeyCharacteristics> characteristics;
+ };
+
+ static bool arm_deleteAllKeys;
+ static bool dump_Attestations;
+
void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
@@ -57,10 +72,18 @@
uint32_t os_patch_level() { return os_patch_level_; }
ErrorCode GetReturnErrorCode(const Status& result);
- ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
- vector<KeyCharacteristics>* key_characteristics);
- ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
+ vector<KeyCharacteristics>* key_characteristics) {
+ return GenerateKey(key_desc, std::nullopt /* attest_key */, key_blob, key_characteristics,
+ &cert_chain_);
+ }
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key, vector<uint8_t>* key_blob,
+ vector<KeyCharacteristics>* key_characteristics,
+ vector<Certificate>* cert_chain);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key = std::nullopt);
ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
const string& key_material, vector<uint8_t>* key_blob,
@@ -106,7 +129,9 @@
string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
const string& message, const AuthorizationSet& in_params,
AuthorizationSet* out_params);
-
+ std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
+ ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+ const std::string& message, const AuthorizationSet& in_params);
string SignMessage(const vector<uint8_t>& key_blob, const string& message,
const AuthorizationSet& params);
string SignMessage(const string& message, const AuthorizationSet& params);
@@ -149,6 +174,56 @@
std::pair<ErrorCode, vector<uint8_t>> UpgradeKey(const vector<uint8_t>& key_blob);
+ template <typename TagType>
+ std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
+ KeyData /* ecdsaKey */>
+ CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+ /* AES */
+ KeyData aesKeyData;
+ ErrorCode errorCode = GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(tagToTest)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED),
+ &aesKeyData.blob, &aesKeyData.characteristics);
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* HMAC */
+ KeyData hmacKeyData;
+ errorCode = GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED),
+ &hmacKeyData.blob, &hmacKeyData.characteristics);
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* RSA */
+ KeyData rsaKeyData;
+ errorCode = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(tagToTest)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ &rsaKeyData.blob, &rsaKeyData.characteristics);
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* ECDSA */
+ KeyData ecdsaKeyData;
+ errorCode = GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(256)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
+ EXPECT_EQ(expectedReturn, errorCode);
+ return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+ }
bool IsSecure() const { return securityLevel_ != SecurityLevel::SOFTWARE; }
SecurityLevel SecLevel() const { return securityLevel_; }
@@ -182,6 +257,10 @@
const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(
const vector<KeyCharacteristics>& key_characteristics);
+ ErrorCode UseAesKey(const vector<uint8_t>& aesKeyBlob);
+ ErrorCode UseHmacKey(const vector<uint8_t>& hmacKeyBlob);
+ ErrorCode UseRsaKey(const vector<uint8_t>& rsaKeyBlob);
+ ErrorCode UseEcdsaKey(const vector<uint8_t>& ecdsaKeyBlob);
private:
std::shared_ptr<IKeyMintDevice> keymint_;
@@ -194,6 +273,16 @@
long challenge_;
};
+bool verify_attestation_record(const string& challenge, //
+ const string& app_id, //
+ AuthorizationSet expected_sw_enforced, //
+ AuthorizationSet expected_hw_enforced, //
+ SecurityLevel security_level,
+ const vector<uint8_t>& attestation_cert);
+string bin2hex(const vector<uint8_t>& data);
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
+::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
+
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 88122ce..71aae90 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "keymint_5_test"
+#define LOG_TAG "keymint_1_test"
#include <cutils/log.h>
#include <signal.h>
@@ -23,34 +23,21 @@
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
-#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <cutils/properties.h>
#include <aidl/android/hardware/security/keymint/KeyFormat.h>
-#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/openssl_utils.h>
#include "KeyMintAidlTestBase.h"
-static bool arm_deleteAllKeys = false;
-static bool dump_Attestations = false;
-
using aidl::android::hardware::security::keymint::AuthorizationSet;
using aidl::android::hardware::security::keymint::KeyCharacteristics;
using aidl::android::hardware::security::keymint::KeyFormat;
-namespace aidl::android::hardware::security::keymint {
-
-bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
- return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
-}
-
-} // namespace aidl::android::hardware::security::keymint
-
namespace std {
using namespace aidl::android::hardware::security::keymint;
@@ -78,7 +65,8 @@
namespace {
template <TagType tag_type, Tag tag, typename ValueT>
-bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+bool contains(const vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag,
+ ValueT expected_value) {
auto it = std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
if (auto p = authorizationValue(ttag, param)) {
return *p == expected_value;
@@ -89,7 +77,7 @@
}
template <TagType tag_type, Tag tag>
-bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag>) {
+bool contains(const vector<KeyParameter>& set, TypedTag<tag_type, tag>) {
auto it = std::find_if(set.begin(), set.end(),
[&](const KeyParameter& param) { return param.tag == tag; });
return (it != set.end());
@@ -182,281 +170,6 @@
void operator()(RSA* p) { RSA_free(p); }
};
-char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
-string bin2hex(const vector<uint8_t>& data) {
- string retval;
- retval.reserve(data.size() * 2 + 1);
- for (uint8_t byte : data) {
- retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
- retval.push_back(nibble2hex[0x0F & byte]);
- }
- return retval;
-}
-
-X509* parse_cert_blob(const vector<uint8_t>& blob) {
- const uint8_t* p = blob.data();
- return d2i_X509(nullptr, &p, blob.size());
-}
-
-bool verify_chain(const vector<Certificate>& chain) {
- for (size_t i = 0; i < chain.size(); ++i) {
- X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
- X509_Ptr signing_cert;
- if (i < chain.size() - 1) {
- signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate));
- } else {
- signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate));
- }
- EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
- if (!key_cert.get() || !signing_cert.get()) return false;
-
- EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
- EXPECT_TRUE(!!signing_pubkey.get());
- if (!signing_pubkey.get()) return false;
-
- EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
- << "Verification of certificate " << i << " failed "
- << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-
- char* cert_issuer = //
- X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
- char* signer_subj =
- X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
- EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
- if (i == 0) {
- char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
- EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
- << "Cert " << i << " has wrong subject.";
- OPENSSL_free(cert_sub);
- }
-
- OPENSSL_free(cert_issuer);
- OPENSSL_free(signer_subj);
-
- if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl;
- }
-
- return true;
-}
-
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
- ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
- EXPECT_TRUE(!!oid.get());
- if (!oid.get()) return nullptr;
-
- int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
- EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
- if (location == -1) return nullptr;
-
- X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
- EXPECT_TRUE(!!attest_rec_ext)
- << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
- if (!attest_rec_ext) return nullptr;
-
- ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
- EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
- return attest_rec;
-}
-
-bool tag_in_list(const KeyParameter& entry) {
- // Attestations don't contain everything in key authorization lists, so we need to filter
- // the key lists to produce the lists that we expect to match the attestations.
- auto tag_list = {
- Tag::BLOB_USAGE_REQUIREMENTS, //
- Tag::CREATION_DATETIME, //
- Tag::EC_CURVE,
- Tag::HARDWARE_TYPE,
- Tag::INCLUDE_UNIQUE_ID,
- };
- return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
-}
-
-AuthorizationSet filtered_tags(const AuthorizationSet& set) {
- AuthorizationSet filtered;
- std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
- return filtered;
-}
-
-bool avb_verification_enabled() {
- char value[PROPERTY_VALUE_MAX];
- return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
-}
-
-bool verify_attestation_record(const string& challenge, //
- const string& app_id, //
- AuthorizationSet expected_sw_enforced, //
- AuthorizationSet expected_hw_enforced, //
- SecurityLevel security_level,
- const vector<uint8_t>& attestation_cert) {
- X509_Ptr cert(parse_cert_blob(attestation_cert));
- EXPECT_TRUE(!!cert.get());
- if (!cert.get()) return false;
-
- ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
- EXPECT_TRUE(!!attest_rec);
- if (!attest_rec) return false;
-
- AuthorizationSet att_sw_enforced;
- AuthorizationSet att_hw_enforced;
- uint32_t att_attestation_version;
- uint32_t att_keymaster_version;
- SecurityLevel att_attestation_security_level;
- SecurityLevel att_keymaster_security_level;
- vector<uint8_t> att_challenge;
- vector<uint8_t> att_unique_id;
- vector<uint8_t> att_app_id;
-
- auto error = 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);
- EXPECT_EQ(ErrorCode::OK, error);
- if (error != ErrorCode::OK) return false;
-
- EXPECT_GE(att_attestation_version, 3U);
-
- expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
- vector<uint8_t>(app_id.begin(), app_id.end()));
-
- EXPECT_GE(att_keymaster_version, 4U);
- EXPECT_EQ(security_level, att_keymaster_security_level);
- EXPECT_EQ(security_level, att_attestation_security_level);
-
- EXPECT_EQ(challenge.length(), att_challenge.size());
- EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
-
- char property_value[PROPERTY_VALUE_MAX] = {};
- // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
- // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
- // for the BOOT_PATCH_LEVEL.
- if (avb_verification_enabled()) {
- for (int i = 0; i < att_hw_enforced.size(); i++) {
- if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
- att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
- std::string date =
- std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
- // strptime seems to require delimiters, but the tag value will
- // be YYYYMMDD
- date.insert(6, "-");
- date.insert(4, "-");
- EXPECT_EQ(date.size(), 10);
- struct tm time;
- strptime(date.c_str(), "%Y-%m-%d", &time);
-
- // Day of the month (0-31)
- EXPECT_GE(time.tm_mday, 0);
- EXPECT_LT(time.tm_mday, 32);
- // Months since Jan (0-11)
- EXPECT_GE(time.tm_mon, 0);
- EXPECT_LT(time.tm_mon, 12);
- // Years since 1900
- EXPECT_GT(time.tm_year, 110);
- EXPECT_LT(time.tm_year, 200);
- }
- }
- }
-
- // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates
- // true. A provided boolean tag that can be pulled back out of the certificate indicates correct
- // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
- // will handle mismatches of tags.
- if (security_level == SecurityLevel::SOFTWARE) {
- EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
- } else {
- EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
- }
-
- // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
- // the authorization list during key generation) isn't being attested to in the certificate.
- EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-
- if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
- // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
- EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
- att_hw_enforced.Contains(TAG_KEY_SIZE));
- }
-
- // Test root of trust elements
- vector<uint8_t> verified_boot_key;
- VerifiedBoot verified_boot_state;
- bool device_locked;
- vector<uint8_t> verified_boot_hash;
- error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
- &verified_boot_state, &device_locked, &verified_boot_hash);
- EXPECT_EQ(ErrorCode::OK, error);
-
- if (avb_verification_enabled()) {
- EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
- string prop_string(property_value);
- EXPECT_EQ(prop_string.size(), 64);
- EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
- EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
- if (!strcmp(property_value, "unlocked")) {
- EXPECT_FALSE(device_locked);
- } else {
- EXPECT_TRUE(device_locked);
- }
-
- // Check that the device is locked if not debuggable, e.g., user build
- // images in CTS. For VTS, debuggable images are used to allow adb root
- // and the device is unlocked.
- if (!property_get_bool("ro.debuggable", false)) {
- EXPECT_TRUE(device_locked);
- } else {
- EXPECT_FALSE(device_locked);
- }
- }
-
- // Verified boot key should be all 0's if the boot state is not verified or self signed
- std::string empty_boot_key(32, '\0');
- std::string verified_boot_key_str((const char*)verified_boot_key.data(),
- verified_boot_key.size());
- EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
- if (!strcmp(property_value, "green")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "yellow")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "orange")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "red")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
- } else {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- }
-
- att_sw_enforced.Sort();
- expected_sw_enforced.Sort();
- EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));
-
- att_hw_enforced.Sort();
- expected_hw_enforced.Sort();
- EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
-
- return true;
-}
-
std::string make_string(const uint8_t* data, size_t length) {
return std::string(reinterpret_cast<const char*>(data), length);
}
@@ -595,7 +308,7 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
- EXPECT_TRUE(verify_chain(cert_chain_));
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -691,7 +404,7 @@
<< "key usage count limit " << 1U << " missing";
// Check the usage count limit tag also appears in the attestation.
- EXPECT_TRUE(verify_chain(cert_chain_));
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -4596,6 +4309,57 @@
}
}
+/*
+ * UsageCountLimitTest.TestSingleUseKeyAndRollbackResistance
+ *
+ * Verifies that when rollback resistance is supported by the KeyMint implementation with
+ * the secure hardware, the single use key with usage count limit tag = 1 must also be enforced
+ * in hardware.
+ */
+TEST_P(UsageCountLimitTest, TestSingleUseKeyAndRollbackResistance) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE)
+ .SetDefaultValidity());
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+ if (error == ErrorCode::OK) {
+ // Rollback resistance is supported by KeyMint, verify it is enforced in hardware.
+ AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_EQ(ErrorCode::OK, DeleteKey());
+
+ // The KeyMint should also enforce single use key in hardware when it supports rollback
+ // resistance.
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 65537)
+ .NoDigestOrPadding()
+ .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
+ .SetDefaultValidity()));
+
+ // Check the usage count limit tag appears in the hardware authorizations.
+ AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
+ EXPECT_TRUE(hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
+ << "key usage count limit " << 1U << " missing";
+
+ string message = "1234567890123456";
+ auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+ // First usage of RSA key should work.
+ SignMessage(message, params);
+
+ // Usage count limit tag is enforced by hardware. After using the key, the key blob
+ // must be invalidated from secure storage (such as RPMB partition).
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
+ }
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(UsageCountLimitTest);
typedef KeyMintAidlTestBase AddEntropyTest;
@@ -4645,7 +4409,8 @@
.Digest(Digest::NONE)
.Padding(PaddingMode::NONE)
.Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_ROLLBACK_RESISTANCE));
+ .Authorization(TAG_ROLLBACK_RESISTANCE)
+ .SetDefaultValidity());
ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
// Delete must work if rollback protection is implemented
@@ -4678,7 +4443,8 @@
.Digest(Digest::NONE)
.Padding(PaddingMode::NONE)
.Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_ROLLBACK_RESISTANCE));
+ .Authorization(TAG_ROLLBACK_RESISTANCE)
+ .SetDefaultValidity());
ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
// Delete must work if rollback protection is implemented
@@ -4961,17 +4727,122 @@
INSTANTIATE_KEYMINT_AIDL_TEST(KeyAgreementTest);
+typedef KeyMintAidlTestBase EarlyBootKeyTest;
+
+TEST_P(EarlyBootKeyTest, CreateEarlyBootKeys) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+ CheckedDeleteKey(&rsaKeyData.blob);
+ CheckedDeleteKey(&ecdsaKeyData.blob);
+}
+
+// This is a more comprenhensive test, but it can only be run on a machine which is still in early
+// boot stage, which no proper Android device is by the time we can run VTS. To use this,
+// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end
+// early boot, so you'll have to reboot between runs.
+TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+ // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
+ EXPECT_TRUE(HwEnforcedAuthorizations(aesKeyData.characteristics).Contains(TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(
+ HwEnforcedAuthorizations(hmacKeyData.characteristics).Contains(TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(HwEnforcedAuthorizations(rsaKeyData.characteristics).Contains(TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(
+ HwEnforcedAuthorizations(ecdsaKeyData.characteristics).Contains(TAG_EARLY_BOOT_ONLY));
+
+ // Should be able to use keys, since early boot has not ended
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ // End early boot
+ ErrorCode earlyBootResult = GetReturnErrorCode(keyMint().earlyBootEnded());
+ EXPECT_EQ(earlyBootResult, ErrorCode::OK);
+
+ // Should not be able to use already-created keys.
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+ CheckedDeleteKey(&rsaKeyData.blob);
+ CheckedDeleteKey(&ecdsaKeyData.blob);
+
+ // Should not be able to create new keys
+ std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+ CheckedDeleteKey(&rsaKeyData.blob);
+ CheckedDeleteKey(&ecdsaKeyData.blob);
+}
+INSTANTIATE_KEYMINT_AIDL_TEST(EarlyBootKeyTest);
+
+typedef KeyMintAidlTestBase UnlockedDeviceRequiredTest;
+
+// This may be a problematic test. It can't be run repeatedly without unlocking the device in
+// between runs... and on most test devices there are no enrolled credentials so it can't be
+// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
+// device is to reboot it. For that reason, this is disabled by default. It can be used as part of
+// a manual test process, which includes unlocking between runs, which is why it's included here.
+// Well, that and the fact that it's the only test we can do without also making calls into the
+// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the
+// implications might be, so that may or may not be a solution.
+TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ ErrorCode rc = GetReturnErrorCode(
+ keyMint().deviceLocked(false /* passwordOnly */, {} /* verificationToken */));
+ ASSERT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+ CheckedDeleteKey(&rsaKeyData.blob);
+ CheckedDeleteKey(&ecdsaKeyData.blob);
+}
+INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
+
} // namespace aidl::android::hardware::security::keymint::test
int main(int argc, char** argv) {
+ std::cout << "Testing ";
+ auto halInstances =
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
+ std::cout << "HAL instances:\n";
+ for (auto& entry : halInstances) {
+ std::cout << " " << entry << '\n';
+ }
+
::testing::InitGoogleTest(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (std::string(argv[i]) == "--arm_deleteAllKeys") {
- arm_deleteAllKeys = true;
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+ arm_deleteAllKeys = true;
}
if (std::string(argv[i]) == "--dump_attestations") {
- dump_Attestations = true;
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+ dump_Attestations = true;
+ } else {
+ std::cout << "NOT dumping attestations" << std::endl;
}
}
}
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
new file mode 100644
index 0000000..45f9df6
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
+
+#include <RemotelyProvisionedComponent.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <android/binder_manager.h>
+#include <cppbor_parse.h>
+#include <cppcose/cppcose.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <keymaster/keymaster_configuration.h>
+#include <remote_prov/remote_prov_utils.h>
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using ::std::string;
+using ::std::vector;
+
+namespace {
+
+#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P( \
+ PerInstance, name, \
+ testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
+ ::android::PrintInstanceNameToString)
+
+using bytevec = std::vector<uint8_t>;
+using testing::MatchesRegex;
+using namespace remote_prov;
+using namespace keymaster;
+
+bytevec string_to_bytevec(const char* s) {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
+ return bytevec(p, p + strlen(s));
+}
+
+} // namespace
+
+class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ if (AServiceManager_isDeclared(GetParam().c_str())) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
+ }
+ ASSERT_NE(provisionable_, nullptr);
+ }
+
+ static vector<string> build_params() {
+ auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+ return params;
+ }
+
+ protected:
+ std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
+};
+
+using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
+
+/**
+ * Generate and validate a production-mode key. MAC tag can't be verified.
+ */
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_prodMode) {
+ MacedPublicKey macedPubKey;
+ bytevec privateKeyBlob;
+ bool testMode = false;
+ auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk());
+
+ auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+ ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+ ASSERT_NE(coseMac0->asArray(), nullptr);
+ ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+ auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+ ASSERT_NE(protParms, nullptr);
+ ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
+
+ auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+ ASSERT_NE(unprotParms, nullptr);
+ ASSERT_EQ(unprotParms->value().size(), 0);
+
+ auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+ ASSERT_NE(payload, nullptr);
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n"
+ " 3 : -7,\n"
+ " -1 : 1,\n"
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
+ // 32 hexadecimal bytes, enclosed in braces and separated by commas.
+ // In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+ "}"));
+
+ auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+ ASSERT_TRUE(coseMac0Tag);
+ auto extractedTag = coseMac0Tag->value();
+ EXPECT_EQ(extractedTag.size(), 32U);
+
+ // Compare with tag generated with kTestMacKey. Shouldn't match.
+ auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+ payload->value());
+ ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+
+ EXPECT_NE(*testTag, extractedTag);
+}
+
+/**
+ * Generate and validate a test-mode key.
+ */
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_testMode) {
+ MacedPublicKey macedPubKey;
+ bytevec privateKeyBlob;
+ bool testMode = true;
+ auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk());
+
+ auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+ ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+ ASSERT_NE(coseMac0->asArray(), nullptr);
+ ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+ auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+ ASSERT_NE(protParms, nullptr);
+ ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
+
+ auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+ ASSERT_NE(unprotParms, nullptr);
+ ASSERT_EQ(unprotParms->value().size(), 0);
+
+ auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+ ASSERT_NE(payload, nullptr);
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n"
+ " 3 : -7,\n"
+ " -1 : 1,\n"
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
+ // 32 hexadecimal bytes, enclosed in braces and separated by commas.
+ // In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+ " -70000 : null,\n"
+ "}"));
+
+ auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+ ASSERT_TRUE(coseMac0);
+ auto extractedTag = coseMac0Tag->value();
+ EXPECT_EQ(extractedTag.size(), 32U);
+
+ // Compare with tag generated with kTestMacKey. Should match.
+ auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+ payload->value());
+ ASSERT_TRUE(testTag) << testTag.message();
+
+ EXPECT_EQ(*testTag, extractedTag);
+}
+
+class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+ protected:
+ CertificateRequestTest() : eekId_(string_to_bytevec("eekid")) {
+ auto chain = generateEekChain(3, eekId_);
+ EXPECT_TRUE(chain) << chain.message();
+ if (chain) eekChain_ = chain.moveValue();
+ }
+
+ void generateKeys(bool testMode, size_t numKeys) {
+ keysToSign_ = std::vector<MacedPublicKey>(numKeys);
+ cborKeysToSign_ = cppbor::Array();
+
+ for (auto& key : keysToSign_) {
+ bytevec privateKeyBlob;
+ auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto [parsedMacedKey, _, parseErr] = cppbor::parse(key.macedKey);
+ ASSERT_TRUE(parsedMacedKey) << "Failed parsing MACed key: " << parseErr;
+ ASSERT_TRUE(parsedMacedKey->asArray()) << "COSE_Mac0 not an array?";
+ ASSERT_EQ(parsedMacedKey->asArray()->size(), kCoseMac0EntryCount);
+
+ auto& payload = parsedMacedKey->asArray()->get(kCoseMac0Payload);
+ ASSERT_TRUE(payload);
+ ASSERT_TRUE(payload->asBstr());
+
+ cborKeysToSign_.add(cppbor::EncodedItem(payload->asBstr()->value()));
+ }
+ }
+
+ bytevec eekId_;
+ EekChain eekChain_;
+ std::vector<MacedPublicKey> keysToSign_;
+ cppbor::Array cborKeysToSign_;
+};
+
+/**
+ * Generate an empty certificate request in test mode, and decrypt and verify the structure and
+ * content.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_testMode) {
+ bool testMode = true;
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto challenge = randomBytes(32);
+ auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
+ eekChain_.chain, challenge,
+ &keysToSignMac, &protectedData);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+ ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
+ ASSERT_TRUE(parsedProtectedData->asArray());
+ ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+
+ auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+ ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+ EXPECT_EQ(senderPubkey->second, eekId_);
+
+ auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+ auto protectedDataPayload =
+ decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+ ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
+
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+ ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+ ASSERT_TRUE(parsedPayload->asArray());
+ EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+
+ auto& signedMac = parsedPayload->asArray()->get(0);
+ auto& bcc = parsedPayload->asArray()->get(1);
+ ASSERT_TRUE(signedMac && signedMac->asArray());
+ ASSERT_TRUE(bcc && bcc->asArray());
+
+ // BCC is [ pubkey, + BccEntry]
+ auto bccContents = validateBcc(bcc->asArray());
+ ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
+ ASSERT_GT(bccContents->size(), 0U);
+
+ auto& signingKey = bccContents->back().pubKey;
+ auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
+ cppbor::Array() // DeviceInfo
+ .add(challenge) //
+ .add(cppbor::Map())
+ .encode());
+ ASSERT_TRUE(macKey) << macKey.message();
+
+ auto coseMac0 = cppbor::Array()
+ .add(cppbor::Map() // protected
+ .add(ALGORITHM, HMAC_256)
+ .canonicalize()
+ .encode())
+ .add(cppbor::Bstr()) // unprotected
+ .add(cppbor::Array().encode()) // payload (keysToSign)
+ .add(std::move(keysToSignMac)); // tag
+
+ auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+ ASSERT_TRUE(macPayload) << macPayload.message();
+}
+
+/**
+ * Generate an empty certificate request in prod mode. Generation will fail because we don't have a
+ * valid GEEK.
+ *
+ * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
+ * able to decrypt.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
+ bool testMode = false;
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto challenge = randomBytes(32);
+ auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
+ eekChain_.chain, challenge,
+ &keysToSignMac, &protectedData);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+}
+
+/**
+ * Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testMode) {
+ bool testMode = true;
+ generateKeys(testMode, 4 /* numKeys */);
+
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto challenge = randomBytes(32);
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+ ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
+ ASSERT_TRUE(parsedProtectedData->asArray());
+ ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+
+ auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+ ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+ EXPECT_EQ(senderPubkey->second, eekId_);
+
+ auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
+ ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+ auto protectedDataPayload =
+ decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+ ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
+
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+ ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+ ASSERT_TRUE(parsedPayload->asArray());
+ EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+
+ auto& signedMac = parsedPayload->asArray()->get(0);
+ auto& bcc = parsedPayload->asArray()->get(1);
+ ASSERT_TRUE(signedMac && signedMac->asArray());
+ ASSERT_TRUE(bcc);
+
+ auto bccContents = validateBcc(bcc->asArray());
+ ASSERT_TRUE(bccContents) << "\n" << prettyPrint(bcc.get());
+ ASSERT_GT(bccContents->size(), 0U);
+
+ auto& signingKey = bccContents->back().pubKey;
+ auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
+ cppbor::Array() // DeviceInfo
+ .add(challenge) //
+ .add(cppbor::Array())
+ .encode());
+ ASSERT_TRUE(macKey) << macKey.message();
+
+ auto coseMac0 = cppbor::Array()
+ .add(cppbor::Map() // protected
+ .add(ALGORITHM, HMAC_256)
+ .canonicalize()
+ .encode())
+ .add(cppbor::Bstr()) // unprotected
+ .add(cborKeysToSign_.encode()) // payload
+ .add(std::move(keysToSignMac)); // tag
+
+ auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+ ASSERT_TRUE(macPayload) << macPayload.message();
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
+ * GEEK.
+ *
+ * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
+ * able to decrypt.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
+ bool testMode = false;
+ generateKeys(testMode, 4 /* numKeys */);
+
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto challenge = randomBytes(32);
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+}
+
+/**
+ * Generate a non-empty certificate request in test mode, with prod keys. Must fail with
+ * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodKeyInTestCert) {
+ generateKeys(false /* testMode */, 2 /* numKeys */);
+
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto challenge = randomBytes(32);
+ auto status = provisionable_->generateCertificateRequest(true /* testMode */, keysToSign_,
+ eekChain_.chain, challenge,
+ &keysToSignMac, &protectedData);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getServiceSpecificError(),
+ BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, with test keys. Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testKeyInProdCert) {
+ generateKeys(true /* testMode */, 2 /* numKeys */);
+
+ bytevec keysToSignMac;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ false /* testMode */, keysToSign_, eekChain_.chain, randomBytes(32) /* challenge */,
+ &keysToSignMac, &protectedData);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(status.getServiceSpecificError(),
+ BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+}
+
+INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
+
+} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index fde6b57..efdff2b 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -37,3 +37,40 @@
"libutils",
],
}
+
+cc_library {
+ name: "libkeymint_remote_prov_support",
+ vendor_available: true,
+ srcs: [
+ "remote_prov_utils.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libcppcose",
+ "libcppbor_external",
+ "libcrypto",
+ ],
+}
+
+cc_library {
+ name: "libcppcose",
+ vendor_available: true,
+ srcs: [
+ "cppcose.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcppbor_external",
+ "libcrypto",
+ "liblog",
+ ],
+ static_libs: [
+ // TODO(swillden): Remove keymint NDK
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ ],
+}
diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp
index 8d42571..25eace3 100644
--- a/security/keymint/support/authorization_set.cpp
+++ b/security/keymint/support/authorization_set.cpp
@@ -191,6 +191,10 @@
return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
}
+AuthorizationSetBuilder& AuthorizationSetBuilder::AttestKey() {
+ return Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+}
+
AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
Authorization(TAG_DIGEST, Digest::NONE);
return Authorization(TAG_PADDING, PaddingMode::NONE);
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
new file mode 100644
index 0000000..c626ade
--- /dev/null
+++ b/security/keymint/support/cppcose.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cppcose/cppcose.h>
+
+#include <stdio.h>
+#include <iostream>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/err.h>
+
+namespace cppcose {
+
+namespace {
+
+ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
+ const bytevec& nonce,
+ const bytevec& aad,
+ bool encrypt) {
+ if (key.size() != kAesGcmKeySize) return "Invalid key size";
+
+ bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+ if (!ctx) return "Failed to allocate cipher context";
+
+ if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
+ nonce.data(), encrypt ? 1 : 0)) {
+ return "Failed to initialize cipher";
+ }
+
+ int outlen;
+ if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
+ aad.data(), aad.size())) {
+ return "Failed to process AAD";
+ }
+
+ return std::move(ctx);
+}
+
+} // namespace
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+ const bytevec& payload) {
+ auto macStructure = cppbor::Array()
+ .add("MAC0")
+ .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+ .add(externalAad)
+ .add(payload)
+ .encode();
+
+ bytevec macTag(SHA256_DIGEST_LENGTH);
+ uint8_t* out = macTag.data();
+ unsigned int outLen;
+ out = HMAC(EVP_sha256(), //
+ macKey.data(), macKey.size(), //
+ macStructure.data(), macStructure.size(), //
+ out, &outLen);
+
+ assert(out != nullptr && outLen == macTag.size());
+ if (out == nullptr || outLen != macTag.size()) {
+ return "Error computing public key MAC";
+ }
+
+ return macTag;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+ const bytevec& payload) {
+ auto tag = generateCoseMac0Mac(macKey, externalAad, payload);
+ if (!tag) return tag.moveMessage();
+
+ return cppbor::Array()
+ .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+ .add(cppbor::Bstr() /* unprotected */)
+ .add(payload)
+ .add(tag.moveValue());
+}
+
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) {
+ auto mac = macItem ? macItem->asArray() : nullptr;
+ if (!mac || mac->size() != kCoseMac0EntryCount) {
+ return "Invalid COSE_Mac0";
+ }
+
+ auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+ auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+ auto payload = mac->get(kCoseMac0Payload)->asBstr();
+ auto tag = mac->get(kCoseMac0Tag)->asBstr();
+ if (!protectedParms || !unprotectedParms || !payload || !tag) {
+ return "Invalid COSE_Mac0 contents";
+ }
+
+ return payload->value();
+}
+
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+ const bytevec& macKey) {
+ auto mac = macItem ? macItem->asArray() : nullptr;
+ if (!mac || mac->size() != kCoseMac0EntryCount) {
+ return "Invalid COSE_Mac0";
+ }
+
+ auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+ auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+ auto payload = mac->get(kCoseMac0Payload)->asBstr();
+ auto tag = mac->get(kCoseMac0Tag)->asBstr();
+ if (!protectedParms || !unprotectedParms || !payload || !tag) {
+ return "Invalid COSE_Mac0 contents";
+ }
+
+ auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
+ if (!protectedMap || !protectedMap->asMap()) {
+ return "Invalid Mac0 protected: " + errMsg;
+ }
+ auto& algo = protectedMap->asMap()->get(ALGORITHM);
+ if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+ return "Unsupported Mac0 algorithm";
+ }
+
+ auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
+ if (!macTag) return macTag.moveMessage();
+
+ if (macTag->size() != tag->value().size() ||
+ CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+ return "MAC tag mismatch";
+ }
+
+ return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+ const bytevec& payload, const bytevec& aad) {
+ bytevec signatureInput = cppbor::Array()
+ .add("Signature1") //
+ .add(protectedParams)
+ .add(aad)
+ .add(payload)
+ .encode();
+
+ if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
+ bytevec signature(ED25519_SIGNATURE_LEN);
+ if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
+ return "Signing failed";
+ }
+
+ return signature;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
+ const bytevec& payload, const bytevec& aad) {
+ bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
+ auto signature = createCoseSign1Signature(key, protParms, payload, aad);
+ if (!signature) return signature.moveMessage();
+
+ return cppbor::Array()
+ .add(protParms)
+ .add(bytevec{} /* unprotected parameters */)
+ .add(payload)
+ .add(*signature);
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+ const bytevec& aad) {
+ return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1,
+ const bytevec& signingCoseKey, const bytevec& aad) {
+ if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+ return "Invalid COSE_Sign1";
+ }
+
+ const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+ const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+ const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+ const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+ if (!protectedParams || !unprotectedParams || !payload || !signature) {
+ return "Invalid COSE_Sign1";
+ }
+
+ auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+ if (!parsedProtParams) {
+ return errMsg + " when parsing protected params.";
+ }
+ if (!parsedProtParams->asMap()) {
+ return "Protected params must be a map";
+ }
+
+ auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+ if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+ return "Unsupported signature algorithm";
+ }
+
+ if (!ignoreSignature) {
+ bool selfSigned = signingCoseKey.empty();
+ auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
+ if (!key) return "Bad signing key: " + key.moveMessage();
+
+ bytevec signatureInput = cppbor::Array()
+ .add("Signature1")
+ .add(*protectedParams)
+ .add(aad)
+ .add(*payload)
+ .encode();
+
+ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+ key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+ return "Signature verification failed";
+ }
+ }
+
+ return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+ const bytevec& protectedParams,
+ const bytevec& plaintextPayload, const bytevec& aad) {
+ auto ciphertext = aesGcmEncrypt(key, nonce,
+ cppbor::Array() // Enc strucure as AAD
+ .add("Encrypt") // Context
+ .add(protectedParams) // Protected
+ .add(aad) // External AAD
+ .encode(),
+ plaintextPayload);
+
+ if (!ciphertext) return ciphertext.moveMessage();
+ return ciphertext.moveValue();
+}
+
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+ const bytevec& plaintextPayload, const bytevec& aad,
+ cppbor::Array recipients) {
+ auto encryptProtectedHeader = cppbor::Map() //
+ .add(ALGORITHM, AES_GCM_256)
+ .canonicalize()
+ .encode();
+
+ auto ciphertext =
+ createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
+ if (!ciphertext) return ciphertext.moveMessage();
+
+ return cppbor::Array()
+ .add(encryptProtectedHeader) // Protected
+ .add(cppbor::Map().add(IV, nonce).canonicalize()) // Unprotected
+ .add(*ciphertext) // Payload
+ .add(std::move(recipients));
+}
+
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+ const cppbor::Item* coseEncrypt) {
+ if (!coseEncrypt || !coseEncrypt->asArray() ||
+ coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+ return "Invalid COSE_Encrypt";
+ }
+
+ auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+ if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
+ return "Invalid recipients list";
+ }
+
+ auto& recipient = recipients->asArray()->get(0);
+ if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
+ return "Invalid COSE_recipient";
+ }
+
+ auto& ciphertext = recipient->asArray()->get(2);
+ if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
+ return "Unexpected value in recipients ciphertext field " +
+ cppbor::prettyPrint(ciphertext.get());
+ }
+
+ auto& protParms = recipient->asArray()->get(0);
+ if (!protParms || !protParms->asBstr()) return "Invalid protected params";
+ auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
+ if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
+ if (!parsedProtParms->asMap()) return "Invalid protected params";
+
+ auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
+ if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
+ return "Invalid algorithm";
+ }
+
+ auto& unprotParms = recipient->asArray()->get(1);
+ if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
+
+ auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
+ if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
+
+ auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
+ if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
+ return "Invalid key type";
+ }
+
+ auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
+ if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
+ return "Unsupported curve";
+ }
+
+ auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
+ if (!pubkey || !pubkey->asBstr() ||
+ pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+ return "Invalid X25519 public key";
+ }
+
+ auto& key_id = unprotParms->asMap()->get(KEY_ID);
+ if (key_id && key_id->asBstr()) {
+ return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
+ }
+
+ // If no key ID, just return an empty vector.
+ return std::make_pair(pubkey->asBstr()->value(), bytevec{});
+}
+
+ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
+ const bytevec& external_aad) {
+ if (!coseEncrypt || !coseEncrypt->asArray() ||
+ coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+ return "Invalid COSE_Encrypt";
+ }
+
+ auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
+ auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
+ auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
+ auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+
+ if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
+ return "Invalid COSE_Encrypt";
+ }
+
+ auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
+ if (!parsedProtParams) {
+ return errMsg + " when parsing protected params.";
+ }
+ if (!parsedProtParams->asMap()) {
+ return "Protected params must be a map";
+ }
+
+ auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+ if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
+ return "Unsupported encryption algorithm";
+ }
+
+ if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
+ return "Invalid unprotected params";
+ }
+
+ auto& nonce = unprotParms->asMap()->get(IV);
+ if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
+ return "Invalid nonce";
+ }
+
+ if (!ciphertext->asBstr()) return "Invalid ciphertext";
+
+ auto aad = cppbor::Array() // Enc strucure as AAD
+ .add("Encrypt") // Context
+ .add(protParms->asBstr()->value()) // Protected
+ .add(external_aad) // External AAD
+ .encode();
+
+ return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
+}
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
+ const bytevec& pubKeyB, bool senderIsA) {
+ bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
+ if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
+ return "ECDH operation failed";
+ }
+
+ bytevec kdfContext = cppbor::Array()
+ .add(AES_GCM_256)
+ .add(cppbor::Array() // Sender Info
+ .add(cppbor::Bstr("client"))
+ .add(bytevec{} /* nonce */)
+ .add(senderIsA ? pubKeyA : pubKeyB))
+ .add(cppbor::Array() // Recipient Info
+ .add(cppbor::Bstr("server"))
+ .add(bytevec{} /* nonce */)
+ .add(senderIsA ? pubKeyB : pubKeyA))
+ .add(cppbor::Array() // SuppPubInfo
+ .add(128) // output key length
+ .add(bytevec{})) // protected
+ .encode();
+
+ bytevec retval(SHA256_DIGEST_LENGTH);
+ bytevec salt{};
+ if (!HKDF(retval.data(), retval.size(), //
+ EVP_sha256(), //
+ rawSharedKey.data(), rawSharedKey.size(), //
+ salt.data(), salt.size(), //
+ kdfContext.data(), kdfContext.size())) {
+ return "ECDH HKDF failed";
+ }
+
+ return retval;
+}
+
+ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+ const bytevec& plaintext) {
+ auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
+ if (!ctx) return ctx.moveMessage();
+
+ bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
+ int outlen;
+ if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
+ plaintext.size())) {
+ return "Failed to encrypt plaintext";
+ }
+ assert(plaintext.size() == outlen);
+
+ if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
+ return "Failed to finalize encryption";
+ }
+ assert(outlen == 0);
+
+ if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
+ ciphertext.data() + plaintext.size())) {
+ return "Failed to retrieve tag";
+ }
+
+ return ciphertext;
+}
+
+ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+ const bytevec& ciphertextWithTag) {
+ auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
+ if (!ctx) return ctx.moveMessage();
+
+ if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
+
+ bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
+ int outlen;
+ if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
+ ciphertextWithTag.size() - kAesGcmTagSize)) {
+ return "Failed to decrypt plaintext";
+ }
+ assert(plaintext.size() == outlen);
+
+ bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
+ if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
+ return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
+ }
+
+ if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
+ return "Failed to finalize encryption";
+ }
+ assert(outlen == 0);
+
+ return plaintext;
+}
+
+} // namespace cppcose
diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h
new file mode 100644
index 0000000..a936bfd
--- /dev/null
+++ b/security/keymint/support/include/cppcose/cppcose.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+namespace cppcose {
+
+using bytevec = std::vector<uint8_t>;
+
+constexpr int kCoseSign1EntryCount = 4;
+constexpr int kCoseSign1ProtectedParams = 0;
+constexpr int kCoseSign1UnprotectedParams = 1;
+constexpr int kCoseSign1Payload = 2;
+constexpr int kCoseSign1Signature = 3;
+
+constexpr int kCoseMac0EntryCount = 4;
+constexpr int kCoseMac0ProtectedParams = 0;
+constexpr int kCoseMac0UnprotectedParams = 1;
+constexpr int kCoseMac0Payload = 2;
+constexpr int kCoseMac0Tag = 3;
+
+constexpr int kCoseEncryptEntryCount = 4;
+constexpr int kCoseEncryptProtectedParams = 0;
+constexpr int kCoseEncryptUnprotectedParams = 1;
+constexpr int kCoseEncryptPayload = 2;
+constexpr int kCoseEncryptRecipients = 3;
+
+enum Label : int {
+ ALGORITHM = 1,
+ KEY_ID = 4,
+ IV = 5,
+ COSE_KEY = -1,
+};
+
+enum CoseKeyAlgorithm : int {
+ AES_GCM_256 = 3,
+ HMAC_256 = 5,
+ ES256 = -7, // ECDSA with SHA-256
+ EDDSA = -8,
+ ECDH_ES_HKDF_256 = -25,
+};
+
+enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
+enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
+enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
+
+constexpr int kAesGcmNonceLength = 12;
+constexpr int kAesGcmTagSize = 16;
+constexpr int kAesGcmKeySize = 32;
+
+template <typename T>
+class ErrMsgOr {
+ public:
+ ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {}
+ ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {}
+ ErrMsgOr(T val) : value_(std::move(val)) {}
+
+ operator bool() const { return value_.has_value(); }
+
+ T* operator->() & {
+ assert(value_);
+ return &value_.value();
+ }
+ T& operator*() & {
+ assert(value_);
+ return value_.value();
+ };
+ T&& operator*() && {
+ assert(value_);
+ return std::move(value_).value();
+ };
+
+ const std::string& message() { return errMsg_; }
+ std::string moveMessage() { return std::move(errMsg_); }
+
+ T moveValue() {
+ assert(value_);
+ return std::move(value_).value();
+ }
+
+ private:
+ std::string errMsg_;
+ std::optional<T> value_;
+};
+
+class CoseKey {
+ public:
+ CoseKey() {}
+ CoseKey(const CoseKey&) = delete;
+ CoseKey(CoseKey&&) = default;
+
+ enum Label : int {
+ KEY_TYPE = 1,
+ KEY_ID = 2,
+ ALGORITHM = 3,
+ KEY_OPS = 4,
+ CURVE = -1,
+ PUBKEY_X = -2,
+ PUBKEY_Y = -3,
+ PRIVATE_KEY = -4,
+ TEST_KEY = -70000 // Application-defined
+ };
+
+ static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
+ auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
+ if (!parsedKey) return errMsg + " when parsing key";
+ if (!parsedKey->asMap()) return "CoseKey must be a map";
+ return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
+ }
+
+ static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
+ CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
+ auto key = parse(coseKey);
+ if (!key) return key;
+
+ if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
+ !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
+ !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
+ return "Unexpected key type:";
+ }
+
+ return key;
+ }
+
+ static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
+ auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
+ if (!key) return key;
+
+ auto& pubkey = key->getMap().get(PUBKEY_X);
+ if (!pubkey || !pubkey->asBstr() ||
+ pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
+ return "Invalid Ed25519 public key";
+ }
+
+ return key;
+ }
+
+ static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
+ auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
+ if (!key) return key;
+
+ auto& pubkey = key->getMap().get(PUBKEY_X);
+ if (!pubkey || !pubkey->asBstr() ||
+ pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+ return "Invalid X25519 public key";
+ }
+
+ auto& kid = key->getMap().get(KEY_ID);
+ if (requireKid && (!kid || !kid->asBstr())) {
+ return "Missing KID";
+ }
+
+ return key;
+ }
+
+ static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
+ auto key = parse(coseKey, EC2, ES256, P256);
+ if (!key) return key;
+
+ auto& pubkey_x = key->getMap().get(PUBKEY_X);
+ auto& pubkey_y = key->getMap().get(PUBKEY_Y);
+ if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+ pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
+ return "Invalid P256 public key";
+ }
+
+ return key;
+ }
+
+ std::optional<int> getIntValue(Label label) {
+ const auto& value = key_->get(label);
+ if (!value || !value->asInt()) return {};
+ return value->asInt()->value();
+ }
+
+ std::optional<bytevec> getBstrValue(Label label) {
+ const auto& value = key_->get(label);
+ if (!value || !value->asBstr()) return {};
+ return value->asBstr()->value();
+ }
+
+ const cppbor::Map& getMap() const { return *key_; }
+ cppbor::Map&& moveMap() { return std::move(*key_); }
+
+ bool checkIntValue(Label label, int expectedValue) {
+ const auto& value = key_->get(label);
+ return value && value->asInt() && value->asInt()->value() == expectedValue;
+ }
+
+ void add(Label label, int value) { key_->add(label, value); }
+ void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
+
+ bytevec encode() { return key_->canonicalize().encode(); }
+
+ private:
+ CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
+
+ // This is the full parsed key structure.
+ std::unique_ptr<cppbor::Map> key_;
+};
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+ const bytevec& payload);
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+ const bytevec& payload);
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem);
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+ const bytevec& macKey);
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+ const bytevec& payload, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+ const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
+ const bytevec& payload, const bytevec& aad);
+/**
+ * Verify and parse a COSE_Sign1 message, returning the payload.
+ *
+ * @param ignoreSignature indicates whether signature verification should be skipped. If true, no
+ * verification of the signature will be done.
+ *
+ * @param coseSign1 is the COSE_Sign1 to verify and parse.
+ *
+ * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature. The bytevec may
+ * be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
+ * use, i.e. that coseSign1 is a self-signed "certificate".
+ */
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature,
+ const cppbor::Array* coseSign1,
+ const bytevec& signingCoseKey,
+ const bytevec& aad);
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+ const bytevec& protectedParams, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+ const bytevec& plaintextPayload, const bytevec& aad,
+ cppbor::Array recipients);
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+ const cppbor::Item* encryptItem);
+inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
+ return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
+}
+
+ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key,
+ const cppbor::Item* encryptItem,
+ const bytevec& aad);
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
+ const bytevec& recipientPubKey, bool senderIsA);
+
+ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
+ const bytevec& aad,
+ const bytevec& plaintext);
+ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
+ const bytevec& aad,
+ const bytevec& ciphertextWithTag);
+
+} // namespace cppcose
diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h
index 6d36794..ca51b08 100644
--- a/security/keymint/support/include/keymint_support/authorization_set.h
+++ b/security/keymint/support/include/keymint_support/authorization_set.h
@@ -288,6 +288,7 @@
AuthorizationSetBuilder& SigningKey();
AuthorizationSetBuilder& EncryptionKey();
+ AuthorizationSetBuilder& AttestKey();
AuthorizationSetBuilder& NoDigestOrPadding();
diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h
index c3bc60b..a0212aa 100644
--- a/security/keymint/support/include/keymint_support/openssl_utils.h
+++ b/security/keymint/support/include/keymint_support/openssl_utils.h
@@ -34,13 +34,14 @@
typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
-MAKE_OPENSSL_PTR_TYPE(EC_KEY)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
+MAKE_OPENSSL_PTR_TYPE(EC_KEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
MAKE_OPENSSL_PTR_TYPE(RSA)
MAKE_OPENSSL_PTR_TYPE(X509)
-MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+MAKE_OPENSSL_PTR_TYPE(X509_NAME)
typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
new file mode 100644
index 0000000..5e205a2
--- /dev/null
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <cppcose/cppcose.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+using bytevec = std::vector<uint8_t>;
+using namespace cppcose;
+
+extern bytevec kTestMacKey;
+
+/**
+ * Generates random bytes.
+ */
+bytevec randomBytes(size_t numBytes);
+
+struct EekChain {
+ bytevec chain;
+ bytevec last_pubkey;
+ bytevec last_privkey;
+};
+
+/**
+ * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
+ * specified length. All keys are generated randomly.
+ */
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+
+struct BccEntryData {
+ bytevec pubKey;
+};
+
+/**
+ * Validates the provided CBOR-encoded BCC, returning a vector of BccEntryData
+ * structs containing the BCC entry contents. If an entry contains no firmware
+ * digest, the corresponding BccEntryData.firmwareDigest will have length zero
+ * (there's no way to distinguish between an empty and missing firmware digest,
+ * which seems fine).
+ */
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc);
+
+} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
new file mode 100644
index 0000000..111cb30
--- /dev/null
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#include <remote_prov/remote_prov_utils.h>
+
+#include <openssl/rand.h>
+
+#include <cppbor.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
+
+bytevec randomBytes(size_t numBytes) {
+ bytevec retval(numBytes);
+ RAND_bytes(retval.data(), numBytes);
+ return retval;
+}
+
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+ auto eekChain = cppbor::Array();
+
+ bytevec prev_priv_key;
+ for (size_t i = 0; i < length - 1; ++i) {
+ bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
+ bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
+
+ ED25519_keypair(pub_key.data(), priv_key.data());
+
+ // The first signing key is self-signed.
+ if (prev_priv_key.empty()) prev_priv_key = priv_key;
+
+ auto coseSign1 = constructCoseSign1(prev_priv_key,
+ cppbor::Map() /* payload CoseKey */
+ .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+ .add(CoseKey::ALGORITHM, EDDSA)
+ .add(CoseKey::CURVE, ED25519)
+ .add(CoseKey::PUBKEY_X, pub_key)
+ .canonicalize()
+ .encode(),
+ {} /* AAD */);
+ if (!coseSign1) return coseSign1.moveMessage();
+ eekChain.add(coseSign1.moveValue());
+ }
+
+ bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
+ bytevec priv_key(X25519_PRIVATE_KEY_LEN);
+ X25519_keypair(pub_key.data(), priv_key.data());
+
+ auto coseSign1 = constructCoseSign1(prev_priv_key,
+ cppbor::Map() /* payload CoseKey */
+ .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+ .add(CoseKey::KEY_ID, eekId)
+ .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
+ .add(CoseKey::CURVE, cppcose::X25519)
+ .add(CoseKey::PUBKEY_X, pub_key)
+ .canonicalize()
+ .encode(),
+ {} /* AAD */);
+ if (!coseSign1) return coseSign1.moveMessage();
+ eekChain.add(coseSign1.moveValue());
+
+ return EekChain{eekChain.encode(), pub_key, priv_key};
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(bool ignoreSignature, const cppbor::Array* coseSign1,
+ const bytevec& signingCoseKey, const bytevec& aad) {
+ if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+ return "Invalid COSE_Sign1";
+ }
+
+ const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+ const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+ const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+ const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+ if (!protectedParams || !unprotectedParams || !payload || !signature) {
+ return "Invalid COSE_Sign1";
+ }
+
+ auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+ if (!parsedProtParams) {
+ return errMsg + " when parsing protected params.";
+ }
+ if (!parsedProtParams->asMap()) {
+ return "Protected params must be a map";
+ }
+
+ auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+ if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+ return "Unsupported signature algorithm";
+ }
+
+ // TODO(jbires): Handle CWTs as the CoseSign1 payload in a less hacky way. Since the CWT payload
+ // is extremely remote provisioning specific, probably just make a separate
+ // function there.
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload);
+ if (!parsedPayload) return payloadErrMsg + " when parsing key";
+ if (!parsedPayload->asMap()) return "CWT must be a map";
+ auto serializedKey = parsedPayload->asMap()->get(-4670552)->clone();
+ if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry";
+
+ if (!ignoreSignature) {
+ bool selfSigned = signingCoseKey.empty();
+ auto key = CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value()
+ : signingCoseKey);
+ if (!key) return "Bad signing key: " + key.moveMessage();
+
+ bytevec signatureInput = cppbor::Array()
+ .add("Signature1")
+ .add(*protectedParams)
+ .add(aad)
+ .add(*payload)
+ .encode();
+
+ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+ key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+ return "Signature verification failed";
+ }
+ }
+
+ return serializedKey->asBstr()->value();
+}
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
+ if (!bcc || bcc->size() == 0) return "Invalid BCC";
+
+ std::vector<BccEntryData> result;
+
+ bytevec prevKey;
+ // TODO(jbires): Actually process the pubKey at the start of the new bcc entry
+ for (size_t i = 1; i < bcc->size(); ++i) {
+ const cppbor::Array* entry = bcc->get(i)->asArray();
+ if (!entry || entry->size() != kCoseSign1EntryCount) {
+ return "Invalid BCC entry " + std::to_string(i) + ": " + prettyPrint(entry);
+ }
+ auto payload = verifyAndParseCoseSign1Cwt(false /* ignoreSignature */, entry,
+ std::move(prevKey), bytevec{} /* AAD */);
+ if (!payload) {
+ return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage();
+ }
+
+ auto& certProtParms = entry->get(kCoseSign1ProtectedParams);
+ if (!certProtParms || !certProtParms->asBstr()) return "Invalid prot params";
+ auto [parsedProtParms, _, errMsg] = cppbor::parse(certProtParms->asBstr()->value());
+ if (!parsedProtParms || !parsedProtParms->asMap()) return "Invalid prot params";
+
+ result.push_back(BccEntryData{*payload});
+
+ // This entry's public key is the signing key for the next entry.
+ prevKey = payload.moveValue();
+ }
+
+ return result;
+}
+
+} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/ISecureClock.aidl b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/ISecureClock.aidl
index c16b312..3778897 100644
--- a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/ISecureClock.aidl
+++ b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/ISecureClock.aidl
@@ -1,4 +1,17 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
@@ -20,5 +33,5 @@
@VintfStability
interface ISecureClock {
android.hardware.security.secureclock.TimeStampToken generateTimeStamp(in long challenge);
- const String TIME_STAMP_MAC_LABEL = "Time Verification";
+ const String TIME_STAMP_MAC_LABEL = "Auth Verification";
}
diff --git a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/TimeStampToken.aidl b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/TimeStampToken.aidl
index 21eeb74..00a8bb2 100644
--- a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/TimeStampToken.aidl
+++ b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/TimeStampToken.aidl
@@ -1,4 +1,18 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/Timestamp.aidl b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/Timestamp.aidl
index f01fdc7..bebeb5c 100644
--- a/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/Timestamp.aidl
+++ b/security/secureclock/aidl/aidl_api/android.hardware.security.secureclock/current/android/hardware/security/secureclock/Timestamp.aidl
@@ -1,4 +1,18 @@
-///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/security/secureclock/aidl/android/hardware/security/secureclock/ISecureClock.aidl b/security/secureclock/aidl/android/hardware/security/secureclock/ISecureClock.aidl
index 7d416dd..577dd8f 100644
--- a/security/secureclock/aidl/android/hardware/security/secureclock/ISecureClock.aidl
+++ b/security/secureclock/aidl/android/hardware/security/secureclock/ISecureClock.aidl
@@ -33,7 +33,7 @@
* String used as context in the HMAC computation signing the generated time stamp.
* See TimeStampToken.mac for details.
*/
- const String TIME_STAMP_MAC_LABEL = "Time Verification";
+ const String TIME_STAMP_MAC_LABEL = "Auth Verification";
/**
* Generates an authenticated timestamp.
diff --git a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
index 3fb5860..dd95732 100644
--- a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
+++ b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
@@ -39,18 +39,20 @@
* 32-byte HMAC-SHA256 of the above values, computed as:
*
* HMAC(H,
- * ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp)
+ * ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp || securityLevel )
*
* where:
*
* ``ISecureClock.TIME_STAMP_MAC_LABEL'' is a sting constant defined in ISecureClock.aidl.
*
- * ``H'' is the shared HMAC key (see computeSharedHmac() in ISharedHmacSecret).
+ * ``H'' is the shared HMAC key (see computeSharedHmac() in ISharedSecret).
*
* ``||'' represents concatenation
*
* The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
- * order. securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+ * order. SecurityLevel is represented as a 32-bit unsigned integer in big-endian order as
+ * described in android.hardware.security.keymint.SecurityLevel. It represents the security
+ * level of the secure clock environment.
*/
byte[] mac;
}
diff --git a/security/secureclock/aidl/vts/functional/Android.bp b/security/secureclock/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..30244eb
--- /dev/null
+++ b/security/secureclock/aidl/vts/functional/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsAidlSecureClockTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ srcs: [
+ "SecureClockAidlTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ "libkeymint",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.hardware.security.secureclock-unstable-ndk_platform",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/security/secureclock/aidl/vts/functional/AndroidTest.xml b/security/secureclock/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..4861c7c
--- /dev/null
+++ b/security/secureclock/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs VtsAidlSecureClockTargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="VtsAidlSecureClockTargetTest->/data/local/tmp/VtsAidlSecureClockTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsAidlSecureClockTargetTest" />
+ <option name="native-test-timeout" value="900000"/>
+ </test>
+</configuration>
diff --git a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
new file mode 100644
index 0000000..9ca1ee8
--- /dev/null
+++ b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "secureclock_test"
+#include <android-base/logging.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+#include <android/binder_manager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+namespace aidl::android::hardware::security::secureclock::test {
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::hardware::security::keymint::ErrorCode;
+using ::std::shared_ptr;
+using ::std::string;
+using ::std::vector;
+
+class SecureClockAidlTest : public ::testing::TestWithParam<string> {
+ public:
+ struct TimestampTokenResult {
+ ErrorCode error;
+ TimeStampToken token;
+ };
+
+ TimestampTokenResult getTimestampToken(int64_t in_challenge) {
+ TimestampTokenResult result;
+ result.error =
+ GetReturnErrorCode(secureClock_->generateTimeStamp(in_challenge, &result.token));
+ return result;
+ }
+
+ uint64_t getTime() {
+ struct timespec timespec;
+ EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, ×pec));
+ return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+ }
+
+ int sleep_ms(uint32_t milliseconds) {
+ struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000),
+ static_cast<long>(milliseconds % 1000) * 1000000};
+ while (sleep_time.tv_sec || sleep_time.tv_nsec) {
+ if (nanosleep(&sleep_time /* to wait */,
+ &sleep_time /* remaining (on interrruption) */) == 0) {
+ sleep_time = {};
+ } else {
+ if (errno != EINTR) return errno;
+ }
+ }
+ return 0;
+ }
+
+ ErrorCode GetReturnErrorCode(const Status& result) {
+ if (result.isOk()) return ErrorCode::OK;
+
+ if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return static_cast<ErrorCode>(result.getServiceSpecificError());
+ }
+
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+
+ void InitializeSecureClock(std::shared_ptr<ISecureClock> secureClock) {
+ ASSERT_NE(secureClock, nullptr);
+ secureClock_ = secureClock;
+ }
+
+ ISecureClock& secureClock() { return *secureClock_; }
+
+ static vector<string> build_params() {
+ auto params = ::android::getAidlHalInstanceNames(ISecureClock::descriptor);
+ return params;
+ }
+
+ void SetUp() override {
+ if (AServiceManager_isDeclared(GetParam().c_str())) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+ InitializeSecureClock(ISecureClock::fromBinder(binder));
+ } else {
+ InitializeSecureClock(nullptr);
+ }
+ }
+
+ void TearDown() override {}
+
+ private:
+ std::shared_ptr<ISecureClock> secureClock_;
+};
+
+/*
+ * The precise capabilities required to generate TimeStampToken will vary depending on the specific
+ * vendor implementations. The only thing we really can test is that tokens can be created by
+ * secureclock services, and that the timestamps increase as expected.
+ */
+TEST_P(SecureClockAidlTest, TestCreation) {
+ auto result1 = getTimestampToken(1 /* challenge */);
+ auto result1_time = getTime();
+ EXPECT_EQ(ErrorCode::OK, result1.error);
+ EXPECT_EQ(1U, result1.token.challenge);
+ EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+ unsigned long time_to_sleep = 200;
+ sleep_ms(time_to_sleep);
+
+ auto result2 = getTimestampToken(2 /* challenge */);
+ auto result2_time = getTime();
+ EXPECT_EQ(ErrorCode::OK, result2.error);
+ EXPECT_EQ(2U, result2.token.challenge);
+ EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+
+ auto host_time_delta = result2_time - result1_time;
+
+ EXPECT_GE(host_time_delta, time_to_sleep)
+ << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+ EXPECT_LE(host_time_delta, time_to_sleep + 100)
+ << "The getTimestampToken call took " << (host_time_delta - time_to_sleep)
+ << " ms? That's awful!";
+ EXPECT_GE(result2.token.timestamp.milliSeconds, result1.token.timestamp.milliSeconds);
+ unsigned long km_time_delta =
+ result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+ // 20 ms of slop just to avoid test flakiness.
+ EXPECT_LE(host_time_delta, km_time_delta + 20);
+ EXPECT_LE(km_time_delta, host_time_delta + 20);
+ ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+ ASSERT_NE(0,
+ memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+/*
+ * Test that the mac changes when the time stamp changes. This is does not guarantee that the time
+ * stamp is included in the mac but on failure we know that it is not. Other than in the test
+ * case above we call getTimestampToken with the exact same set of parameters.
+ */
+TEST_P(SecureClockAidlTest, MacChangesOnChangingTimestamp) {
+ auto result1 = getTimestampToken(0 /* challenge */);
+ auto result1_time = getTime();
+ EXPECT_EQ(ErrorCode::OK, result1.error);
+ EXPECT_EQ(0U, result1.token.challenge);
+ EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+ unsigned long time_to_sleep = 200;
+ sleep_ms(time_to_sleep);
+
+ auto result2 = getTimestampToken(1 /* challenge */);
+ auto result2_time = getTime();
+ EXPECT_EQ(ErrorCode::OK, result2.error);
+ EXPECT_EQ(1U, result2.token.challenge);
+ EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+
+ auto host_time_delta = result2_time - result1_time;
+
+ EXPECT_GE(host_time_delta, time_to_sleep)
+ << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+ EXPECT_LE(host_time_delta, time_to_sleep + 100)
+ << "The getTimestampToken call took " << (host_time_delta - time_to_sleep)
+ << " ms? That's awful!";
+
+ EXPECT_GE(result2.token.timestamp.milliSeconds, result1.token.timestamp.milliSeconds);
+ unsigned long km_time_delta =
+ result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+
+ EXPECT_LE(host_time_delta, km_time_delta + 20);
+ EXPECT_LE(km_time_delta, host_time_delta + 20);
+ ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+ ASSERT_NE(0,
+ memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SecureClockAidlTest,
+ testing::ValuesIn(SecureClockAidlTest::build_params()),
+ ::android::PrintInstanceNameToString);
+} // namespace aidl::android::hardware::security::secureclock::test
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/security/sharedsecret/aidl/vts/functional/Android.bp b/security/sharedsecret/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..56ab317
--- /dev/null
+++ b/security/sharedsecret/aidl/vts/functional/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsAidlSharedSecretTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "SharedSecretAidlTest.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ "libkeymint",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.hardware.security.sharedsecret-unstable-ndk_platform",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/security/sharedsecret/aidl/vts/functional/AndroidTest.xml b/security/sharedsecret/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..c6697bc
--- /dev/null
+++ b/security/sharedsecret/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs VtsAidlSharedSecretTargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="VtsAidlSharedSecretTargetTest->/data/local/tmp/VtsAidlSharedSecretTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsAidlSharedSecretTargetTest" />
+ <option name="native-test-timeout" value="900000"/>
+ </test>
+</configuration>
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
new file mode 100644
index 0000000..83f6ef3
--- /dev/null
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "sharedsecret_test"
+#include <android-base/logging.h>
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/sharedsecret/ISharedSecret.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+namespace aidl::android::hardware::security::sharedsecret::test {
+using ::aidl::android::hardware::security::keymint::ErrorCode;
+using ::std::shared_ptr;
+using ::std::vector;
+using Status = ::ndk::ScopedAStatus;
+
+class SharedSecretAidlTest : public ::testing::Test {
+ public:
+ struct GetParamsResult {
+ ErrorCode error;
+ SharedSecretParameters params;
+ auto tie() { return std::tie(error, params); }
+ };
+
+ struct ComputeResult {
+ ErrorCode error;
+ vector<uint8_t> sharing_check;
+ auto tie() { return std::tie(error, sharing_check); }
+ };
+
+ GetParamsResult getSharedSecretParameters(shared_ptr<ISharedSecret>& sharedSecret) {
+ SharedSecretParameters params;
+ auto error = GetReturnErrorCode(sharedSecret->getSharedSecretParameters(¶ms));
+ EXPECT_EQ(ErrorCode::OK, error);
+ GetParamsResult result;
+ result.tie() = std::tie(error, params);
+ return result;
+ }
+
+ vector<SharedSecretParameters> getAllSharedSecretParameters() {
+ vector<SharedSecretParameters> paramsVec;
+ for (auto& sharedSecret : allSharedSecrets_) {
+ auto result = getSharedSecretParameters(sharedSecret);
+ EXPECT_EQ(ErrorCode::OK, result.error);
+ if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
+ }
+ return paramsVec;
+ }
+
+ ComputeResult computeSharedSecret(shared_ptr<ISharedSecret>& sharedSecret,
+ const vector<SharedSecretParameters>& params) {
+ std::vector<uint8_t> sharingCheck;
+ auto error = GetReturnErrorCode(sharedSecret->computeSharedSecret(params, &sharingCheck));
+ ComputeResult result;
+ result.tie() = std::tie(error, sharingCheck);
+ return result;
+ }
+
+ vector<ComputeResult> computeAllSharedSecrets(const vector<SharedSecretParameters>& params) {
+ vector<ComputeResult> result;
+ for (auto& sharedSecret : allSharedSecrets_) {
+ result.push_back(computeSharedSecret(sharedSecret, params));
+ }
+ return result;
+ }
+
+ vector<vector<uint8_t>> copyNonces(const vector<SharedSecretParameters>& paramsVec) {
+ vector<vector<uint8_t>> nonces;
+ for (auto& param : paramsVec) {
+ nonces.push_back(param.nonce);
+ }
+ return nonces;
+ }
+
+ void verifyResponses(const vector<uint8_t>& expected, const vector<ComputeResult>& responses) {
+ for (auto& response : responses) {
+ EXPECT_EQ(ErrorCode::OK, response.error);
+ EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
+ }
+ }
+
+ ErrorCode GetReturnErrorCode(const Status& result) {
+ if (result.isOk()) return ErrorCode::OK;
+ if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return static_cast<ErrorCode>(result.getServiceSpecificError());
+ }
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+
+ static shared_ptr<ISharedSecret> getSharedSecretService(const char* name) {
+ if (AServiceManager_isDeclared(name)) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(name));
+ return ISharedSecret::fromBinder(binder);
+ }
+ return nullptr;
+ }
+
+ const vector<shared_ptr<ISharedSecret>>& allSharedSecrets() { return allSharedSecrets_; }
+
+ static void SetUpTestCase() {
+ if (allSharedSecrets_.empty()) {
+ auto names = ::android::getAidlHalInstanceNames(ISharedSecret::descriptor);
+ for (const auto& name : names) {
+ auto servicePtr = getSharedSecretService(name.c_str());
+ if (servicePtr != nullptr) allSharedSecrets_.push_back(std::move(servicePtr));
+ }
+ }
+ }
+ static void TearDownTestCase() {}
+ void SetUp() override {}
+ void TearDown() override {}
+
+ private:
+ static vector<shared_ptr<ISharedSecret>> allSharedSecrets_;
+};
+
+vector<shared_ptr<ISharedSecret>> SharedSecretAidlTest::allSharedSecrets_;
+
+TEST_F(SharedSecretAidlTest, GetParameters) {
+ auto sharedSecrets = allSharedSecrets();
+ for (auto sharedSecret : sharedSecrets) {
+ auto result1 = getSharedSecretParameters(sharedSecret);
+ EXPECT_EQ(ErrorCode::OK, result1.error);
+ auto result2 = getSharedSecretParameters(sharedSecret);
+ EXPECT_EQ(ErrorCode::OK, result2.error);
+ ASSERT_EQ(result1.params.seed, result2.params.seed)
+ << "A given shared secret service should always return the same seed.";
+ ASSERT_EQ(result1.params.nonce, result2.params.nonce)
+ << "A given shared secret service should always return the same nonce until "
+ "restart.";
+ }
+}
+
+TEST_F(SharedSecretAidlTest, ComputeSharedSecret) {
+ auto params = getAllSharedSecretParameters();
+ ASSERT_EQ(allSharedSecrets().size(), params.size())
+ << "One or more shared secret services failed to provide parameters.";
+ auto nonces = copyNonces(params);
+ EXPECT_EQ(allSharedSecrets().size(), nonces.size());
+ std::sort(nonces.begin(), nonces.end());
+ std::unique(nonces.begin(), nonces.end());
+ EXPECT_EQ(allSharedSecrets().size(), nonces.size());
+
+ auto responses = computeAllSharedSecrets(params);
+ ASSERT_GT(responses.size(), 0U);
+ verifyResponses(responses[0].sharing_check, responses);
+
+ // Do it a second time. Should get the same answers.
+ params = getAllSharedSecretParameters();
+ ASSERT_EQ(allSharedSecrets().size(), params.size())
+ << "One or more shared secret services failed to provide parameters.";
+
+ responses = computeAllSharedSecrets(params);
+ ASSERT_GT(responses.size(), 0U);
+ ASSERT_EQ(32U, responses[0].sharing_check.size());
+ verifyResponses(responses[0].sharing_check, responses);
+}
+
+template <class F>
+class final_action {
+ public:
+ explicit final_action(F f) : f_(std::move(f)) {}
+ ~final_action() { f_(); }
+
+ private:
+ F f_;
+};
+
+template <class F>
+inline final_action<F> finally(const F& f) {
+ return final_action<F>(f);
+}
+
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptNonce) {
+ auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+
+ auto params = getAllSharedSecretParameters();
+ ASSERT_EQ(allSharedSecrets().size(), params.size())
+ << "One or more shared secret services failed to provide parameters.";
+
+ // All should be well in the normal case
+ auto responses = computeAllSharedSecrets(params);
+
+ ASSERT_GT(responses.size(), 0U);
+ vector<uint8_t> correct_response = responses[0].sharing_check;
+ verifyResponses(correct_response, responses);
+
+ // Pick a random param, a random byte within the param's nonce, and a random bit within
+ // the byte. Flip that bit.
+ size_t param_to_tweak = rand() % params.size();
+ uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
+ uint8_t bit_to_tweak = rand() % 8;
+ params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
+
+ responses = computeAllSharedSecrets(params);
+ for (size_t i = 0; i < responses.size(); ++i) {
+ if (i == param_to_tweak) {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+ << "Shared secret service that provided tweaked param should fail to compute "
+ "shared secret";
+ } else {
+ EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different shared secret, due to the tweaked "
+ "nonce.";
+ }
+ }
+}
+
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
+ auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+ auto params = getAllSharedSecretParameters();
+ ASSERT_EQ(allSharedSecrets().size(), params.size())
+ << "One or more shared secret service failed to provide parameters.";
+
+ // All should be well in the normal case
+ auto responses = computeAllSharedSecrets(params);
+
+ ASSERT_GT(responses.size(), 0U);
+ vector<uint8_t> correct_response = responses[0].sharing_check;
+ verifyResponses(correct_response, responses);
+
+ // Pick a random param and modify the seed. We just increase the seed length by 1. It doesn't
+ // matter what value is in the additional byte; it changes the seed regardless.
+ auto param_to_tweak = rand() % params.size();
+ auto& to_tweak = params[param_to_tweak].seed;
+ ASSERT_TRUE(to_tweak.size() == 32 || to_tweak.size() == 0);
+ if (!to_tweak.size()) {
+ to_tweak.resize(32); // Contents don't matter; a little randomization is nice.
+ }
+ to_tweak[0]++;
+
+ responses = computeAllSharedSecrets(params);
+ for (size_t i = 0; i < responses.size(); ++i) {
+ if (i == param_to_tweak) {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+ << "Shared secret service that provided tweaked param should fail to compute "
+ "shared secret";
+ } else {
+ EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different shared secret, due to the tweaked "
+ "nonce.";
+ }
+ }
+}
+} // namespace aidl::android::hardware::security::sharedsecret::test
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}