Merge "health: stop spamming."
diff --git a/audio/7.0/config/update_audio_policy_config.sh b/audio/7.0/config/update_audio_policy_config.sh
index 159fa35..c475dd1 100755
--- a/audio/7.0/config/update_audio_policy_config.sh
+++ b/audio/7.0/config/update_audio_policy_config.sh
@@ -41,7 +41,7 @@
set -euo pipefail
-if (echo "$@" | grep -qe -h); then
+if (echo "$@" | grep -qe "^-h"); then
echo "This script will update Audio Policy Manager config file"
echo "to the format required by V7.0 XSD schema from a previous"
echo "version."
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index bbc14ad..898c22d 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "audiohalservice"
+#include <signal.h>
#include <string>
#include <vector>
@@ -45,6 +46,8 @@
}
int main(int /* argc */, char* /* argv */ []) {
+ signal(SIGPIPE, SIG_IGN);
+
::android::ProcessState::initWithDriver("/dev/vndbinder");
// start a threadpool for vndbinder interactions
::android::ProcessState::self()->startThreadPool();
diff --git a/audio/common/all-versions/test/utility/Android.bp b/audio/common/all-versions/test/utility/Android.bp
index 1602d25..757f8a8 100644
--- a/audio/common/all-versions/test/utility/Android.bp
+++ b/audio/common/all-versions/test/utility/Android.bp
@@ -25,7 +25,7 @@
cc_library_static {
name: "android.hardware.audio.common.test.utility",
- defaults : ["hidl_defaults"],
+ defaults: ["hidl_defaults"],
srcs: ["src/ValidateXml.cpp"],
cflags: [
"-O0",
@@ -34,7 +34,34 @@
],
local_include_dirs: ["include/utility"],
export_include_dirs: ["include"],
- shared_libs: ["libxml2", "liblog"],
+ shared_libs: [
+ "libxml2",
+ "liblog",
+ ],
static_libs: ["libgtest"],
export_static_lib_headers: ["libgtest"],
}
+
+// Note: this isn't a VTS test, but rather a unit test
+// to verify correctness of test utilities.
+cc_test {
+ name: "android.hardware.audio.common.test.utility_tests",
+ host_supported: true,
+ local_include_dirs: ["include/utility"],
+ srcs: [
+ "src/ValidateXml.cpp",
+ "tests/utility_tests.cpp",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-g",
+ ],
+ shared_libs: [
+ "libbase",
+ "libxml2",
+ "liblog",
+ ],
+ static_libs: ["libgtest"],
+ test_suites: ["general-tests"],
+}
diff --git a/audio/common/all-versions/test/utility/TEST_MAPPING b/audio/common/all-versions/test/utility/TEST_MAPPING
new file mode 100644
index 0000000..0bc1871
--- /dev/null
+++ b/audio/common/all-versions/test/utility/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "android.hardware.audio.common.test.utility_tests"
+ }
+ ]
+}
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
index a866104..f111c01 100644
--- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -112,7 +112,8 @@
return ::testing::AssertionFailure() << "Failed to parse xml\n" << context();
}
- if (xmlXIncludeProcess(doc.get()) == -1) {
+ // Process 'include' directives w/o modifying elements loaded from included files.
+ if (xmlXIncludeProcessFlags(doc.get(), XML_PARSE_NOBASEFIX) == -1) {
return ::testing::AssertionFailure() << "Failed to resolve xincludes in xml\n" << context();
}
diff --git a/audio/common/all-versions/test/utility/tests/utility_tests.cpp b/audio/common/all-versions/test/utility/tests/utility_tests.cpp
new file mode 100644
index 0000000..c523066
--- /dev/null
+++ b/audio/common/all-versions/test/utility/tests/utility_tests.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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 <android-base/file.h>
+#include <gtest/gtest.h>
+
+#include <ValidateXml.h>
+
+using ::android::hardware::audio::common::test::utility::validateXml;
+
+const char* XSD_SOURCE =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<xs:schema version=\"2.0\""
+ " elementFormDefault=\"qualified\""
+ " attributeFormDefault=\"unqualified\""
+ " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
+ " <xs:element name=\"audioPolicyConfiguration\">"
+ " <xs:complexType>"
+ " <xs:sequence>"
+ " <xs:element name=\"modules\">"
+ " <xs:complexType>"
+ " <xs:sequence>"
+ " <xs:element name=\"module\" maxOccurs=\"unbounded\">"
+ " <xs:complexType>"
+ " <xs:attribute name=\"name\" type=\"xs:string\" use=\"required\"/>"
+ " </xs:complexType>"
+ " </xs:element>"
+ " </xs:sequence>"
+ " </xs:complexType>"
+ " </xs:element>"
+ " </xs:sequence>"
+ " </xs:complexType>"
+ " </xs:element>"
+ "</xs:schema>";
+
+const char* INVALID_XML_SOURCE =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+ "<audioPolicyKonfiguration />";
+
+const char* VALID_XML_SOURCE =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+ "<audioPolicyConfiguration>"
+ " <modules>"
+ " <module name=\"aaa\" />"
+ " %s"
+ " </modules>"
+ "</audioPolicyConfiguration>";
+
+const char* MODULE_SOURCE = "<module name=\"bbb\" />";
+
+const char* XI_INCLUDE = "<xi:include xmlns:xi=\"http://www.w3.org/2001/XInclude\" href=\"%s\" />";
+
+const char* XML_INCLUDED_SOURCE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>%s";
+
+namespace {
+
+std::string substitute(const char* fmt, const char* param) {
+ std::string buffer(static_cast<size_t>(strlen(fmt) + strlen(param)), '\0');
+ snprintf(buffer.data(), buffer.size(), fmt, param);
+ return buffer;
+}
+
+std::string substitute(const char* fmt, const std::string& s) {
+ return substitute(fmt, s.c_str());
+}
+
+} // namespace
+
+TEST(ValidateXml, InvalidXml) {
+ TemporaryFile xml;
+ ASSERT_TRUE(android::base::WriteStringToFile(INVALID_XML_SOURCE, xml.path)) << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_FALSE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
+
+TEST(ValidateXml, ValidXml) {
+ TemporaryFile xml;
+ ASSERT_TRUE(
+ android::base::WriteStringToFile(substitute(VALID_XML_SOURCE, MODULE_SOURCE), xml.path))
+ << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
+
+TEST(ValidateXml, IncludeAbsolutePath) {
+ TemporaryFile xmlInclude;
+ ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
+ xmlInclude.path))
+ << strerror(errno);
+ TemporaryFile xml;
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ substitute(VALID_XML_SOURCE, substitute(XI_INCLUDE, xmlInclude.path)), xml.path))
+ << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
+
+TEST(ValidateXml, IncludeSameDirRelativePath) {
+ TemporaryFile xmlInclude;
+ ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
+ xmlInclude.path))
+ << strerror(errno);
+ TemporaryFile xml;
+ ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ substitute(VALID_XML_SOURCE,
+ substitute(XI_INCLUDE, android::base::Basename(xmlInclude.path))),
+ xml.path))
+ << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
+
+TEST(ValidateXml, IncludeSubdirRelativePath) {
+ TemporaryDir xmlIncludeDir;
+ TemporaryFile xmlInclude(xmlIncludeDir.path);
+ ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
+ xmlInclude.path))
+ << strerror(errno);
+ TemporaryFile xml;
+ ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ substitute(VALID_XML_SOURCE,
+ substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
+ android::base::Basename(xmlInclude.path))),
+ xml.path))
+ << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
+
+TEST(ValidateXml, IncludeParentDirRelativePath) {
+ // An XML file from a subdirectory includes a file from the parent directory using '..' syntax.
+ TemporaryFile xmlInclude;
+ ASSERT_TRUE(android::base::WriteStringToFile(substitute(XML_INCLUDED_SOURCE, MODULE_SOURCE),
+ xmlInclude.path))
+ << strerror(errno);
+ TemporaryDir xmlIncludeDir;
+ TemporaryFile xmlParentInclude(xmlIncludeDir.path);
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ substitute(XML_INCLUDED_SOURCE,
+ substitute(XI_INCLUDE, "../" + android::base::Basename(xmlInclude.path))),
+ xmlParentInclude.path))
+ << strerror(errno);
+ TemporaryFile xml;
+ ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlInclude.path));
+ ASSERT_EQ(android::base::Dirname(xml.path), android::base::Dirname(xmlIncludeDir.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ substitute(
+ VALID_XML_SOURCE,
+ substitute(XI_INCLUDE, android::base::Basename(xmlIncludeDir.path) + "/" +
+ android::base::Basename(xmlParentInclude.path))),
+ xml.path))
+ << strerror(errno);
+ TemporaryFile xsd;
+ ASSERT_TRUE(android::base::WriteStringToFile(XSD_SOURCE, xsd.path)) << strerror(errno);
+ EXPECT_TRUE(validateXml("xml", "xsd", xml.path, xsd.path));
+}
diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp
index 599f3c3..17621a9 100644
--- a/audio/core/all-versions/default/StreamIn.cpp
+++ b/audio/core/all-versions/default/StreamIn.cpp
@@ -412,9 +412,9 @@
}
// Create and launch the thread.
- auto tempReadThread =
- std::make_unique<ReadThread>(&mStopReadThread, mStream, tempCommandMQ.get(),
- tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+ sp<ReadThread> tempReadThread =
+ new ReadThread(&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
+ tempStatusMQ.get(), tempElfGroup.get());
if (!tempReadThread->init()) {
ALOGW("failed to start reader thread: %s", strerror(-status));
sendError(Result::INVALID_ARGUMENTS);
@@ -430,7 +430,7 @@
mCommandMQ = std::move(tempCommandMQ);
mDataMQ = std::move(tempDataMQ);
mStatusMQ = std::move(tempStatusMQ);
- mReadThread = tempReadThread.release();
+ mReadThread = tempReadThread;
mEfGroup = tempElfGroup.release();
#if MAJOR_VERSION <= 6
threadInfo.pid = getpid();
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 4fe6601..c23922d 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -398,9 +398,9 @@
}
// Create and launch the thread.
- auto tempWriteThread =
- std::make_unique<WriteThread>(&mStopWriteThread, mStream, tempCommandMQ.get(),
- tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+ sp<WriteThread> tempWriteThread =
+ new WriteThread(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
+ tempStatusMQ.get(), tempElfGroup.get());
if (!tempWriteThread->init()) {
ALOGW("failed to start writer thread: %s", strerror(-status));
sendError(Result::INVALID_ARGUMENTS);
@@ -416,7 +416,7 @@
mCommandMQ = std::move(tempCommandMQ);
mDataMQ = std::move(tempDataMQ);
mStatusMQ = std::move(tempStatusMQ);
- mWriteThread = tempWriteThread.release();
+ mWriteThread = tempWriteThread;
mEfGroup = tempElfGroup.release();
#if MAJOR_VERSION <= 6
threadInfo.pid = getpid();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
index 548285a..9be9ea7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
@@ -31,6 +31,14 @@
GeneratorHub::GeneratorHub(const OnHalEvent& onHalEvent)
: mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {}
+GeneratorHub::~GeneratorHub() {
+ mShuttingDownFlag.store(true);
+ mCond.notify_all();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
void GeneratorHub::registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator) {
{
std::lock_guard<std::mutex> g(mLock);
@@ -58,15 +66,18 @@
}
void GeneratorHub::run() {
- while (true) {
+ while (!mShuttingDownFlag.load()) {
std::unique_lock<std::mutex> g(mLock);
// Pop events whose generator does not exist (may be already unregistered)
while (!mEventQueue.empty()
&& mGenerators.find(mEventQueue.top().cookie) == mGenerators.end()) {
mEventQueue.pop();
}
- // Wait until event queue is not empty
- mCond.wait(g, [this] { return !mEventQueue.empty(); });
+ // Wait until event queue is not empty or shutting down flag is set
+ mCond.wait(g, [this] { return !mEventQueue.empty() || mShuttingDownFlag.load(); });
+ if (mShuttingDownFlag.load()) {
+ break;
+ }
const VhalEvent& curEvent = mEventQueue.top();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
index dcf6a4f..b25dbf1 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
@@ -58,7 +58,7 @@
public:
GeneratorHub(const OnHalEvent& onHalEvent);
- ~GeneratorHub() = default;
+ ~GeneratorHub();
/**
* Register a new generator. The generator will be discarded if it could not produce next event.
@@ -84,6 +84,7 @@
mutable std::mutex mLock;
std::condition_variable mCond;
std::thread mThread;
+ std::atomic<bool> mShuttingDownFlag{false};
};
} // namespace impl
diff --git a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
index 6c7362f..3fb827d 100644
--- a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
+++ b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
@@ -5,6 +5,6 @@
class late_start
user system
group system
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
capabilities SYS_NICE
rlimit rtprio 10 10
diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
index 1667677..e7e8d30 100644
--- a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
+++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
@@ -5,4 +5,4 @@
class late_start
user system
group system input uhid
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index 70a42b7..ee368fd 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -22,7 +22,7 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_library_shared {
+cc_library {
name: "android.hardware.bluetooth@1.0-impl",
defaults: ["hidl_defaults"],
vendor: true,
diff --git a/bluetooth/audio/2.1/default/Android.bp b/bluetooth/audio/2.1/default/Android.bp
index 5c30f79..3000223 100644
--- a/bluetooth/audio/2.1/default/Android.bp
+++ b/bluetooth/audio/2.1/default/Android.bp
@@ -19,6 +19,7 @@
"A2dpSoftwareAudioProvider.cpp",
"HearingAidAudioProvider.cpp",
"LeAudioAudioProvider.cpp",
+ "LeAudioOffloadAudioProvider.cpp",
],
header_libs: ["libhardware_headers"],
shared_libs: [
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
index e1b1ac6..b0d171a 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
@@ -41,8 +41,12 @@
BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
LeAudioOutputAudioProvider
BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
+LeAudioOffloadOutputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_offload_output_provider_instance_;
LeAudioInputAudioProvider
BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
+LeAudioOffloadInputAudioProvider
+ BluetoothAudioProvidersFactory::leaudio_offload_input_provider_instance_;
Return<void> BluetoothAudioProvidersFactory::openProvider(
const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
@@ -90,9 +94,15 @@
case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
provider = &leaudio_output_provider_instance_;
break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+ provider = &leaudio_offload_output_provider_instance_;
+ break;
case SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
provider = &leaudio_input_provider_instance_;
break;
+ case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+ provider = &leaudio_offload_input_provider_instance_;
+ break;
default:
status = BluetoothAudioStatus::FAILURE;
}
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
index fd83694..f8f557e 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
@@ -23,6 +23,7 @@
#include "BluetoothAudioProvider.h"
#include "HearingAidAudioProvider.h"
#include "LeAudioAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
namespace android {
namespace hardware {
@@ -55,6 +56,8 @@
static HearingAidAudioProvider hearing_aid_provider_instance_;
static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
static LeAudioInputAudioProvider leaudio_input_provider_instance_;
+ static LeAudioOffloadOutputAudioProvider leaudio_offload_output_provider_instance_;
+ static LeAudioOffloadInputAudioProvider leaudio_offload_input_provider_instance_;
};
extern "C" IBluetoothAudioProvidersFactory*
diff --git a/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..c11bdad
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 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 "BTAudioProviderLeAudioOffload"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_1;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+ : LeAudioOffloadAudioProvider() {
+ session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+ : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+ LOG(ERROR) << __func__ << ", invalid session type for Offloaded Le Audio provider: "
+ << toString(sessionType);
+
+ return false;
+}
+
+bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
+ return (sessionType == session_type_);
+}
+
+Return<void> LeAudioOffloadAudioProvider::startSession_2_1(
+ const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+ /**
+ * Initialize the audio platform if audioConfiguration is supported.
+ * Save the IBluetoothAudioPort interface, so that it can be used
+ * later to send stream control commands to the HAL client, based on
+ * interaction with Audio framework.
+ */
+ if (audioConfig.getDiscriminator() !=
+ AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
+ LOG(WARNING) << __func__
+ << " - Invalid Audio Configuration=" << toString(audioConfig);
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ if (!android::bluetooth::audio::IsOffloadLeAudioConfigurationValid(session_type_,
+ audioConfig.leAudioCodecConfig())) {
+ LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+ << toString(audioConfig.leAudioCodecConfig());
+ _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+ DataMQ::Descriptor());
+ return Void();
+ }
+
+ return BluetoothAudioProvider::startSession_2_1(hostIf, audioConfig,
+ _hidl_cb);
+}
+
+Return<void> LeAudioOffloadAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+ BluetoothAudioSessionReport_2_1::OnSessionStarted(session_type_, stack_iface_,
+ nullptr, audio_config_);
+ _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..564e9a3
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+ LeAudioOffloadAudioProvider();
+
+ bool isValid(const SessionType& sessionType) override;
+ bool isValid(const V2_0::SessionType& sessionType) override;
+
+ Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+ const AudioConfiguration& audioConfig,
+ startSession_cb _hidl_cb) override;
+
+ private:
+ Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+ LeAudioOffloadInputAudioProvider();
+};
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace audio
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
index 4d7be21..95f7408 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
@@ -35,7 +35,7 @@
std::shared_ptr<BluetoothAudioSession_2_1> session_ptr =
BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type);
if (session_ptr != nullptr) {
- return session_ptr->GetAudioSession()->IsSessionReady();
+ return session_ptr->IsSessionReady();
}
return false;
}
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
index 9d91196..c250ef1 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
@@ -60,6 +60,16 @@
}
}
+bool BluetoothAudioSession_2_1::IsSessionReady() {
+ if (session_type_2_1_ !=
+ SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ return audio_session->IsSessionReady();
+ }
+
+ std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+ return audio_session->stack_iface_ != nullptr;
+}
+
std::shared_ptr<BluetoothAudioSession>
BluetoothAudioSession_2_1::GetAudioSession() {
return audio_session;
@@ -70,7 +80,7 @@
const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
BluetoothAudioSession_2_1::GetAudioConfig() {
std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
- if (audio_session->IsSessionReady()) {
+ if (IsSessionReady()) {
// If session is unknown it means it should be 2.0 type
if (session_type_2_1_ != SessionType_2_1::UNKNOWN)
return audio_config_2_1_;
@@ -110,20 +120,29 @@
SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
session_type_2_1_ ==
SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
- bool is_offload_session =
+ bool is_offload_a2dp_session =
(session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+ bool is_offload_le_audio_session =
+ (session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
auto audio_config_discriminator = audio_config.getDiscriminator();
bool is_software_audio_config =
(is_software_session &&
audio_config_discriminator ==
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
hidl_discriminator::pcmConfig);
- bool is_offload_audio_config =
- (is_offload_session &&
+ bool is_a2dp_offload_audio_config =
+ (is_offload_a2dp_session &&
audio_config_discriminator ==
::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
hidl_discriminator::codecConfig);
- if (!is_software_audio_config && !is_offload_audio_config) {
+ bool is_le_audio_offload_audio_config =
+ (is_offload_le_audio_session &&
+ audio_config_discriminator ==
+ ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
+ hidl_discriminator::leAudioCodecConfig);
+ if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+ !is_le_audio_offload_audio_config) {
return false;
}
audio_config_2_1_ = audio_config;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
index 5a35153..db82c73 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
@@ -50,6 +50,10 @@
const ::android::hardware::bluetooth::audio::V2_1::SessionType&
session_type);
+ // The function helps to check if this session is ready or not
+ // @return: true if the Bluetooth stack has started the specified session
+ bool IsSessionReady();
+
std::shared_ptr<BluetoothAudioSession> GetAudioSession();
// The report function is used to report that the Bluetooth stack has started
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
index 8b0b0f7..c90ce6d 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
@@ -122,6 +122,21 @@
return false;
}
+bool IsOffloadLeAudioConfigurationValid(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration&) {
+
+ if (session_type != SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type != SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
+
+ //TODO: perform checks on le_audio_codec_config once we know supported parameters
+
+ return true;
+}
+
} // namespace audio
} // namespace bluetooth
} // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
index 746d9c0..a52636c 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
@@ -41,6 +41,11 @@
const ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration&
codec_config);
+bool IsOffloadLeAudioConfigurationValid(
+ const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+ session_type,
+ const ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration&
+ le_audio_codec_config);
} // namespace audio
} // namespace bluetooth
} // namespace android
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 362ab41..615fde0 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -496,10 +496,26 @@
* - program changes exactly to what was requested.
*/
TEST_P(BroadcastRadioHalTest, DabTune) {
+ Result halResult;
+ hidl_vec<DabTableEntry> config;
+ auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
+ halResult = result;
+ config = configCb;
+ };
+ auto hidlResult = mModule->getDabRegionConfig(cb);
+ ASSERT_TRUE(hidlResult.isOk());
+
+ if (halResult == Result::NOT_SUPPORTED) {
+ printSkipped("DAB not supported");
+ return;
+ }
+ ASSERT_EQ(Result::OK, halResult);
+ ASSERT_NE(config.size(), 0U);
+
ASSERT_TRUE(openSession());
ProgramSelector sel = {};
- uint64_t freq = 178352;
+ uint64_t freq = config[config.size() / 2].frequency;
sel.primaryId = make_identifier(IdentifierType::DAB_FREQUENCY,freq);
std::this_thread::sleep_for(gTuneWorkaround);
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 27e74f1..16fb85c 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -549,7 +549,6 @@
}
}
}
- free_camera_metadata(metadata);
}
mCameraInfoMap.removeItem(cameraId);
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
index 443549a..622ee8f 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
@@ -6,4 +6,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
index 74f2f96..5df4825 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -3,4 +3,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 73c505d..0721dc3 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -7,4 +7,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc
index 4081fe1..132d943 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc
@@ -3,4 +3,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
index 1c75100..d91fdce 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -8,4 +8,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
index d1c853e..b22971a 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -3,4 +3,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/current.txt b/current.txt
index cd1446d..88b067d 100644
--- a/current.txt
+++ b/current.txt
@@ -836,4 +836,7 @@
ead4ec8713a2cb40906fe31ba793d21a6b1190143c446690d16a6ea686aa2fea android.hardware.tetheroffload.control@1.1::ITetheringOffloadCallback
e34b4c7bec5e032c14804707ca924dd6b99ed5ba139da7505fe7d698d0fe178f android.hardware.tetheroffload.control@1.1::types
+# ABI preserving changes to HALs during Android T
+62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
+
# There should be no more HIDL HALs - please use AIDL instead.
diff --git a/drm/1.0/default/Android.bp b/drm/1.0/default/Android.bp
index af1c076..a5cba5c 100644
--- a/drm/1.0/default/Android.bp
+++ b/drm/1.0/default/Android.bp
@@ -32,6 +32,7 @@
"-Werror",
"-Wextra",
"-Wall",
+ "-Wthread-safety",
],
shared_libs: [
"liblog",
@@ -42,7 +43,7 @@
export_header_lib_headers: [
"libutils_headers",
],
- export_include_dirs : ["include"]
+ export_include_dirs: ["include"],
}
soong_config_module_type {
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index e6d4e84..8dea7e9 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -53,6 +53,8 @@
uint32_t bufferId) {
sp<IMemory> hidlMemory = mapMemory(base);
+ std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+
// allow mapMemory to return nullptr
mSharedBufferMap[bufferId] = hidlMemory;
return Void();
@@ -65,7 +67,7 @@
const SharedBuffer& source, uint64_t offset,
const DestinationBuffer& destination,
decrypt_cb _hidl_cb) {
-
+ std::unique_lock<std::mutex> shared_buffer_lock(mSharedBufferLock);
if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set");
return Void();
@@ -79,7 +81,7 @@
}
}
- android::CryptoPlugin::Mode legacyMode;
+ android::CryptoPlugin::Mode legacyMode = android::CryptoPlugin::kMode_Unencrypted;
switch(mode) {
case Mode::UNENCRYPTED:
legacyMode = android::CryptoPlugin::kMode_Unencrypted;
@@ -146,7 +148,10 @@
return Void();
}
- if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+ size_t totalSize = 0;
+ if (__builtin_add_overflow(destBuffer.offset, destBuffer.size, &totalSize) ||
+ totalSize > destBase->getSize()) {
+ android_errorWriteLog(0x534e4554, "176496353");
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
return Void();
}
@@ -157,7 +162,7 @@
}
base = static_cast<uint8_t *>(static_cast<void *>(destBase->getPointer()));
- destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+ destPtr = static_cast<void*>(base + destination.nonsecureMemory.offset);
} else if (destination.type == BufferType::NATIVE_HANDLE) {
if (!secure) {
_hidl_cb(Status::BAD_VALUE, 0, "native handle destination must be secure");
@@ -170,6 +175,10 @@
_hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
return Void();
}
+
+ // release mSharedBufferLock
+ shared_buffer_lock.unlock();
+
ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
subSamples.size(), destPtr, &detailMessage);
diff --git a/drm/1.0/default/CryptoPlugin.h b/drm/1.0/default/CryptoPlugin.h
index 11cc2aa..0d091fa 100644
--- a/drm/1.0/default/CryptoPlugin.h
+++ b/drm/1.0/default/CryptoPlugin.h
@@ -17,11 +17,14 @@
#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
-#include <android/hidl/memory/1.0/IMemory.h>
+#include <android-base/thread_annotations.h>
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <hidl/Status.h>
#include <media/hardware/CryptoAPI.h>
+#include <mutex>
+
namespace android {
namespace hardware {
namespace drm {
@@ -60,19 +63,21 @@
Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base,
uint32_t bufferId) override;
- Return<void> decrypt(bool secure, const hidl_array<uint8_t, 16>& keyId,
- const hidl_array<uint8_t, 16>& iv, Mode mode, const Pattern& pattern,
- const hidl_vec<SubSample>& subSamples, const SharedBuffer& source,
- uint64_t offset, const DestinationBuffer& destination,
- decrypt_cb _hidl_cb) override;
+ Return<void> decrypt(
+ bool secure, const hidl_array<uint8_t, 16>& keyId, const hidl_array<uint8_t, 16>& iv,
+ Mode mode, const Pattern& pattern, const hidl_vec<SubSample>& subSamples,
+ const SharedBuffer& source, uint64_t offset, const DestinationBuffer& destination,
+ decrypt_cb _hidl_cb) override NO_THREAD_SAFETY_ANALYSIS; // use unique_lock
-private:
+ private:
android::CryptoPlugin *mLegacyPlugin;
- std::map<uint32_t, sp<IMemory> > mSharedBufferMap;
+ std::map<uint32_t, sp<IMemory>> mSharedBufferMap GUARDED_BY(mSharedBufferLock);
CryptoPlugin() = delete;
CryptoPlugin(const CryptoPlugin &) = delete;
void operator=(const CryptoPlugin &) = delete;
+
+ std::mutex mSharedBufferLock;
};
} // namespace implementation
diff --git a/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc b/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc
index 4b32f7f..e5ae5cd 100644
--- a/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc
+++ b/drm/1.0/default/android.hardware.drm@1.0-service-lazy.rc
@@ -7,4 +7,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/drm/1.0/default/android.hardware.drm@1.0-service.rc b/drm/1.0/default/android.hardware.drm@1.0-service.rc
index 790eded..2aba187 100644
--- a/drm/1.0/default/android.hardware.drm@1.0-service.rc
+++ b/drm/1.0/default/android.hardware.drm@1.0-service.rc
@@ -5,4 +5,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh
diff --git a/fastboot/1.0/IFastboot.hal b/fastboot/1.0/IFastboot.hal
index dce3ad7..b39061c 100644
--- a/fastboot/1.0/IFastboot.hal
+++ b/fastboot/1.0/IFastboot.hal
@@ -33,7 +33,7 @@
/**
* Executes a fastboot OEM command.
*
- * @param oemCmdArgs The oem command that is passed to the fastboot HAL.
+ * @param oemCmd The oem command that is passed to the fastboot HAL.
* @return result Returns the status SUCCESS if the operation is successful,
* INVALID_ARGUMENT for bad arguments,
* FAILURE_UNKNOWN for an invalid/unsupported command.
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
index 7d32ced..618624e 100644
--- a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -236,6 +236,10 @@
generatePassword(password, 0);
enrollNewPassword(password, enrollRsp, true);
verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+ ALOGI("Testing unenrolled password doesn't verify");
+ generatePassword(password, 1);
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
ALOGI("Testing Enroll+Verify done");
}
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
index cbd589a..c8fccdc 100644
--- a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
+++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -5,4 +5,4 @@
group graphics drmrpc
capabilities SYS_NICE
onrestart restart surfaceflinger
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
index efe6dad..7714119 100644
--- a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -4,4 +4,4 @@
group graphics drmrpc
capabilities SYS_NICE
onrestart restart surfaceflinger
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
index 81ce890..d3835a4 100644
--- a/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
+++ b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
@@ -4,4 +4,4 @@
group graphics drmrpc
capabilities SYS_NICE
onrestart restart surfaceflinger
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
index a296b0a..d82dcd9 100644
--- a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
+++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
@@ -4,4 +4,4 @@
group graphics drmrpc
capabilities SYS_NICE
onrestart restart surfaceflinger
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
diff --git a/identity/TEST_MAPPING b/identity/TEST_MAPPING
index f35f4b7..85cf91f 100644
--- a/identity/TEST_MAPPING
+++ b/identity/TEST_MAPPING
@@ -8,6 +8,9 @@
},
{
"name": "android.hardware.identity-support-lib-test"
+ },
+ {
+ "name": "libeic_test"
}
]
}
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 7c68aee..28c4893 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -114,6 +114,43 @@
],
}
+cc_test {
+ name: "libeic_test",
+ srcs: [
+ "EicTests.cpp",
+ "FakeSecureHardwareProxy.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-g",
+ "-DEIC_DEBUG",
+ ],
+ local_include_dirs: [
+ "common",
+ ],
+ shared_libs: [
+ "liblog",
+ "libcrypto",
+ "libkeymaster_messages",
+ ],
+ static_libs: [
+ "libbase",
+ "libcppbor_external",
+ "libcppcose_rkp",
+ "libutils",
+ "libsoft_attestation_cert",
+ "libkeymaster_portable",
+ "libsoft_attestation_cert",
+ "libpuresoftkeymasterdevice",
+ "android.hardware.identity-support-lib",
+ "android.hardware.identity-libeic-library",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+}
+
prebuilt_etc {
name: "android.hardware.identity_credential.xml",
sub_dir: "permissions",
diff --git a/identity/aidl/default/EicTests.cpp b/identity/aidl/default/EicTests.cpp
new file mode 100644
index 0000000..a28080d
--- /dev/null
+++ b/identity/aidl/default/EicTests.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "FakeSecureHardwareProxy.h"
+
+// Most of libeic is tested as part of VTS since there's almost a 1:1 mapping between
+// the HAL and libeic interfaces. This test suite is mainly for the few things which
+// doesn't map directly.
+//
+
+using std::optional;
+using std::string;
+using std::vector;
+
+using android::hardware::identity::AccessCheckResult;
+using android::hardware::identity::FakeSecureHardwarePresentationProxy;
+using android::hardware::identity::FakeSecureHardwareProvisioningProxy;
+
+TEST(EicTest, AccessControlIsEnforced) {
+ // First provision the credential...
+ //
+ FakeSecureHardwareProvisioningProxy provisioningProxy;
+ bool isTestCredential = false;
+ provisioningProxy.initialize(isTestCredential);
+ optional<vector<uint8_t>> credKey =
+ provisioningProxy.createCredentialKey({0x01, 0x02}, {0x03, 0x04});
+ ASSERT_TRUE(credKey.has_value());
+ string docType = "org.iso.18013.5.1.mDL";
+ ASSERT_TRUE(provisioningProxy.startPersonalization(0, {1}, docType, 125));
+
+ vector<int> acpIds = {};
+ string nameSpace = "org.iso.18013.5.1";
+ string name = "NonAccessibleElement";
+ vector<uint8_t> content = {0x63, 0x46, 0x6f, 0x6f}; // "Foo" tstr
+ ASSERT_TRUE(provisioningProxy.beginAddEntry(acpIds, nameSpace, name, content.size()));
+ optional<vector<uint8_t>> encContent =
+ provisioningProxy.addEntryValue(acpIds, nameSpace, name, content);
+ ASSERT_TRUE(encContent.has_value());
+ ASSERT_EQ(encContent->size(), content.size() + 28);
+
+ optional<vector<uint8_t>> signatureOfToBeSigned = provisioningProxy.finishAddingEntries();
+ ASSERT_TRUE(signatureOfToBeSigned.has_value());
+
+ optional<vector<uint8_t>> credData = provisioningProxy.finishGetCredentialData(docType);
+ ASSERT_TRUE(credData.has_value());
+ ASSERT_TRUE(provisioningProxy.shutdown());
+
+ // Then present data from it...
+ //
+ FakeSecureHardwarePresentationProxy presentationProxy;
+ ASSERT_TRUE(presentationProxy.initialize(isTestCredential, docType, credData.value()));
+ AccessCheckResult res =
+ presentationProxy.startRetrieveEntryValue(nameSpace, name, 1, content.size(), acpIds);
+ ASSERT_EQ(res, AccessCheckResult::kNoAccessControlProfiles);
+
+ // Ensure that we can't get the data out if startRetrieveEntryValue() returned
+ // something other than kOk... See b/190757775 for details.
+ //
+ optional<vector<uint8_t>> decContent =
+ presentationProxy.retrieveEntryValue(encContent.value(), nameSpace, name, acpIds);
+ ASSERT_FALSE(decContent.has_value());
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 9e033b3..3d13766 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -633,6 +633,8 @@
// We'll need to calc and store a digest of additionalData to check that it's the same
// additionalData being passed in for every eicPresentationRetrieveEntryValue() call...
+ //
+ ctx->accessCheckOk = false;
if (!eicCborCalcEntryAdditionalData(accessControlProfileIds, numAccessControlProfileIds,
nameSpace, name, additionalDataCbor,
additionalDataCborBufSize, &additionalDataCborSize,
@@ -680,6 +682,7 @@
if (result == EIC_ACCESS_CHECK_RESULT_OK) {
eicCborAppendString(&ctx->cbor, name);
+ ctx->accessCheckOk = true;
}
return result;
}
@@ -702,10 +705,15 @@
calculatedSha256)) {
return false;
}
+
if (eicCryptoMemCmp(calculatedSha256, ctx->additionalDataSha256, EIC_SHA256_DIGEST_SIZE) != 0) {
eicDebug("SHA-256 mismatch of additionalData");
return false;
}
+ if (!ctx->accessCheckOk) {
+ eicDebug("Attempting to retrieve a value for which access is not granted");
+ return false;
+ }
if (!eicOpsDecryptAes128Gcm(ctx->storageKey, encryptedContent, encryptedContentSize,
additionalDataCbor, additionalDataCborSize, content)) {
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index 7cad068..c888049 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -70,6 +70,10 @@
// Set to true initialized as a test credential.
bool testCredential;
+ // Set to true if the evaluation of access control checks in
+ // eicPresentationStartRetrieveEntryValue() resulted EIC_ACCESS_CHECK_RESULT_OK
+ bool accessCheckOk;
+
// These are bitmasks indicating which of the possible 32 access control profiles are
// authorized. They are built up by eicPresentationValidateAccessControlProfile().
//
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index bc294bd..342b3e2 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -71,6 +71,7 @@
ASN1_INTEGER_SET* padding;
ASN1_INTEGER* ec_curve;
ASN1_INTEGER* rsa_public_exponent;
+ ASN1_NULL* rollback_resistance;
ASN1_INTEGER* active_date_time;
ASN1_INTEGER* origination_expire_date_time;
ASN1_INTEGER* usage_expire_date_time;
@@ -78,56 +79,84 @@
ASN1_INTEGER* user_auth_type;
ASN1_INTEGER* auth_timeout;
ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
ASN1_NULL* all_applications;
ASN1_OCTET_STRING* application_id;
ASN1_INTEGER* creation_date_time;
ASN1_INTEGER* origin;
- ASN1_NULL* rollback_resistance;
KM_ROOT_OF_TRUST* root_of_trust;
ASN1_INTEGER* os_version;
ASN1_INTEGER* os_patchlevel;
ASN1_OCTET_STRING* attestation_application_id;
- ASN1_NULL* trusted_user_presence_required;
- ASN1_NULL* trusted_confirmation_required;
- ASN1_NULL* unlocked_device_required;
+ ASN1_OCTET_STRING* attestation_id_brand;
+ ASN1_OCTET_STRING* attestation_id_device;
+ ASN1_OCTET_STRING* attestation_id_product;
+ ASN1_OCTET_STRING* attestation_id_serial;
+ ASN1_OCTET_STRING* attestation_id_imei;
+ ASN1_OCTET_STRING* attestation_id_meid;
+ ASN1_OCTET_STRING* attestation_id_manufacturer;
+ ASN1_OCTET_STRING* attestation_id_model;
ASN1_INTEGER* vendor_patchlevel;
ASN1_INTEGER* boot_patchlevel;
} KM_AUTH_LIST;
ASN1_SEQUENCE(KM_AUTH_LIST) = {
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
- ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
- TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, TAG_ROLLBACK_RESISTANCE.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
- TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
- TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
- TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
- TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
- TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, TAG_CREATION_DATETIME.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, TAG_VENDOR_PATCHLEVEL.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
- TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+ TAG_ROLLBACK_RESISTANCE.maskedTag()),
+
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+ TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_BRAND.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_IMEI.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MEID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MODEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+ TAG_VENDOR_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
@@ -259,6 +288,14 @@
copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+ copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+ copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+ copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+ copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+ copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+ copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+ copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list);
copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 9e37ed0..01c502c 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -96,6 +96,18 @@
return count > 0;
}
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+ const char* prop) {
+ char value[PROPERTY_VALUE_MAX];
+ int len = property_get(prop, value, /* default = */ "");
+ if (len > 0) {
+ tags->Authorization(ttag, reinterpret_cast<const uint8_t*>(value),
+ static_cast<size_t>(len));
+ }
+}
+
constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
@@ -4409,6 +4421,95 @@
}
/*
+ * AttestationTest.EcAttestationID
+ *
+ * Verifies that attesting to EC keys with correct attestation ID fields works and generates the
+ * expected output.
+ */
+TEST_P(AttestationTest, EcAttestationID) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ // Collection of valid attestation ID tags.
+ auto attestation_id_tags = AuthorizationSetBuilder();
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+ for (const KeyParameter& tag : attestation_id_tags) {
+ AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo"));
+ // Include one of the (valid) attestation ID tags.
+ builder.push_back(tag);
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ auto result = AttestKey(builder, &cert_chain);
+ if (result == ErrorCode::CANNOT_ATTEST_IDS) {
+ continue;
+ }
+
+ ASSERT_EQ(ErrorCode::OK, result);
+ EXPECT_GE(cert_chain.size(), 2U);
+
+ std::vector<KeyParameter> expected_hw_enforced = key_characteristics_.hardwareEnforced;
+ expected_hw_enforced.push_back(tag);
+
+ EXPECT_TRUE(verify_attestation_record(
+ "challenge", "foo", key_characteristics_.softwareEnforced,
+ hidl_vec<KeyParameter>(expected_hw_enforced), SecLevel(), cert_chain[0]));
+ }
+}
+
+/*
+ * AttestationTest.EcAttestationMismatchID
+ *
+ * Verifies that attesting to EC keys with incorrect attestation ID fields fails.
+ */
+TEST_P(AttestationTest, EcAttestationMismatchID) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ // Collection of invalid attestation ID tags.
+ std::string invalid = "completely-invalid";
+ auto invalid_tags =
+ AuthorizationSetBuilder()
+ .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(),
+ invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size());
+
+ for (const KeyParameter& invalid_tag : invalid_tags) {
+ AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo"));
+ // Include one of the invalid attestation ID tags.
+ builder.push_back(invalid_tag);
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ auto result = AttestKey(builder, &cert_chain);
+
+ EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+ << "result: " << static_cast<int32_t>(result);
+ }
+}
+
+/*
* AttestationTest.EcAttestationRequiresAttestationAppId
*
* Verifies that attesting to EC keys requires app ID
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 207a7e8..15230d5 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -79,6 +79,8 @@
ASN1_INTEGER_SET* padding;
ASN1_INTEGER* ec_curve;
ASN1_INTEGER* rsa_public_exponent;
+ ASN1_NULL* rollback_resistance;
+ ASN1_NULL* early_boot_only;
ASN1_INTEGER* active_date_time;
ASN1_INTEGER* origination_expire_date_time;
ASN1_INTEGER* usage_expire_date_time;
@@ -86,21 +88,27 @@
ASN1_INTEGER* user_auth_type;
ASN1_INTEGER* auth_timeout;
ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
ASN1_NULL* all_applications;
ASN1_OCTET_STRING* application_id;
ASN1_INTEGER* creation_date_time;
ASN1_INTEGER* origin;
- ASN1_NULL* rollback_resistance;
KM_ROOT_OF_TRUST* root_of_trust;
ASN1_INTEGER* os_version;
ASN1_INTEGER* os_patchlevel;
ASN1_OCTET_STRING* attestation_application_id;
- ASN1_NULL* trusted_user_presence_required;
- ASN1_NULL* trusted_confirmation_required;
- ASN1_NULL* unlocked_device_required;
+ ASN1_OCTET_STRING* attestation_id_brand;
+ ASN1_OCTET_STRING* attestation_id_device;
+ ASN1_OCTET_STRING* attestation_id_product;
+ ASN1_OCTET_STRING* attestation_id_serial;
+ ASN1_OCTET_STRING* attestation_id_imei;
+ ASN1_OCTET_STRING* attestation_id_meid;
+ ASN1_OCTET_STRING* attestation_id_manufacturer;
+ ASN1_OCTET_STRING* attestation_id_model;
ASN1_INTEGER* vendor_patchlevel;
ASN1_INTEGER* boot_patchlevel;
- ASN1_NULL* early_boot_only;
ASN1_NULL* device_unique_attestation;
ASN1_NULL* identity_credential_key;
} KM_AUTH_LIST;
@@ -116,6 +124,7 @@
TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
@@ -138,12 +147,27 @@
ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_BRAND.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_IMEI.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MEID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MODEL.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
TAG_VENDOR_PATCHLEVEL.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
- TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
@@ -279,6 +303,14 @@
copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+ copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+ copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+ copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+ copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+ copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+ copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+ copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list);
copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 40eb142..e8db56a 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -53,6 +53,14 @@
using V4_0::TAG_ASSOCIATED_DATA;
using V4_0::TAG_ATTESTATION_APPLICATION_ID;
using V4_0::TAG_ATTESTATION_CHALLENGE;
+using V4_0::TAG_ATTESTATION_ID_BRAND;
+using V4_0::TAG_ATTESTATION_ID_DEVICE;
+using V4_0::TAG_ATTESTATION_ID_IMEI;
+using V4_0::TAG_ATTESTATION_ID_MANUFACTURER;
+using V4_0::TAG_ATTESTATION_ID_MEID;
+using V4_0::TAG_ATTESTATION_ID_MODEL;
+using V4_0::TAG_ATTESTATION_ID_PRODUCT;
+using V4_0::TAG_ATTESTATION_ID_SERIAL;
using V4_0::TAG_AUTH_TIMEOUT;
using V4_0::TAG_BLOB_USAGE_REQUIREMENTS;
using V4_0::TAG_BLOCK_MODE;
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
index 0639da8..4a57f44 100644
--- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "keymaster_hidl_hal_test"
#include <cutils/log.h>
+#include <vector>
#include "Keymaster4_1HidlTest.h"
@@ -26,6 +27,8 @@
#include <keymasterV4_1/attestation_record.h>
#include <keymasterV4_1/authorization_set.h>
+using android::hardware::keymaster::V4_0::test::add_tag_from_prop;
+
// Not to dump the attestation by default. Can enable by specify the parameter
// "--dump_attestations" on lunching VTS
static bool dumpAttestations = false;
@@ -172,10 +175,42 @@
attestation.software_enforced.Sort();
attestation.hardware_enforced.Sort();
- EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced))
- << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
- EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced))
- << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+ expected_sw_enforced = filter_tags(expected_sw_enforced);
+ expected_hw_enforced = filter_tags(expected_hw_enforced);
+ AuthorizationSet attestation_sw_enforced = filter_tags(attestation.software_enforced);
+ AuthorizationSet attestation_hw_enforced = filter_tags(attestation.hardware_enforced);
+
+ EXPECT_EQ(expected_sw_enforced, attestation_sw_enforced)
+ << DIFFERENCE(expected_sw_enforced, attestation_sw_enforced);
+ EXPECT_EQ(expected_hw_enforced, attestation_hw_enforced)
+ << DIFFERENCE(expected_hw_enforced, attestation_hw_enforced);
+}
+
+X509_Ptr parse_cert_blob(const std::vector<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
+bool check_certificate_chain_signatures(const hidl_vec<hidl_vec<uint8_t>>& cert_chain) {
+ // TODO: Check that root is self-signed once b/187803288 is resolved.
+ for (size_t i = 0; i < cert_chain.size() - 1; ++i) {
+ X509_Ptr key_cert(parse_cert_blob(cert_chain[i]));
+ X509_Ptr signing_cert(parse_cert_blob(cert_chain[i + 1]));
+
+ if (!key_cert.get() || !signing_cert.get()) {
+ return false;
+ }
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ if (!signing_pubkey.get()) {
+ return false;
+ }
+
+ if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+ return false;
+ }
+ }
+ return true;
}
} // namespace
@@ -243,6 +278,7 @@
EXPECT_EQ(ErrorCode::OK, result);
EXPECT_EQ(2U, cert_chain.size());
+ EXPECT_TRUE(check_certificate_chain_signatures(cert_chain));
if (dumpAttestations) {
for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
}
@@ -289,6 +325,7 @@
EXPECT_EQ(ErrorCode::OK, result);
EXPECT_EQ(2U, cert_chain.size());
+ EXPECT_TRUE(check_certificate_chain_signatures(cert_chain));
if (dumpAttestations) {
for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
}
@@ -312,6 +349,106 @@
SecLevel());
}
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ // Collection of valid attestation ID tags.
+ auto attestation_id_tags = AuthorizationSetBuilder();
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer");
+ add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+ for (const KeyParameter& tag : attestation_id_tags) {
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id);
+ builder.push_back(tag);
+ ErrorCode result = convert(AttestKey(builder, &cert_chain));
+
+ // It is optional for Strong box to support DeviceUniqueAttestation.
+ if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
+
+ ASSERT_EQ(ErrorCode::OK, result);
+ EXPECT_EQ(2U, cert_chain.size());
+ if (dumpAttestations) {
+ for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
+ }
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ ASSERT_EQ(ErrorCode::OK, err);
+
+ AuthorizationSetBuilder hw_enforced =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+ hw_enforced.push_back(tag);
+ check_attestation_record(
+ attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ hw_enforced, SecLevel());
+ }
+}
+
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ // Collection of invalid attestation ID tags.
+ std::string invalid = "completely-invalid";
+ auto attestation_id_tags =
+ AuthorizationSetBuilder()
+ .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(),
+ invalid.size())
+ .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size());
+
+ for (const KeyParameter& invalid_tag : attestation_id_tags) {
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id);
+ builder.push_back(invalid_tag);
+ ErrorCode result = convert(AttestKey(builder, &cert_chain));
+
+ EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+ << "result: " << static_cast<int32_t>(result);
+ }
+}
+
INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
} // namespace test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
index f8c1fad..670ccfb 100644
--- a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -18,6 +18,8 @@
#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <android-base/properties.h>
+
#include <KeymasterHidlTest.h>
#include <keymasterV4_1/authorization_set.h>
@@ -159,3 +161,17 @@
android::hardware::PrintInstanceNameToString)
} // namespace android::hardware::keymaster::V4_1::test
+
+namespace android::hardware::keymaster::V4_0::test {
+
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+ const char* prop) {
+ std::string prop_value = ::android::base::GetProperty(prop, /* default= */ "");
+ if (!prop_value.empty()) {
+ tags->Authorization(ttag, prop_value.data(), prop_value.size());
+ }
+}
+
+} // namespace android::hardware::keymaster::V4_0::test
diff --git a/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl b/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
index e78d4d7..13c3389 100644
--- a/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
+++ b/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
@@ -31,12 +31,14 @@
* accounting for stride, bit depth, rounding up to page size, etc.
*
* The following getMemory() categories are important for memory accounting in
- * `dumpsys meminfo` and should be reported as described below:
+ * Android frameworks (e.g. `dumpsys meminfo`) and should be reported as described
+ * below:
*
* - MemtrackType::GRAPHICS and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
- * This should report the PSS of all DMA buffers mapped by the process
- * with the specified PID. This PSS can be calculated using ReadDmaBufPss()
- * form libdmabufinfo.
+ * This should report the PSS of all CPU-Mapped DMA-BUFs (buffers mapped into
+ * the process address space) and all GPU-Mapped DMA-BUFs (buffers mapped into
+ * the GPU device address space on behalf of the process), removing any overlap
+ * between the CPU-mapped and GPU-mapped sets.
*
* - MemtrackType::GL and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
* This category should report all GPU private allocations for the specified
@@ -46,6 +48,10 @@
* Any other memory not accounted for in /proc/<pid>/smaps if any, otherwise
* this should return 0.
*
+ * SMAPS_UNACCOUNTED memory should also include memory that is mapped with
+ * VM_PFNMAP flag set. For these mappings PSS and RSS are reported as 0 in smaps.
+ * Such mappings have no backing page structs from which PSS/RSS can be calculated.
+ *
* Constructor for the interface should be used to perform memtrack management
* setup actions and must be called once before any calls to getMemory().
*/
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index e8a4f55..11225cf 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -239,7 +239,7 @@
using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
switch (memoryPool.getDiscriminator()) {
case Discriminator::hidlMemory:
- return hal::utils::createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
+ return unvalidatedConvert(memoryPool.hidlMemory());
case Discriminator::token:
return static_cast<Request::MemoryDomainToken>(memoryPool.token());
}
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 5eab9ff..78433a7 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -95,9 +95,7 @@
GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension);
GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation);
-GeneralResult<SharedHandle> unvalidatedConvert(
- const ::aidl::android::hardware::common::NativeHandle& handle);
-GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence);
+GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle);
GeneralResult<std::vector<Operation>> unvalidatedConvert(
const std::vector<aidl_hal::Operation>& operations);
@@ -113,7 +111,7 @@
GeneralResult<Priority> convert(const aidl_hal::Priority& priority);
GeneralResult<Request> convert(const aidl_hal::Request& request);
GeneralResult<Timing> convert(const aidl_hal::Timing& timing);
-GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence);
+GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle);
GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension);
GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
@@ -160,9 +158,7 @@
nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration);
nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalTimePoint& optionalTimePoint);
nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SyncFence& syncFence);
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle);
-nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvertCache(
- const nn::SharedHandle& handle);
+nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle);
nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken);
nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index 87cd0e4..800ac32 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -62,7 +62,7 @@
private:
const std::shared_ptr<const Burst> kBurst;
const Request kRequest;
- const std::vector<int64_t>& kMemoryIdentifierTokens;
+ const std::vector<int64_t> kMemoryIdentifierTokens;
const bool kMeasure;
const int64_t kLoopTimeoutDuration;
const hal::utils::RequestRelocation kRelocation;
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 4b263ee..0517730 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -108,17 +108,6 @@
return canonical;
}
-GeneralResult<Handle> unvalidatedConvertHelper(const NativeHandle& aidlNativeHandle) {
- std::vector<base::unique_fd> fds;
- fds.reserve(aidlNativeHandle.fds.size());
- for (const auto& fd : aidlNativeHandle.fds) {
- auto duplicatedFd = NN_TRY(dupFd(fd.get()));
- fds.emplace_back(duplicatedFd.release());
- }
-
- return Handle{.fds = std::move(fds), .ints = aidlNativeHandle.ints};
-}
-
struct NativeHandleDeleter {
void operator()(native_handle_t* handle) const {
if (handle) {
@@ -498,18 +487,14 @@
return static_cast<ExecutionPreference>(executionPreference);
}
-GeneralResult<SharedHandle> unvalidatedConvert(const NativeHandle& aidlNativeHandle) {
- return std::make_shared<const Handle>(NN_TRY(unvalidatedConvertHelper(aidlNativeHandle)));
-}
-
GeneralResult<std::vector<Operation>> unvalidatedConvert(
const std::vector<aidl_hal::Operation>& operations) {
return unvalidatedConvertVec(operations);
}
-GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence) {
- auto duplicatedFd = NN_TRY(dupFd(syncFence.get()));
- return SyncFence::create(std::move(duplicatedFd));
+GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle) {
+ auto duplicatedFd = NN_TRY(dupFd(handle.get()));
+ return std::make_shared<const Handle>(std::move(duplicatedFd));
}
GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities) {
@@ -553,8 +538,8 @@
return validatedConvert(timing);
}
-GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence) {
- return validatedConvert(syncFence);
+GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle) {
+ return validatedConvert(handle);
}
GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
@@ -619,17 +604,6 @@
return halObject;
}
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::Handle& handle) {
- common::NativeHandle aidlNativeHandle;
- aidlNativeHandle.fds.reserve(handle.fds.size());
- for (const auto& fd : handle.fds) {
- auto duplicatedFd = NN_TRY(nn::dupFd(fd.get()));
- aidlNativeHandle.fds.emplace_back(duplicatedFd.release());
- }
- aidlNativeHandle.ints = handle.ints;
- return aidlNativeHandle;
-}
-
// Helper template for std::visit
template <class... Ts>
struct overloaded : Ts... {
@@ -755,11 +729,6 @@
return measureTiming == nn::MeasureTiming::YES;
}
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle) {
- CHECK(sharedHandle != nullptr);
- return unvalidatedConvert(*sharedHandle);
-}
-
nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
if (memory == nullptr) {
return (NN_ERROR() << "Unable to convert nullptr memory")
@@ -997,16 +966,8 @@
return ndk::ScopedFileDescriptor(duplicatedFd.release());
}
-nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvertCache(
- const nn::SharedHandle& handle) {
- if (handle->ints.size() != 0) {
- NN_ERROR() << "Cache handle must not contain ints";
- }
- if (handle->fds.size() != 1) {
- NN_ERROR() << "Cache handle must contain exactly one fd but contains "
- << handle->fds.size();
- }
- auto duplicatedFd = NN_TRY(nn::dupFd(handle->fds.front().get()));
+nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle) {
+ auto duplicatedFd = NN_TRY(nn::dupFd(handle->get()));
return ndk::ScopedFileDescriptor(duplicatedFd.release());
}
@@ -1069,16 +1030,7 @@
nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
const std::vector<nn::SharedHandle>& cacheHandles) {
- const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(cacheHandles)));
- if (version > kVersion) {
- return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
- }
- std::vector<ndk::ScopedFileDescriptor> cacheFds;
- cacheFds.reserve(cacheHandles.size());
- for (const auto& cacheHandle : cacheHandles) {
- cacheFds.push_back(NN_TRY(unvalidatedConvertCache(cacheHandle)));
- }
- return cacheFds;
+ return validatedConvert(cacheHandles);
}
nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index 0fd453b..e80de0b 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -119,7 +119,7 @@
<< numberOfCacheFiles.numDataCache << " vs " << nn::kMaxNumberOfCacheFiles
<< ")";
}
- return std::make_pair(numberOfCacheFiles.numDataCache, numberOfCacheFiles.numModelCache);
+ return std::make_pair(numberOfCacheFiles.numModelCache, numberOfCacheFiles.numDataCache);
}
} // namespace
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index 18e7636..f861d74 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -160,7 +160,7 @@
auto resultSyncFence = nn::SyncFence::createAsSignaled();
if (result.syncFence.get() != -1) {
- resultSyncFence = NN_TRY(nn::convert(result.syncFence));
+ resultSyncFence = nn::SyncFence::create(NN_TRY(nn::convert(result.syncFence))).value();
}
auto callback = result.callback;
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index e53b0a8..f121aca 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -58,7 +58,7 @@
const std::shared_ptr<BnDevice> kInvalidDevice;
constexpr PerformanceInfo kNoPerformanceInfo = {.execTime = std::numeric_limits<float>::max(),
.powerUsage = std::numeric_limits<float>::max()};
-constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles,
+constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles - 1,
.numDataCache = nn::kMaxNumberOfCacheFiles};
constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
@@ -300,6 +300,21 @@
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
+TEST(DeviceTest, getNumberOfCacheFilesNeeded) {
+ // setup call
+ const auto mockDevice = createMockDevice();
+ EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(1);
+
+ // run test
+ const auto result = Device::create(kName, mockDevice);
+
+ // verify result
+ ASSERT_TRUE(result.has_value());
+ constexpr auto kNumberOfCacheFilesPair = std::make_pair<uint32_t, uint32_t>(
+ kNumberOfCacheFiles.numModelCache, kNumberOfCacheFiles.numDataCache);
+ EXPECT_EQ(result.value()->getNumberOfCacheFilesNeeded(), kNumberOfCacheFilesPair);
+}
+
TEST(DeviceTest, getNumberOfCacheFilesNeededError) {
// setup call
const auto mockDevice = createMockDevice();
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index d3b041d..2356ff0 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -435,8 +435,8 @@
mInputMemory = TestBlobAHWB::create(std::max<size_t>(inputSize, 1));
mOutputMemory = TestBlobAHWB::create(std::max<size_t>(outputSize, 1));
} else {
- mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1));
- mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1));
+ mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1), /*aidlReadonly=*/true);
+ mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1), /*aidlReadonly=*/false);
}
CHECK_NE(mInputMemory, nullptr);
CHECK_NE(mOutputMemory, nullptr);
diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp
index 3c7f5f7..9af362e 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.cpp
+++ b/neuralnetworks/aidl/vts/functional/Utils.cpp
@@ -23,6 +23,7 @@
#include <android/binder_status.h>
#include <android/hardware_buffer.h>
+#include <sys/mman.h>
#include <iostream>
#include <limits>
#include <numeric>
@@ -98,19 +99,39 @@
std::multiplies<>{});
}
-std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size) {
- auto ashmem = std::make_unique<TestAshmem>(size);
+std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size, bool aidlReadonly) {
+ auto ashmem = std::make_unique<TestAshmem>(size, aidlReadonly);
return ashmem->mIsValid ? std::move(ashmem) : nullptr;
}
-void TestAshmem::initialize(uint32_t size) {
+// This function will create a readonly shared memory with PROT_READ only.
+// The input shared memory must be either Ashmem or mapped-FD.
+static nn::SharedMemory convertSharedMemoryToReadonly(const nn::SharedMemory& sharedMemory) {
+ if (std::holds_alternative<nn::Memory::Ashmem>(sharedMemory->handle)) {
+ const auto& memory = std::get<nn::Memory::Ashmem>(sharedMemory->handle);
+ return nn::createSharedMemoryFromFd(memory.size, PROT_READ, memory.fd.get(), /*offset=*/0)
+ .value();
+ } else if (std::holds_alternative<nn::Memory::Fd>(sharedMemory->handle)) {
+ const auto& memory = std::get<nn::Memory::Fd>(sharedMemory->handle);
+ return nn::createSharedMemoryFromFd(memory.size, PROT_READ, memory.fd.get(), memory.offset)
+ .value();
+ }
+ CHECK(false) << "Unexpected shared memory type";
+ return sharedMemory;
+}
+
+void TestAshmem::initialize(uint32_t size, bool aidlReadonly) {
mIsValid = false;
ASSERT_GT(size, 0);
const auto sharedMemory = nn::createSharedMemory(size).value();
mMappedMemory = nn::map(sharedMemory).value();
mPtr = static_cast<uint8_t*>(std::get<void*>(mMappedMemory.pointer));
CHECK_NE(mPtr, nullptr);
- mAidlMemory = utils::convert(sharedMemory).value();
+ if (aidlReadonly) {
+ mAidlMemory = utils::convert(convertSharedMemoryToReadonly(sharedMemory)).value();
+ } else {
+ mAidlMemory = utils::convert(sharedMemory).value();
+ }
mIsValid = true;
}
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index 77085a7..9dd7359 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -79,15 +79,18 @@
class TestAshmem : public TestMemoryBase {
public:
- static std::unique_ptr<TestAshmem> create(uint32_t size);
+ // If aidlReadonly is true, getAidlMemory will return a sAIDL memory with readonly access;
+ // otherwise, the sAIDL memory has read-write access. This only affects the sAIDL memory.
+ // getPointer will always return a valid address with read-write access.
+ static std::unique_ptr<TestAshmem> create(uint32_t size, bool aidlReadonly = false);
// Prefer TestAshmem::create.
// The constructor calls initialize, which constructs the memory resources. This is a workaround
// that gtest macros cannot be used directly in a constructor.
- TestAshmem(uint32_t size) { initialize(size); }
+ TestAshmem(uint32_t size, bool aidlReadonly) { initialize(size, aidlReadonly); }
private:
- void initialize(uint32_t size);
+ void initialize(uint32_t size, bool aidlReadonly);
nn::Mapping mMappedMemory;
};
diff --git a/neuralnetworks/utils/README.md b/neuralnetworks/utils/README.md
index 87b3f9f..ffad6ee 100644
--- a/neuralnetworks/utils/README.md
+++ b/neuralnetworks/utils/README.md
@@ -44,7 +44,7 @@
EXPECT_EQ(versionedBefore, versionedAfter);
```
-The `convert` functions operate only on types that used in a HIDL method call directly. The
+The `convert` functions operate only on types that are used in a HIDL method call directly. The
`unvalidatedConvert` functions operate on types that are either used in a HIDL method call directly
(i.e., not as a nested class) or used in a subsequent version of the NN HAL. Prefer using `convert`
over `unvalidatedConvert`.
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 8e55bf0..906b0cf 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -89,23 +89,39 @@
});
}
-nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(std::vector<base::unique_fd> fds,
const std::vector<int32_t>& ints) {
constexpr size_t kIntMax = std::numeric_limits<int>::max();
+ CHECK_LE(fds.size(), kIntMax);
CHECK_LE(ints.size(), kIntMax);
- native_handle_t* nativeHandle = native_handle_create(1, static_cast<int>(ints.size()));
+ native_handle_t* nativeHandle =
+ native_handle_create(static_cast<int>(fds.size()), static_cast<int>(ints.size()));
if (nativeHandle == nullptr) {
return NN_ERROR() << "Failed to create native_handle";
}
- nativeHandle->data[0] = fd.release();
- std::copy(ints.begin(), ints.end(), nativeHandle->data + 1);
+ for (size_t i = 0; i < fds.size(); ++i) {
+ nativeHandle->data[i] = fds[i].release();
+ }
+ std::copy(ints.begin(), ints.end(), nativeHandle->data + nativeHandle->numFds);
hidl_handle handle;
handle.setTo(nativeHandle, /*shouldOwn=*/true);
return handle;
}
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+ const std::vector<int32_t>& ints) {
+ std::vector<base::unique_fd> fds;
+ fds.push_back(std::move(fd));
+ return createNativeHandleFrom(std::move(fds), ints);
+}
+
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(const nn::Memory::Unknown::Handle& handle) {
+ std::vector<base::unique_fd> fds = NN_TRY(nn::dupFds(handle.fds.begin(), handle.fds.end()));
+ return createNativeHandleFrom(std::move(fds), handle.ints);
+}
+
nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Ashmem& memory) {
auto fd = NN_TRY(nn::dupFd(memory.fd));
auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), {}));
@@ -139,7 +155,22 @@
}
nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Unknown& memory) {
- return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
+ return hidl_memory(memory.name, NN_TRY(createNativeHandleFrom(memory.handle)), memory.size);
+}
+
+nn::GeneralResult<nn::Memory::Unknown::Handle> unknownHandleFromNativeHandle(
+ const native_handle_t* handle) {
+ if (handle == nullptr) {
+ return NN_ERROR() << "unknownHandleFromNativeHandle failed because handle is nullptr";
+ }
+
+ std::vector<base::unique_fd> fds =
+ NN_TRY(nn::dupFds(handle->data + 0, handle->data + handle->numFds));
+
+ std::vector<int> ints(handle->data + handle->numFds,
+ handle->data + handle->numFds + handle->numInts);
+
+ return nn::Memory::Unknown::Handle{.fds = std::move(fds), .ints = std::move(ints)};
}
} // anonymous namespace
@@ -349,7 +380,7 @@
if (memory.name() != "hardware_buffer_blob") {
auto handle = nn::Memory::Unknown{
- .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
+ .handle = NN_TRY(unknownHandleFromNativeHandle(memory.handle())),
.size = static_cast<size_t>(memory.size()),
.name = memory.name(),
};
@@ -395,53 +426,19 @@
}
nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
- std::vector<base::unique_fd> fds;
- fds.reserve(handle.fds.size());
- for (const auto& fd : handle.fds) {
- const int dupFd = dup(fd);
- if (dupFd == -1) {
- return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
- }
- fds.emplace_back(dupFd);
- }
-
- constexpr size_t kIntMax = std::numeric_limits<int>::max();
- CHECK_LE(handle.fds.size(), kIntMax);
- CHECK_LE(handle.ints.size(), kIntMax);
- native_handle_t* nativeHandle = native_handle_create(static_cast<int>(handle.fds.size()),
- static_cast<int>(handle.ints.size()));
- if (nativeHandle == nullptr) {
- return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
- }
- for (size_t i = 0; i < fds.size(); ++i) {
- nativeHandle->data[i] = fds[i].release();
- }
- std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]);
-
- hidl_handle hidlHandle;
- hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
- return hidlHandle;
+ base::unique_fd fd = NN_TRY(nn::dupFd(handle.get()));
+ return createNativeHandleFrom(std::move(fd), {});
}
nn::GeneralResult<nn::Handle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
if (handle == nullptr) {
return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle is nullptr";
}
-
- std::vector<base::unique_fd> fds;
- fds.reserve(handle->numFds);
- for (int i = 0; i < handle->numFds; ++i) {
- const int dupFd = dup(handle->data[i]);
- if (dupFd == -1) {
- return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
- }
- fds.emplace_back(dupFd);
+ if (handle->numFds != 1 || handle->numInts != 0) {
+ return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle does not only "
+ "hold a single fd";
}
-
- std::vector<int> ints(&handle->data[handle->numFds],
- &handle->data[handle->numFds + handle->numInts]);
-
- return nn::Handle{.fds = std::move(fds), .ints = std::move(ints)};
+ return nn::dupFd(handle->data[0]);
}
nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 422e91c..391166b 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -19,6 +19,82 @@
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
/*
+ * Test IRadio.setAllowedNetworkTypesBitmap for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setAllowedNetworkTypesBitmap) {
+ serial = GetRandomSerialNumber();
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+ allowedNetworkTypesBitmap{};
+ allowedNetworkTypesBitmap |= ::android::hardware::radio::V1_4::RadioAccessFamily::LTE;
+
+ radio_v1_6->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+ if (getRadioHalCapabilities()) {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
+ } else {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+ ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+ ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+ ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
+ }
+}
+
+/*
+ * Test IRadio.getAllowedNetworkTypesBitmap for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, getAllowedNetworkTypesBitmap) {
+ serial = GetRandomSerialNumber();
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+ allowedNetworkTypesBitmap{};
+ allowedNetworkTypesBitmap |= ::android::hardware::radio::V1_4::RadioAccessFamily::LTE;
+
+ radio_v1_6->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+ if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+ sleep(3); // wait for modem
+ serial = GetRandomSerialNumber();
+ radio_v1_6->getAllowedNetworkTypesBitmap(serial);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+ if (getRadioHalCapabilities()) {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
+ } else {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+ ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+ ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+ ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
+ }
+ }
+}
+
+/*
* Test IRadio.setupDataCall_1_6() for the response returned.
*/
TEST_P(RadioHidlTest_v1_6, setupDataCall_1_6) {
@@ -512,11 +588,11 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
- {::android::hardware::radio::V1_6::RadioError::NONE,
- ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
- ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::SIM_ERR}));
// setSimCardPower_1_6 does not return until the request is handled, and should not trigger
// CardState::ABSENT when turning off power
@@ -534,11 +610,11 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
- {::android::hardware::radio::V1_6::RadioError::NONE,
- ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
- ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+ ::android::hardware::radio::V1_6::RadioError::SIM_ERR}));
// setSimCardPower_1_6 does not return until the request is handled. Just verify that we still
// have CardState::PRESENT after turning the power back on
@@ -821,7 +897,7 @@
/*
* Test IRadio.updateSimPhonebookRecords() for the response returned.
*/
-TEST_F(RadioHidlTest_v1_6, updateSimPhonebookRecords) {
+TEST_P(RadioHidlTest_v1_6, updateSimPhonebookRecords) {
serial = GetRandomSerialNumber();
radio_v1_6->getSimPhonebookCapacity(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -851,7 +927,11 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
- EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED},
+ CHECK_GENERAL_ERROR));
if(pbCapacity.maxAdnRecords > 0
&& pbCapacity.usedAdnRecords < pbCapacity.maxAdnRecords) {
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index b1e679b..e1b9f56 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -1172,10 +1172,13 @@
}
Return<void> RadioResponse_v1_6::getAllowedNetworkTypesBitmapResponse(
- const ::android::hardware::radio::V1_6::RadioResponseInfo& /*info*/,
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
const ::android::hardware::hidl_bitfield<
::android::hardware::radio::V1_4::RadioAccessFamily>
- /*networkTypeBitmap*/) {
+ networkTypeBitmap) {
+ rspInfo = info;
+ networkTypeBitmapResponse = networkTypeBitmap;
+ parent_v1_6.notify(info.serial);
return Void();
}
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 0c11f3b..3796847 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -30,6 +30,10 @@
},
rust: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ ],
},
},
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index 3ea14a1..b0761bf 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -37,10 +37,19 @@
* ? "board" : tstr,
* ? "vb_state" : "green" / "yellow" / "orange", // Taken from the AVB values
* ? "bootloader_state" : "locked" / "unlocked", // Taken from the AVB values
+ * ? "vbmeta_digest": bstr, // Taken from the AVB values
* ? "os_version" : tstr, // Same as android.os.Build.VERSION.release
* ? "system_patch_level" : uint, // YYYYMMDD
* ? "boot_patch_level" : uint, // YYYYMMDD
* ? "vendor_patch_level" : uint, // YYYYMMDD
+ * "version" : 1, // The CDDL schema version.
+ * "security_level" : "tee" / "strongbox"
+ * "att_id_state": "locked" / "open", // Attestation IDs State. If "locked", this
+ * // indicates a device's attestable IDs are
+ * // factory-locked and immutable. If "open",
+ * // this indicates the device is still in a
+ * // provisionable state and the attestable IDs
+ * // are not yet frozen.
* }
*/
byte[] deviceInfo;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 5b0b303..1849723 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -233,8 +233,6 @@
* indistinguishable from random. Thus, if the entropy from any source is good, the output
* must be good.
*
- * TODO(seleneh) specify what mixing functions and cprng we allow.
- *
* @param data Bytes to be mixed into the CRNG seed. The caller must not provide more than 2
* KiB of data per invocation.
*
@@ -277,6 +275,10 @@
* must return ErrorCode::INVALID_ARGUMENT. The values 3 and 65537 must be supported. It is
* recommended to support all prime values up to 2^64.
*
+ * o Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER specify the valid date range for
+ * the returned X.509 certificate holding the public key. If omitted, generateKey must return
+ * ErrorCode::MISSING_NOT_BEFORE or ErrorCode::MISSING_NOT_AFTER.
+ *
* The following parameters are not necessary to generate a usable RSA key, but generateKey must
* not return an error if they are omitted:
*
@@ -297,6 +299,10 @@
* Tag::EC_CURVE must be provided to generate an ECDSA key. If it is not provided, generateKey
* must return ErrorCode::UNSUPPORTED_KEY_SIZE. TEE IKeyMintDevice implementations must support
* all curves. StrongBox implementations must support P_256.
+
+ * Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER must be provided to specify the
+ * valid date range for the returned X.509 certificate holding the public key. If omitted,
+ * generateKey must return ErrorCode::MISSING_NOT_BEFORE or ErrorCode::MISSING_NOT_AFTER.
*
* == AES Keys ==
*
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 04d91d0..a29fb08 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -33,8 +33,8 @@
*
* 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
+ * COSE_Key representations of the public keys. The "root" of the BCC is
+ * 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.
@@ -58,12 +58,8 @@
* (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.
+ * can know or predict the post-update key pairs. It is recommended and expected that the BCC is
+ * constructed using the Open Profile for DICE.
*
* 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
@@ -78,7 +74,7 @@
* 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 appropriate solution for devices which haven't implemented
+ * 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.
*
@@ -141,7 +137,7 @@
* 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.
+ * but note that specific services may define a required format. KeyMint does.
*/
byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
@@ -162,65 +158,90 @@
* 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
+ * @param in endpointEncryptionKey contains an X22519 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.
+ * chain. The root is self-signed. An implementor may also choose to use P256 as an
+ * alternative curve for signing and encryption instead of Curve 25519.
*
* EekChain = [ + SignedSignatureKey, SignedEek ]
*
* SignedSignatureKey = [ // COSE_Sign1
* protected: bstr .cbor {
- * 1 : -8, // Algorithm : EdDSA
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
- * unprotected: { },
- * payload: bstr .cbor SignatureKey,
- * signature: bstr PureEd25519(.cbor SignatureKeySignatureInput)
+ * unprotected: {},
+ * payload: bstr .cbor SignatureKeyEd25519 /
+ * bstr .cbor SignatureKeyP256,
+ * signature: bstr PureEd25519(.cbor SignatureKeySignatureInput) /
+ * bstr ECDSA(.cbor SignatureKeySignatureInput)
* ]
*
- * SignatureKey = { // COSE_Key
+ * SignatureKeyEd25519 = { // COSE_Key
* 1 : 1, // Key type : Octet Key Pair
- * 3 : -8, // Algorithm : EdDSA
+ * 3 : AlgorithmEdDSA, // Algorithm
* -1 : 6, // Curve : Ed25519
* -2 : bstr // Ed25519 public key
* }
*
+ * SignatureKeyP256 = {
+ * 1 : 2, // Key type : EC2
+ * 3 : AlgorithmES256, // Algorithm
+ * -1 : 1, // Curve: P256
+ * -2 : bstr, // X coordinate
+ * -3 : bstr // Y coordinate
+ * }
+ *
* SignatureKeySignatureInput = [
* context: "Signature1",
* body_protected: bstr .cbor {
- * 1 : -8, // Algorithm : EdDSA
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
* external_aad: bstr .size 0,
- * payload: bstr .cbor SignatureKey
+ * payload: bstr .cbor SignatureKeyEd25519 /
+ * bstr .cbor SignatureKeyP256
* ]
*
* SignedEek = [ // COSE_Sign1
* protected: bstr .cbor {
- * 1 : -8, // Algorithm : EdDSA
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
- * unprotected: { },
- * payload: bstr .cbor Eek,
- * signature: bstr PureEd25519(.cbor EekSignatureInput)
+ * unprotected: {},
+ * payload: bstr .cbor EekX25519 / .cbor EekP256,
+ * signature: bstr PureEd25519(.cbor EekSignatureInput) /
+ * bstr ECDSA(.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 // X25519 public key
+ * EekX25519 = { // 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
+ * }
+ *
+ * EekP256 = { // COSE_Key
+ * 1 : 2, // Key type : EC2
+ * 2 : bstr // KID : EEK ID
+ * 3 : -25, // Algorithm : ECDH-ES + HKDF-256
+ * -1 : 1, // Curve : P256
+ * -2 : bstr // Sender X coordinate
+ * -3 : bstr // Sender Y coordinate
* }
*
* EekSignatureInput = [
* context: "Signature1",
* body_protected: bstr .cbor {
- * 1 : -8, // Algorithm : EdDSA
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
* external_aad: bstr .size 0,
- * payload: bstr .cbor Eek
+ * payload: bstr .cbor EekX25519 / .cbor EekP256
* ]
*
+ * AlgorithmES256 = -7
+ * AlgorithmEdDSA = -8
+ *
* If the contents of endpointEncryptionKey do not match the SignedEek structure above,
* the method must return STATUS_INVALID_EEK.
*
@@ -228,7 +249,7 @@
* 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 certificate is in its pre-configured set of
+ * 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.
*
@@ -236,8 +257,13 @@
* 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:
+ * @param out DeviceInfo contains the VerifiedDeviceInfo portion of the DeviceInfo array in
+ * CertificateRequest. The structure is described within the DeviceInfo.aidl file.
+ *
+ * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument).
+ *
+ * @return The of KeysToSign in the CertificateRequest structure. Specifically, it contains:
*
* HMAC-256(EK_mac, .cbor KeysToMacStructure)
*
@@ -248,11 +274,11 @@
* protected : bstr .cbor {
* 1 : 5, // Algorithm : HMAC-256
* },
- * unprotected : { },
+ * unprotected : {},
* // Payload is PublicKeys from keysToSign argument, in provided order.
* payload: bstr .cbor [ * PublicKey ],
* tag: bstr
- * ]
+ * ]
*
* KeysToMacStructure = [
* context : "MAC0",
@@ -261,9 +287,6 @@
* // 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).
*/
byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
index 25fdee3..f0df048 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
@@ -32,6 +32,17 @@
*/
@VintfStability
parcelable KeyCharacteristics {
+ /**
+ * The security level enforcing this collection of key properties.
+ */
SecurityLevel securityLevel = SecurityLevel.SOFTWARE;
+
+ /**
+ * `authorizations` is a list of key properties that are enforced at this security level.
+ * A key can have different properties enforced by components of different security levels.
+ * For example, some properties are provided by the operating system, which has a
+ * different security level to the IKeyMintDevice.
+ * See the `keyCharacteristics` field in `KeyCreationResult` for more details.
+ */
KeyParameter[] authorizations;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index f93dbba..fd6bf65 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -159,18 +159,17 @@
* purpose [1] EXPLICIT SET OF INTEGER OPTIONAL,
* algorithm [2] EXPLICIT INTEGER OPTIONAL,
* keySize [3] EXPLICIT INTEGER OPTIONAL,
- * blockMode [4] EXPLICIT SET OF INTEGER OPTIONAL,
* digest [5] EXPLICIT SET OF INTEGER OPTIONAL,
* padding [6] EXPLICIT SET OF INTEGER OPTIONAL,
- * callerNonce [7] EXPLICIT NULL OPTIONAL,
- * minMacLength [8] EXPLICIT INTEGER OPTIONAL,
* ecCurve [10] EXPLICIT INTEGER OPTIONAL,
* rsaPublicExponent [200] EXPLICIT INTEGER OPTIONAL,
+ * mgfDigest [203] EXPLICIT SET OF INTEGER OPTIONAL,
* rollbackResistance [303] EXPLICIT NULL OPTIONAL,
+ * earlyBootOnly [305] EXPLICIT NULL OPTIONAL,
* activeDateTime [400] EXPLICIT INTEGER OPTIONAL,
* originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL,
* usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL,
- * userSecureId [502] EXPLICIT INTEGER OPTIONAL,
+ * usageCountLimit [405] EXPLICIT INTEGER OPTIONAL,
* noAuthRequired [503] EXPLICIT NULL OPTIONAL,
* userAuthType [504] EXPLICIT INTEGER OPTIONAL,
* authTimeout [505] EXPLICIT INTEGER OPTIONAL,
@@ -194,6 +193,7 @@
* attestationIdModel [717] EXPLICIT OCTET_STRING OPTIONAL,
* vendorPatchLevel [718] EXPLICIT INTEGER OPTIONAL,
* bootPatchLevel [719] EXPLICIT INTEGER OPTIONAL,
+ * deviceUniqueAttestation [720] EXPLICIT NULL OPTIONAL,
* }
*/
Certificate[] certificateChain;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
index 8da7578..b82dee6 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -29,7 +29,6 @@
* Implementation version of the keymint hardware. The version number is implementation
* defined, and not necessarily globally meaningful. The version is used to distinguish
* between different versions of a given implementation.
- * TODO(seleneh) add the version related info to the code.
*/
int versionNumber;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index fbb373b..e71a9c9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -17,8 +17,6 @@
package android.hardware.security.keymint;
/**
- * TODO(seleneh) update the description.
- *
* Padding modes that may be applied to plaintext for encryption operations. This list includes
* padding modes for both symmetric and asymmetric algorithms. Note that implementations should not
* provide all possible combinations of algorithm and padding, only the
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
index 5199062..24cdbc1 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -40,11 +40,7 @@
* 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
- * }
+ * -1 : PubKeyX25519 / PubKeyEcdhP256 // Of the sender
* 4 : bstr, // KID : EEK ID
* },
* ciphertext : nil
@@ -67,7 +63,7 @@
* other : bstr // EEK pubkey
* ],
* SuppPubInfo : [
- * 128, // Output key length
+ * 256, // Output key length
* protected : bstr .size 0
* ]
* ]
@@ -75,34 +71,51 @@
* ProtectedDataPayload [
* SignedMac,
* Bcc,
+ * ? AdditionalDKSignatures,
+ * ]
+ * AdditionalDKSignatures = {
+ * + SignerName => DKCertChain
+ * }
+ *
+ * SignerName = tstr
+ *
+ * DKCertChain = [
+ * 2* Certificate // Root -> Leaf. Root is the vendor
+ * // self-signed cert, leaf contains DK_pub
* ]
*
- * SignedMac = [ // COSE_Sign1
- * bstr .cbor { // Protected params
- * 1 : -8, // Algorithm : EdDSA
+ * Certificate = COSE_Sign1 of a public key
+ *
+ * SignedMac = [ // COSE_Sign1
+ * bstr .cbor { // Protected params
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
- * { }, // Unprotected params
+ * {}, // Unprotected params
* bstr .size 32, // MAC key
- * bstr PureEd25519(DK_priv, .cbor SignedMac_structure)
+ * bstr PureEd25519(KM_priv, .cbor SignedMac_structure) /
+ * ECDSA(KM_priv, bstr .cbor SignedMac_structure)
* ]
*
* SignedMac_structure = [
* "Signature1",
- * bstr .cbor { // Protected params
- * 1 : -8, // Algorithm : EdDSA
+ * bstr .cbor { // Protected params
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
* bstr .cbor SignedMacAad
- * bstr .size 32 // MAC key
+ * bstr .size 32 // MAC key
* ]
*
* SignedMacAad = [
* challenge : bstr,
- * DeviceInfo
+ * VerifiedDeviceInfo,
+ * tag: bstr // This is the tag from COSE_Mac0 of
+ * // KeysToCertify, to tie the key set to
+ * // the signature.
* ]
*
* Bcc = [
- * PubKey, // DK_pub
- * + BccEntry, // Root -> leaf (KM_pub)
+ * PubKeyEd25519 / PubKeyECDSA256, // DK_pub
+ * + BccEntry, // Root -> leaf (KM_pub)
* ]
*
* BccPayload = { // CWT
@@ -120,51 +133,65 @@
* ? -4670549 : bstr, // Authority Hash
* ? -4670550 : bstr, // Authority Descriptor
* ? -4670551 : bstr, // Mode
- * -4670552 : bstr .cbor PubKey // Subject Public Key
+ * -4670552 : bstr .cbor PubKeyEd25519 /
+ * bstr .cbor PubKeyECDSA256 // Subject Public Key
* -4670553 : bstr // Key Usage
* }
*
- * BccEntry = [ // COSE_Sign1
- * protected: bstr .cbor {
- * 1 : -8, // Algorithm : EdDSA
+ * BccEntry = [ // COSE_Sign1 (untagged)
+ * protected : bstr .cbor {
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
- * unprotected: { },
+ * unprotected: {},
* 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)
+ * signature: bstr .cbor PureEd25519(SigningKey, bstr .cbor BccEntryInput) /
+ * bstr .cbor ECDSA(SigningKey, bstr .cbor BccEntryInput)
+ * // See RFC 8032 for details of how to encode the signature value for Ed25519.
* ]
*
- * 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
+ * 1 : AlgorithmEdDSA / AlgorithmES256, // Algorithm
* },
* 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
+ * VerifiedDeviceInfo = DeviceInfo // See DeviceInfo.aidl
+ *
+ * PubKeyX25519 = { // COSE_Key
+ * 1 : 1, // Key type : Octet Key Pair
+ * -1 : 4, // Curve : X25519
+ * -2 : bstr // Sender X25519 public key
* }
+ *
+ * PubKeyEd25519 = { // COSE_Key
+ * 1 : 1, // Key type : octet key pair
+ * 3 : AlgorithmEdDSA, // Algorithm : EdDSA
+ * 4 : 2, // Ops: Verify
+ * -1 : 6, // Curve : Ed25519
+ * -2 : bstr // X coordinate, little-endian
+ * }
+ *
+ * PubKeyEcdhP256 = { // COSE_Key
+ * 1 : 2, // Key type : EC2
+ * -1 : 1, // Curve : P256
+ * -2 : bstr // Sender X coordinate
+ * -3 : bstr // Sender Y coordinate
+ * }
+ *
+ * PubKeyECDSA256 = { // COSE_Key
+ * 1 : 2, // Key type : EC2
+ * 3 : AlgorithmES256, // Algorithm : ECDSA w/ SHA-256
+ * 4 : 2, // Ops: Verify
+ * -1 : 1, // Curve: P256
+ * -2 : bstr, // X coordinate
+ * -3 : bstr // Y coordinate
+ * }
+ *
+ * AlgorithmES256 = -7
+ * AlgorithmEdDSA = -8
*/
byte[] protectedData;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 4ff4574..b28ebcb 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -18,10 +18,6 @@
import android.hardware.security.keymint.TagType;
-// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as
-// ROOT_OF_TRUST = TagType:BYTES | 704. So we are forced to write definitions as
-// ROOT_OF_TRUST = (9 << 28) for now. Will need to flip this back later when aidl support is added.
-
/**
* Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of
* data are stored in KeyParameter.
@@ -33,7 +29,7 @@
/**
* Tag::INVALID should never be set. It means you hit an error.
*/
- INVALID = (0 << 28) | 0,
+ INVALID = 0,
/**
* Tag::PURPOSE specifies the set of purposes for which the key may be used. Possible values
@@ -47,7 +43,7 @@
*
* Must be hardware-enforced.
*/
- PURPOSE = (2 << 28) /* TagType:ENUM_REP */ | 1,
+ PURPOSE = TagType.ENUM_REP | 1,
/**
* Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used. This tag
@@ -56,7 +52,7 @@
*
* Must be hardware-enforced.
*/
- ALGORITHM = (1 << 28) /* TagType:ENUM */ | 2,
+ ALGORITHM = TagType.ENUM | 2,
/**
* Tag::KEY_SIZE specifies the size, in bits, of the key, measuring in the normal way for the
@@ -68,7 +64,7 @@
*
* Must be hardware-enforced.
*/
- KEY_SIZE = (3 << 28) /* TagType:UINT */ | 3,
+ KEY_SIZE = TagType.UINT | 3,
/**
* Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used. This tag
@@ -81,7 +77,7 @@
*
* Must be hardware-enforced.
*/
- BLOCK_MODE = (2 << 28) /* TagType:ENUM_REP */ | 4,
+ BLOCK_MODE = TagType.ENUM_REP | 4,
/**
* Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
@@ -95,7 +91,7 @@
*
* Must be hardware-enforced.
*/
- DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 5,
+ DIGEST = TagType.ENUM_REP | 5,
/**
* Tag::PADDING specifies the padding modes that may be used with the key. This tag is relevant
@@ -123,7 +119,7 @@
*
* Must be hardware-enforced.
*/
- PADDING = (2 << 28) /* TagType:ENUM_REP */ | 6,
+ PADDING = TagType.ENUM_REP | 6,
/**
* Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring
@@ -136,7 +132,7 @@
*
* Must be hardware-enforced.
*/
- CALLER_NONCE = (7 << 28) /* TagType:BOOL */ | 7,
+ CALLER_NONCE = TagType.BOOL | 7,
/**
* Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified
@@ -149,7 +145,7 @@
*
* Must be hardware-enforced.
*/
- MIN_MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 8,
+ MIN_MAC_LENGTH = TagType.UINT | 8,
// Tag 9 reserved
@@ -159,7 +155,7 @@
*
* Must be hardware-enforced.
*/
- EC_CURVE = (1 << 28) /* TagType:ENUM */ | 10,
+ EC_CURVE = TagType.ENUM | 10,
/**
* Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair.
@@ -173,7 +169,7 @@
*
* Must be hardware-enforced.
*/
- RSA_PUBLIC_EXPONENT = (5 << 28) /* TagType:ULONG */ | 200,
+ RSA_PUBLIC_EXPONENT = TagType.ULONG | 200,
// Tag 201 reserved
@@ -184,7 +180,7 @@
*
* Must be hardware-enforced.
*/
- INCLUDE_UNIQUE_ID = (7 << 28) /* TagType:BOOL */ | 202,
+ INCLUDE_UNIQUE_ID = TagType.BOOL | 202,
/**
* Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
@@ -197,7 +193,7 @@
*
* Must be hardware-enforced.
*/
- RSA_OAEP_MGF_DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 203,
+ RSA_OAEP_MGF_DIGEST = TagType.ENUM_REP | 203,
// Tag 301 reserved
@@ -209,7 +205,7 @@
*
* Must be hardware-enforced.
*/
- BOOTLOADER_ONLY = (7 << 28) /* TagType:BOOL */ | 302,
+ BOOTLOADER_ONLY = TagType.BOOL | 302,
/**
* Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when
@@ -224,10 +220,10 @@
*
* Must be hardware-enforced.
*/
- ROLLBACK_RESISTANCE = (7 << 28) /* TagType:BOOL */ | 303,
+ ROLLBACK_RESISTANCE = TagType.BOOL | 303,
// Reserved for future use.
- HARDWARE_TYPE = (1 << 28) /* TagType:ENUM */ | 304,
+ HARDWARE_TYPE = TagType.ENUM | 304,
/**
* Keys tagged with EARLY_BOOT_ONLY may only be used during early boot, until
@@ -236,7 +232,7 @@
* provided to IKeyMintDevice::importKey, the import must fail with
* ErrorCode::EARLY_BOOT_ENDED.
*/
- EARLY_BOOT_ONLY = (7 << 28) /* TagType:BOOL */ | 305,
+ EARLY_BOOT_ONLY = TagType.BOOL | 305,
/**
* Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in
@@ -245,7 +241,7 @@
*
* Need not be hardware-enforced.
*/
- ACTIVE_DATETIME = (6 << 28) /* TagType:DATE */ | 400,
+ ACTIVE_DATETIME = TagType.DATE | 400,
/**
* Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -257,7 +253,7 @@
*
* Need not be hardware-enforced.
*/
- ORIGINATION_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 401,
+ ORIGINATION_EXPIRE_DATETIME = TagType.DATE | 401,
/**
* Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -269,13 +265,9 @@
*
* Need not be hardware-enforced.
*/
- USAGE_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 402,
+ USAGE_EXPIRE_DATETIME = TagType.DATE | 402,
/**
- * TODO(seleneh) this tag need to be deleted.
- *
- * TODO(seleneh) this tag need to be deleted.
- *
* Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between
* allowed operations using a key. This can be used to rate-limit uses of keys in contexts
* where unlimited use may enable brute force attacks.
@@ -293,8 +285,10 @@
* fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
*
* Must be hardware-enforced.
+ *
+ * TODO(b/191738660): Remove in KeyMint V2. Currently only used for FDE.
*/
- MIN_SECONDS_BETWEEN_OPS = (3 << 28) /* TagType:UINT */ | 403,
+ MIN_SECONDS_BETWEEN_OPS = TagType.UINT | 403,
/**
* Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between
@@ -314,7 +308,7 @@
*
* Must be hardware-enforced.
*/
- MAX_USES_PER_BOOT = (3 << 28) /* TagType:UINT */ | 404,
+ MAX_USES_PER_BOOT = TagType.UINT | 404,
/**
* Tag::USAGE_COUNT_LIMIT specifies the number of times that a key may be used. This can be
@@ -343,14 +337,14 @@
* record. This tag must have the same SecurityLevel as the tag that is added to the key
* characteristics.
*/
- USAGE_COUNT_LIMIT = (3 << 28) | 405, /* TagType:UINT */
+ USAGE_COUNT_LIMIT = TagType.UINT | 405,
/**
* Tag::USER_ID specifies the ID of the Android user that is permitted to use the key.
*
* Must not be hardware-enforced.
*/
- USER_ID = (3 << 28) /* TagType:UINT */ | 501,
+ USER_ID = TagType.UINT | 501,
/**
* Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user
@@ -383,7 +377,7 @@
*
* Must be hardware-enforced.
*/
- USER_SECURE_ID = (10 << 28) /* TagType:ULONG_REP */ | 502,
+ USER_SECURE_ID = TagType.ULONG_REP | 502,
/**
* Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key. This tag
@@ -391,7 +385,7 @@
*
* Must be hardware-enforced.
*/
- NO_AUTH_REQUIRED = (7 << 28) /* TagType:BOOL */ | 503,
+ NO_AUTH_REQUIRED = TagType.BOOL | 503,
/**
* Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize
@@ -410,7 +404,7 @@
*
* Must be hardware-enforced.
*/
- USER_AUTH_TYPE = (1 << 28) /* TagType:ENUM */ | 504,
+ USER_AUTH_TYPE = TagType.ENUM | 504,
/**
* Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
@@ -424,7 +418,7 @@
*
* Must be hardware-enforced.
*/
- AUTH_TIMEOUT = (3 << 28) /* TagType:UINT */ | 505,
+ AUTH_TIMEOUT = TagType.UINT | 505,
/**
* Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if
@@ -432,7 +426,7 @@
*
* Cannot be hardware-enforced.
*/
- ALLOW_WHILE_ON_BODY = (7 << 28) /* TagType:BOOL */ | 506,
+ ALLOW_WHILE_ON_BODY = TagType.BOOL | 506,
/**
* TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
@@ -479,29 +473,31 @@
*
* Must be hardware-enforced.
*/
- TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 507,
+ TRUSTED_USER_PRESENCE_REQUIRED = TagType.BOOL | 507,
/**
* Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
- * specifies that this key must not be usable unless the user provides confirmation of the data
- * to be signed. Confirmation is proven to keyMint via an approval token. See
- * CONFIRMATION_TOKEN, as well as the ConfirmationUI HAL.
+ * specifies that this key must not be usable unless the user provides confirmation of the data
+ * to be signed. Confirmation is proven to keyMint via an approval token. See the authToken
+ * parameter of begin(), as well as the ConfirmationUI HAL.
*
* If an attempt to use a key with this tag does not have a cryptographically valid
- * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
+ * token provided to finish() or if the data provided to update()/finish() does not
* match the data described in the token, keyMint must return NO_USER_CONFIRMATION.
*
* Must be hardware-enforced.
*/
- TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) /* TagType:BOOL */ | 508,
+ TRUSTED_CONFIRMATION_REQUIRED = TagType.BOOL | 508,
/**
* Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
- * unlocked.
+ * unlocked, as reported to KeyMint via authToken operation parameter and the
+ * IKeyMintDevice::deviceLocked() method
*
- * Must be software-enforced.
+ * Must be hardware-enforced (but is also keystore-enforced on a per-user basis: see the
+ * deviceLocked() documentation).
*/
- UNLOCKED_DEVICE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 509,
+ UNLOCKED_DEVICE_REQUIRED = TagType.BOOL | 509,
/**
* Tag::APPLICATION_ID. When provided to generateKey or importKey, this tag specifies data
@@ -517,7 +513,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 601,
+ APPLICATION_ID = TagType.BYTES | 601,
/*
* Semantically unenforceable tags, either because they have no specific meaning or because
@@ -538,7 +534,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- APPLICATION_DATA = (9 << 28) /* TagType:BYTES */ | 700,
+ APPLICATION_DATA = TagType.BYTES | 700,
/**
* Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
@@ -546,7 +542,7 @@
*
* Must be in the software-enforced list, if provided.
*/
- CREATION_DATETIME = (6 << 28) /* TagType:DATE */ | 701,
+ CREATION_DATETIME = TagType.DATE | 701,
/**
* Tag::ORIGIN specifies where the key was created, if known. This tag must not be specified
@@ -555,7 +551,7 @@
*
* Must be hardware-enforced.
*/
- ORIGIN = (1 << 28) /* TagType:ENUM */ | 702,
+ ORIGIN = TagType.ENUM | 702,
// 703 is unused.
@@ -567,7 +563,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ROOT_OF_TRUST = (9 << 28) /* TagType:BYTES */ | 704,
+ ROOT_OF_TRUST = TagType.BYTES | 704,
/**
* Tag::OS_VERSION specifies the system OS version with which the key may be used. This tag is
@@ -590,7 +586,7 @@
*
* Must be hardware-enforced.
*/
- OS_VERSION = (3 << 28) /* TagType:UINT */ | 705,
+ OS_VERSION = TagType.UINT | 705,
/**
* Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
@@ -611,7 +607,7 @@
*
* Must be hardware-enforced.
*/
- OS_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 706,
+ OS_PATCHLEVEL = TagType.UINT | 706,
/**
* Tag::UNIQUE_ID specifies a unique, time-based identifier. This tag is never provided to or
@@ -646,7 +642,7 @@
*
* Must be hardware-enforced.
*/
- UNIQUE_ID = (9 << 28) /* TagType:BYTES */ | 707,
+ UNIQUE_ID = TagType.BYTES | 707,
/**
* Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attested key
@@ -655,7 +651,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_CHALLENGE = (9 << 28) /* TagType:BYTES */ | 708,
+ ATTESTATION_CHALLENGE = TagType.BYTES | 708,
/**
* Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
@@ -681,7 +677,7 @@
*
* Cannot be hardware-enforced.
*/
- ATTESTATION_APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 709,
+ ATTESTATION_APPLICATION_ID = TagType.BYTES | 709,
/**
* Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
@@ -694,7 +690,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_BRAND = (9 << 28) /* TagType:BYTES */ | 710,
+ ATTESTATION_ID_BRAND = TagType.BYTES | 710,
/**
* Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
@@ -707,7 +703,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_DEVICE = (9 << 28) /* TagType:BYTES */ | 711,
+ ATTESTATION_ID_DEVICE = TagType.BYTES | 711,
/**
* Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
@@ -720,7 +716,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_PRODUCT = (9 << 28) /* TagType:BYTES */ | 712,
+ ATTESTATION_ID_PRODUCT = TagType.BYTES | 712,
/**
* Tag::ATTESTATION_ID_SERIAL the device's serial number. This field must be set only when
@@ -732,7 +728,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_SERIAL = (9 << 28) /* TagType:BYTES */ | 713,
+ ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
/**
* Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
@@ -745,7 +741,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_IMEI = (9 << 28) /* TagType:BYTES */ | 714,
+ ATTESTATION_ID_IMEI = TagType.BYTES | 714,
/**
* Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attested key
@@ -758,7 +754,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_MEID = (9 << 28) /* TagType:BYTES */ | 715,
+ ATTESTATION_ID_MEID = TagType.BYTES | 715,
/**
* Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
@@ -771,7 +767,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_MANUFACTURER = (9 << 28) /* TagType:BYTES */ | 716,
+ ATTESTATION_ID_MANUFACTURER = TagType.BYTES | 716,
/**
* Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
@@ -784,7 +780,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- ATTESTATION_ID_MODEL = (9 << 28) /* TagType:BYTES */ | 717,
+ ATTESTATION_ID_MODEL = TagType.BYTES | 717,
/**
* Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
@@ -806,7 +802,7 @@
*
* Must be hardware-enforced.
*/
- VENDOR_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 718,
+ VENDOR_PATCHLEVEL = TagType.UINT | 718,
/**
* Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the
@@ -826,23 +822,44 @@
*
* Must be hardware-enforced.
*/
- BOOT_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 719,
+ BOOT_PATCHLEVEL = TagType.UINT | 719,
/**
* DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attested key generation/import
* operations. It indicates that attestation using a device-unique key is requested, rather
- * than a batch key. When a device-unique key is used, only the attestation certificate is
- * returned; no additional chained certificates are provided. It's up to the caller to
- * recognize the device-unique signing key. Only SecurityLevel::STRONGBOX IKeyMintDevices may
- * support device-unique attestations. SecurityLevel::TRUSTED_ENVIRONMENT IKeyMintDevices must
- * return ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION.
+ * than a batch key. When a device-unique key is used, the returned chain should contain two or
+ * three certificates.
+ *
+ * In case the chain contains two certificates, they should be:
+ * * The attestation certificate, containing the attestation extension, as described in
+ * KeyCreationResult.aidl.
+ * * A self-signed root certificate, signed by the device-unique key.
+ *
+ * In case the chain contains three certificates, they should be:
+ * * The attestation certificate, containing the attestation extension, as described in
+ * KeyCreationResult.aidl, signed by the device-unique key.
+ * * An intermediate certificate, containing the public portion of the device-unique key.
+ * * A self-signed root certificate, signed by a dedicated key, certifying the
+ * intermediate. Ideally, the dedicated key would be the same for all StrongBox
+ * instances of the same manufacturer to ease validation.
+ *
+ * No additional chained certificates are provided. Only SecurityLevel::STRONGBOX
+ * IKeyMintDevices may support device-unique attestations. SecurityLevel::TRUSTED_ENVIRONMENT
+ * IKeyMintDevices must return ErrorCode::INVALID_ARGUMENT if they receive
+ * DEVICE_UNIQUE_ATTESTATION.
* SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and
* return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
*
+ * The caller needs to obtain the device-unique keys out-of-band and compare them against the
+ * key used to sign the self-signed root certificate.
+ * To ease this process, the IKeyMintDevice implementation should include, both in the subject
+ * and issuer fields of the self-signed root, the unique identifier of the device. Using the
+ * unique identifier will make it straightforward for the caller to link a device to its key.
+ *
* IKeyMintDevice implementations that support device-unique attestation MUST add the
* DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
*/
- DEVICE_UNIQUE_ATTESTATION = (7 << 28) /* TagType:BOOL */ | 720,
+ DEVICE_UNIQUE_ATTESTATION = TagType.BOOL | 720,
/**
* IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key
@@ -850,7 +867,7 @@
* attestation. It is used in attestations produced by the IIdentityCredential HAL when that
* HAL attests to Credential Keys. IIdentityCredential produces KeyMint-style attestations.
*/
- IDENTITY_CREDENTIAL_KEY = (7 << 28) /* TagType:BOOL */ | 721,
+ IDENTITY_CREDENTIAL_KEY = TagType.BOOL | 721,
/**
* To prevent keys from being compromised if an attacker acquires read access to system / kernel
@@ -860,19 +877,21 @@
*
* STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
* encryption. Keys of this type can either be generated or imported or secure imported using
- * keyMint. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key
- * wrapped key once the key characteristics are enforced.
+ * keyMint. The convertStorageKeyToEphemeral() method of IKeyMintDevice can be used to re-wrap
+ * storage key with a per-boot ephemeral key wrapped key once the key characteristics are
+ * enforced.
*
* Keys with this tag cannot be used for any operation within keyMint.
* ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
* begin().
*/
- STORAGE_KEY = (7 << 28) /* TagType:BOOL */ | 722,
+ STORAGE_KEY = TagType.BOOL | 722,
/**
- * TODO: Delete when keystore1 is deleted.
+ * OBSOLETE: Do not use. See IKeyMintOperation.updateAad instead.
+ * TODO(b/191738660): Remove in KeyMint v2.
*/
- ASSOCIATED_DATA = (9 << 28) /* TagType:BYTES */ | 1000,
+ ASSOCIATED_DATA = TagType.BYTES | 1000,
/**
* Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
@@ -887,7 +906,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- NONCE = (9 << 28) /* TagType:BYTES */ | 1001,
+ NONCE = TagType.BYTES | 1001,
/**
* Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits.
@@ -898,7 +917,7 @@
*
* Must never appear in KeyCharacteristics.
*/
- MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 1003,
+ MAC_LENGTH = TagType.UINT | 1003,
/**
* Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the
@@ -906,16 +925,15 @@
*
* Must never appear in KeyCharacteristics.
*/
- RESET_SINCE_ID_ROTATION = (7 << 28) /* TagType:BOOL */ | 1004,
+ RESET_SINCE_ID_ROTATION = TagType.BOOL | 1004,
/**
- * Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user
- * confirmed a signing request. The content is a full-length HMAC-SHA256 value. See the
- * ConfirmationUI HAL for details of token computation.
+ * OBSOLETE: Do not use. See the authToken parameter for IKeyMintDevice::begin and for
+ * IKeyMintOperation methods instead.
*
- * Must never appear in KeyCharacteristics.
+ * TODO(b/191738660): Delete when keystore1 is deleted.
*/
- CONFIRMATION_TOKEN = (9 << 28) /* TagType:BYTES */ | 1005,
+ CONFIRMATION_TOKEN = TagType.BYTES | 1005,
/**
* Tag::CERTIFICATE_SERIAL specifies the serial number to be assigned to the attestation
@@ -923,7 +941,7 @@
* keyMint in the attestation parameters during generateKey() and importKey(). If not provided,
* the serial shall default to 1.
*/
- CERTIFICATE_SERIAL = (8 << 28) /* TagType:BIGNUM */ | 1006,
+ CERTIFICATE_SERIAL = TagType.BIGNUM | 1006,
/**
* Tag::CERTIFICATE_SUBJECT the certificate subject. The value is a DER encoded X509 NAME.
@@ -931,7 +949,7 @@
* during generateKey and importKey. If not provided the subject name shall default to
* CN="Android Keystore Key".
*/
- CERTIFICATE_SUBJECT = (9 << 28) /* TagType:BYTES */ | 1007,
+ CERTIFICATE_SUBJECT = TagType.BYTES | 1007,
/**
* Tag::CERTIFICATE_NOT_BEFORE the beginning of the validity of the certificate in UNIX epoch
@@ -939,7 +957,7 @@
* certificates. ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
* this tag is not provided to generateKey or importKey.
*/
- CERTIFICATE_NOT_BEFORE = (6 << 28) /* TagType:DATE */ | 1008,
+ CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
/**
* Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
@@ -947,7 +965,7 @@
* ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
* importKey.
*/
- CERTIFICATE_NOT_AFTER = (6 << 28) /* TagType:DATE */ | 1009,
+ CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
/**
* Tag::MAX_BOOT_LEVEL specifies a maximum boot level at which a key should function.
@@ -958,5 +976,5 @@
*
* Cannot be hardware enforced in this version.
*/
- MAX_BOOT_LEVEL = (3 << 28) /* TagType:UINT */ | 1010,
+ MAX_BOOT_LEVEL = TagType.UINT | 1010,
}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ff08ce6..386029f 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -23,16 +23,11 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_test {
- name: "VtsAidlKeyMintTargetTest",
+cc_defaults {
+ name: "keymint_vts_defaults",
defaults: [
- "VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
- ],
- srcs: [
- "AttestKeyTest.cpp",
- "DeviceUniqueAttestationTest.cpp",
- "KeyMintTest.cpp",
+ "VtsHalTargetTestDefaults",
],
shared_libs: [
"libbinder_ndk",
@@ -43,9 +38,24 @@
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
+ "libjsoncpp",
"libkeymint",
"libkeymint_remote_prov_support",
"libkeymint_support",
+ ],
+}
+
+cc_test {
+ name: "VtsAidlKeyMintTargetTest",
+ defaults: [
+ "keymint_vts_defaults",
+ ],
+ srcs: [
+ "AttestKeyTest.cpp",
+ "DeviceUniqueAttestationTest.cpp",
+ "KeyMintTest.cpp",
+ ],
+ static_libs: [
"libkeymint_vts_test_utils",
],
test_suites: [
@@ -57,8 +67,7 @@
cc_test_library {
name: "libkeymint_vts_test_utils",
defaults: [
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
+ "keymint_vts_defaults",
],
srcs: [
"KeyMintAidlTestBase.cpp",
@@ -66,45 +75,22 @@
export_include_dirs: [
".",
],
- shared_libs: [
- "libbinder_ndk",
- "libcrypto",
- ],
static_libs: [
- "android.hardware.security.keymint-V1-ndk_platform",
- "android.hardware.security.secureclock-V1-ndk_platform",
- "libcppbor_external",
- "libcppcose_rkp",
"libgmock_ndk",
- "libkeymint",
- "libkeymint_remote_prov_support",
- "libkeymint_support",
],
}
cc_test {
name: "VtsHalRemotelyProvisionedComponentTargetTest",
defaults: [
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
+ "keymint_vts_defaults",
],
srcs: [
"VtsRemotelyProvisionedComponentTests.cpp",
],
- shared_libs: [
- "libbinder_ndk",
- "libcrypto",
- ],
static_libs: [
- "android.hardware.security.keymint-V1-ndk_platform",
- "android.hardware.security.secureclock-V1-ndk_platform",
- "libcppbor_external",
- "libcppcose_rkp",
"libgmock_ndk",
"libkeymaster_portable",
- "libkeymint",
- "libkeymint_support",
- "libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
"libpuresoftkeymasterdevice",
],
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index b8699e9..a312723 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -141,11 +141,18 @@
attest_key, &attested_key_blob, &attested_key_characteristics,
&attested_key_cert_chain));
+ // The returned key characteristics will include CREATION_DATETIME (checked below)
+ // in SecurityLevel::KEYSTORE; this will be stripped out in the CheckCharacteristics()
+ // call below, to match what getKeyCharacteristics() returns (which doesn't include
+ // any SecurityLevel::KEYSTORE characteristics).
+ CheckCharacteristics(attested_key_blob, attested_key_characteristics);
+
CheckedDeleteKey(&attested_key_blob);
CheckedDeleteKey(&attest_key.keyBlob);
hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+
// The client-specified CREATION_DATETIME should be in sw_enforced.
// Its presence will also trigger verify_attestation_record() to check that it
// is in the attestation extension with a matching value.
@@ -549,7 +556,7 @@
.EcdsaSigningKey(curve)
.AttestKey()
.SetDefaultValidity(),
- {} /* attestation siging key */, &attest_key.keyBlob,
+ {} /* attestation signing key */, &attest_key.keyBlob,
&attest_key_characteristics, &attest_key_cert_chain));
ASSERT_GT(attest_key_cert_chain.size(), 0);
@@ -633,7 +640,7 @@
ErrorCode::OK,
GenerateKey(
AuthorizationSetBuilder().EcdsaSigningKey(EcCurve::P_256).SetDefaultValidity(),
- {} /* attestation siging key */, &non_attest_key.keyBlob,
+ {} /* attestation signing key */, &non_attest_key.keyBlob,
&non_attest_key_characteristics, &non_attest_key_cert_chain));
ASSERT_GT(non_attest_key_cert_chain.size(), 0);
@@ -655,6 +662,124 @@
&attested_key_cert_chain));
}
+TEST_P(AttestKeyTest, EcdsaAttestationID) {
+ // Create attestation key.
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ ASSERT_GT(attest_key_cert_chain.size(), 0);
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
+
+ // Collection of valid attestation ID tags.
+ auto attestation_id_tags = AuthorizationSetBuilder();
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+ for (const KeyParameter& tag : attestation_id_tags) {
+ SCOPED_TRACE(testing::Message() << "+tag-" << tag);
+ // Use attestation key to sign an ECDSA key, but include an attestation ID field.
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .SetDefaultValidity();
+ builder.push_back(tag);
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ auto result = GenerateKey(builder, attest_key, &attested_key_blob,
+ &attested_key_characteristics, &attested_key_cert_chain);
+ if (result == ErrorCode::CANNOT_ATTEST_IDS) {
+ continue;
+ }
+
+ ASSERT_EQ(result, ErrorCode::OK);
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+
+ // The attested key characteristics will not contain APPLICATION_ID_* fields (their
+ // spec definitions all have "Must never appear in KeyCharacteristics"), but the
+ // attestation extension should contain them, so make sure the extra tag is added.
+ hw_enforced.push_back(tag);
+
+ EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
+ SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+ }
+ CheckedDeleteKey(&attest_key.keyBlob);
+}
+
+TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) {
+ // Create attestation key.
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ ASSERT_GT(attest_key_cert_chain.size(), 0);
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
+
+ // Collection of invalid attestation ID tags.
+ auto attestation_id_tags =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand")
+ .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device")
+ .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product")
+ .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial")
+ .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei")
+ .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid")
+ .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer")
+ .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ for (const KeyParameter& invalid_tag : attestation_id_tags) {
+ SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag);
+
+ // Use attestation key to sign an ECDSA key, but include an invalid
+ // attestation ID field.
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .SetDefaultValidity();
+ builder.push_back(invalid_tag);
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ auto result = GenerateKey(builder, attest_key, &attested_key_blob,
+ &attested_key_characteristics, &attested_key_cert_chain);
+
+ ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+ << "result = " << result;
+ }
+ CheckedDeleteKey(&attest_key.keyBlob);
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index b0f056a..d7abf07 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -29,7 +29,7 @@
protected:
void CheckUniqueAttestationResults(const vector<uint8_t>& key_blob,
const vector<KeyCharacteristics>& key_characteristics,
- const AuthorizationSet& hw_enforced, int key_size) {
+ const AuthorizationSet& hw_enforced) {
ASSERT_GT(cert_chain_.size(), 0);
if (KeyMintAidlTestBase::dump_Attestations) {
@@ -40,10 +40,16 @@
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) << "Key size missing";
-
- EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
- ASSERT_GT(cert_chain_.size(), 0);
+ // The device-unique attestation chain should contain exactly three certificates:
+ // * The leaf with the attestation extension.
+ // * An intermediate, signing the leaf using the device-unique key.
+ // * A self-signed root, signed using some authority's key, certifying
+ // the device-unique key.
+ const size_t chain_length = cert_chain_.size();
+ ASSERT_TRUE(chain_length == 2 || chain_length == 3);
+ // TODO(b/191361618): Once StrongBox implementations use a correctly-issued
+ // certificate chain, do not skip issuers matching.
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_, /* strict_issuer_check= */ false));
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
@@ -133,17 +139,32 @@
ASSERT_EQ(ErrorCode::OK, result);
- AuthorizationSet hw_enforced = AuthorizationSetBuilder()
- .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaSigningKey(2048, 65537)
- .Digest(Digest::SHA_2_256)
- .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
- .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
- .Authorization(TAG_OS_VERSION, os_version())
- .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+ AuthorizationSetBuilder hw_enforced =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
- CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+ // Any patchlevels attached to the key should also be present in the attestation extension.
+ AuthorizationSet auths;
+ for (const auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+ if (vendor_pl) {
+ hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+ }
+ auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+ if (boot_pl) {
+ hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+ }
+
+ CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
}
/*
@@ -157,11 +178,10 @@
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
- int key_size = 256;
auto result = GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::SHA_2_256)
.Authorization(TAG_INCLUDE_UNIQUE_ID)
.AttestationChallenge("challenge")
@@ -173,17 +193,137 @@
if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
ASSERT_EQ(ErrorCode::OK, result);
- AuthorizationSet hw_enforced = AuthorizationSetBuilder()
- .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(EcCurve::P_256)
- .Digest(Digest::SHA_2_256)
- .Authorization(TAG_EC_CURVE, EcCurve::P_256)
- .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
- .Authorization(TAG_OS_VERSION, os_version())
- .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+ AuthorizationSetBuilder hw_enforced =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+ // Any patchlevels attached to the key should also be present in the attestation extension.
+ AuthorizationSet auths;
+ for (const auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+ if (vendor_pl) {
+ hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+ }
+ auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+ if (boot_pl) {
+ hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+ }
- CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+ CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationID
+ *
+ * Verifies that device unique attestation can include IDs that do match the
+ * local device.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ // Collection of valid attestation ID tags.
+ auto attestation_id_tags = AuthorizationSetBuilder();
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+ "ro.product.manufacturer");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ for (const KeyParameter& tag : attestation_id_tags) {
+ SCOPED_TRACE(testing::Message() << "+tag-" << tag);
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
+ builder.push_back(tag);
+ auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+
+ // It is optional for Strong box to support DeviceUniqueAttestation.
+ if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
+ ASSERT_EQ(ErrorCode::OK, result);
+
+ AuthorizationSetBuilder hw_enforced =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+ // Expect the specified tag to be present in the attestation extension.
+ hw_enforced.push_back(tag);
+ // Any patchlevels attached to the key should also be present in the attestation extension.
+ AuthorizationSet auths;
+ for (const auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+ if (vendor_pl) {
+ hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+ }
+ auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+ if (boot_pl) {
+ hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+ }
+ CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
+ }
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationMismatchID
+ *
+ * Verifies that device unique attestation rejects attempts to attest to IDs that
+ * don't match the local device.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ // Collection of invalid attestation ID tags.
+ auto attestation_id_tags =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand")
+ .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device")
+ .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product")
+ .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial")
+ .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei")
+ .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid")
+ .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer")
+ .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ for (const KeyParameter& invalid_tag : attestation_id_tags) {
+ SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag);
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
+ // Add the tag that doesn't match the local device's real ID.
+ builder.push_back(invalid_tag);
+ auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+
+ ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG);
+ }
}
INSTANTIATE_KEYMINT_AIDL_TEST(DeviceUniqueAttestationTest);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index a9a67bc..2032411 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -62,6 +62,9 @@
namespace {
+// Invalid value for a patchlevel (which is of form YYYYMMDD).
+const uint32_t kInvalidPatchlevel = 99998877;
+
// Overhead for PKCS#1 v1.5 signature padding of undigested messages. Digested messages have
// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
@@ -126,10 +129,9 @@
// 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::CREATION_DATETIME,
- Tag::EC_CURVE,
- Tag::HARDWARE_TYPE,
- Tag::INCLUDE_UNIQUE_ID,
+ Tag::CREATION_DATETIME,
+ Tag::HARDWARE_TYPE,
+ Tag::INCLUDE_UNIQUE_ID,
};
AuthorizationSet filtered_tags(const AuthorizationSet& set) {
@@ -142,6 +144,15 @@
return filtered;
}
+// Remove any SecurityLevel::KEYSTORE entries from a list of key characteristics.
+void strip_keystore_tags(vector<KeyCharacteristics>* characteristics) {
+ characteristics->erase(std::remove_if(characteristics->begin(), characteristics->end(),
+ [](const auto& entry) {
+ return entry.securityLevel == SecurityLevel::KEYSTORE;
+ }),
+ characteristics->end());
+}
+
string x509NameToStr(X509_NAME* name) {
char* s = X509_NAME_oneline(name, nullptr, 0);
string retval(s);
@@ -154,6 +165,28 @@
bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
bool KeyMintAidlTestBase::dump_Attestations = false;
+uint32_t KeyMintAidlTestBase::boot_patch_level(
+ const vector<KeyCharacteristics>& key_characteristics) {
+ // The boot patchlevel is not available as a property, but should be present
+ // in the key characteristics of any created key.
+ AuthorizationSet allAuths;
+ for (auto& entry : key_characteristics) {
+ allAuths.push_back(AuthorizationSet(entry.authorizations));
+ }
+ auto patchlevel = allAuths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+ if (patchlevel.has_value()) {
+ return patchlevel.value();
+ } else {
+ // No boot patchlevel is available. Return a value that won't match anything
+ // and so will trigger test failures.
+ return kInvalidPatchlevel;
+ }
+}
+
+uint32_t KeyMintAidlTestBase::boot_patch_level() {
+ return boot_patch_level(key_characteristics_);
+}
+
ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
if (result.isOk()) return ErrorCode::OK;
@@ -320,6 +353,65 @@
return GetReturnErrorCode(result);
}
+ErrorCode KeyMintAidlTestBase::GetCharacteristics(const vector<uint8_t>& key_blob,
+ const vector<uint8_t>& app_id,
+ const vector<uint8_t>& app_data,
+ vector<KeyCharacteristics>* key_characteristics) {
+ Status result =
+ keymint_->getKeyCharacteristics(key_blob, app_id, app_data, key_characteristics);
+ return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::GetCharacteristics(const vector<uint8_t>& key_blob,
+ vector<KeyCharacteristics>* key_characteristics) {
+ vector<uint8_t> empty_app_id, empty_app_data;
+ return GetCharacteristics(key_blob, empty_app_id, empty_app_data, key_characteristics);
+}
+
+void KeyMintAidlTestBase::CheckCharacteristics(
+ const vector<uint8_t>& key_blob,
+ const vector<KeyCharacteristics>& generate_characteristics) {
+ // Any key characteristics that were in SecurityLevel::KEYSTORE when returned from
+ // generateKey() should be excluded, as KeyMint will have no record of them.
+ // This applies to CREATION_DATETIME in particular.
+ vector<KeyCharacteristics> expected_characteristics(generate_characteristics);
+ strip_keystore_tags(&expected_characteristics);
+
+ vector<KeyCharacteristics> retrieved;
+ ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, &retrieved));
+ EXPECT_EQ(expected_characteristics, retrieved);
+}
+
+void KeyMintAidlTestBase::CheckAppIdCharacteristics(
+ const vector<uint8_t>& key_blob, std::string_view app_id_string,
+ std::string_view app_data_string,
+ const vector<KeyCharacteristics>& generate_characteristics) {
+ // Exclude any SecurityLevel::KEYSTORE characteristics for comparisons.
+ vector<KeyCharacteristics> expected_characteristics(generate_characteristics);
+ strip_keystore_tags(&expected_characteristics);
+
+ vector<uint8_t> app_id(app_id_string.begin(), app_id_string.end());
+ vector<uint8_t> app_data(app_data_string.begin(), app_data_string.end());
+ vector<KeyCharacteristics> retrieved;
+ ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, app_id, app_data, &retrieved));
+ EXPECT_EQ(expected_characteristics, retrieved);
+
+ // Check that key characteristics can't be retrieved if the app ID or app data is missing.
+ vector<uint8_t> empty;
+ vector<KeyCharacteristics> not_retrieved;
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ GetCharacteristics(key_blob, empty, app_data, ¬_retrieved));
+ EXPECT_EQ(not_retrieved.size(), 0);
+
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ GetCharacteristics(key_blob, app_id, empty, ¬_retrieved));
+ EXPECT_EQ(not_retrieved.size(), 0);
+
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ GetCharacteristics(key_blob, empty, empty, ¬_retrieved));
+ EXPECT_EQ(not_retrieved.size(), 0);
+}
+
ErrorCode KeyMintAidlTestBase::DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
Status result = keymint_->deleteKey(*key_blob);
if (!keep_key_blob) {
@@ -930,16 +1022,7 @@
}
break;
case Algorithm::EC:
- switch (SecLevel()) {
- case SecurityLevel::SOFTWARE:
- case SecurityLevel::TRUSTED_ENVIRONMENT:
- return {224, 256, 384, 521};
- case SecurityLevel::STRONGBOX:
- return {256};
- default:
- ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
- break;
- }
+ ADD_FAILURE() << "EC keys must be specified by curve not size";
break;
case Algorithm::AES:
return {128, 256};
@@ -1055,9 +1138,11 @@
}
vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() {
- if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
- CHECK(SecLevel() == SecurityLevel::STRONGBOX);
- return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+ } else {
+ return {};
+ }
}
vector<Digest> KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) {
@@ -1225,9 +1310,9 @@
AuthorizationSet att_sw_enforced;
AuthorizationSet att_hw_enforced;
uint32_t att_attestation_version;
- uint32_t att_keymaster_version;
+ uint32_t att_keymint_version;
SecurityLevel att_attestation_security_level;
- SecurityLevel att_keymaster_security_level;
+ SecurityLevel att_keymint_security_level;
vector<uint8_t> att_challenge;
vector<uint8_t> att_unique_id;
vector<uint8_t> att_app_id;
@@ -1236,8 +1321,8 @@
attest_rec->length, //
&att_attestation_version, //
&att_attestation_security_level, //
- &att_keymaster_version, //
- &att_keymaster_security_level, //
+ &att_keymint_version, //
+ &att_keymint_security_level, //
&att_challenge, //
&att_sw_enforced, //
&att_hw_enforced, //
@@ -1256,14 +1341,14 @@
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, appId);
}
- EXPECT_EQ(att_keymaster_version, 100U);
- EXPECT_EQ(security_level, att_keymaster_security_level);
+ EXPECT_EQ(att_keymint_version, 100U);
+ EXPECT_EQ(security_level, att_keymint_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
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
+ // keymint 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++) {
@@ -1302,13 +1387,6 @@
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) ||
@@ -1374,9 +1452,7 @@
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);
+ EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));
att_hw_enforced.Sort();
expected_hw_enforced.Sort();
@@ -1417,7 +1493,8 @@
return authList;
}
-AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
+AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
+ bool strict_issuer_check) {
std::stringstream cert_data;
for (size_t i = 0; i < chain.size(); ++i) {
@@ -1444,7 +1521,7 @@
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) {
+ if (cert_issuer != signer_subj && strict_issuer_check) {
return AssertionFailure() << "Cert " << i << " has wrong issuer.\n"
<< " Signer subject is " << signer_subj
<< " Issuer subject is " << cert_issuer << endl
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index d8f1bb3..ec3fcf6 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -16,8 +16,12 @@
#pragma once
+#include <functional>
+#include <string_view>
+
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
+#include <android-base/properties.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
@@ -72,6 +76,8 @@
uint32_t os_version() { return os_version_; }
uint32_t os_patch_level() { return os_patch_level_; }
uint32_t vendor_patch_level() { return vendor_patch_level_; }
+ uint32_t boot_patch_level(const vector<KeyCharacteristics>& key_characteristics);
+ uint32_t boot_patch_level();
ErrorCode GetReturnErrorCode(const Status& result);
@@ -104,6 +110,18 @@
unwrapping_params, 0 /* password_sid */, 0 /* biometric_sid */);
}
+ ErrorCode GetCharacteristics(const vector<uint8_t>& key_blob, const vector<uint8_t>& app_id,
+ const vector<uint8_t>& app_data,
+ vector<KeyCharacteristics>* key_characteristics);
+ ErrorCode GetCharacteristics(const vector<uint8_t>& key_blob,
+ vector<KeyCharacteristics>* key_characteristics);
+
+ void CheckCharacteristics(const vector<uint8_t>& key_blob,
+ const vector<KeyCharacteristics>& generate_characteristics);
+ void CheckAppIdCharacteristics(const vector<uint8_t>& key_blob, std::string_view app_id_string,
+ std::string_view app_data_string,
+ const vector<KeyCharacteristics>& generate_characteristics);
+
ErrorCode DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
ErrorCode DeleteKey(bool keep_key_blob = false);
@@ -192,50 +210,58 @@
template <typename TagType>
std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
KeyData /* ecdsaKey */>
- CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+ CreateTestKeys(
+ TagType tagToTest, ErrorCode expectedReturn,
+ std::function<void(AuthorizationSetBuilder*)> tagModifier =
+ [](AuthorizationSetBuilder*) {}) {
/* 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);
+ AuthorizationSetBuilder aesBuilder = AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(tagToTest)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
+ tagModifier(&aesBuilder);
+ ErrorCode errorCode =
+ GenerateKey(aesBuilder, &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);
+ AuthorizationSetBuilder hmacBuilder = AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
+ tagModifier(&hmacBuilder);
+ errorCode = GenerateKey(hmacBuilder, &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);
+ AuthorizationSetBuilder rsaBuilder = AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(tagToTest)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity();
+ tagModifier(&rsaBuilder);
+ errorCode = GenerateKey(rsaBuilder, &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);
+ AuthorizationSetBuilder ecdsaBuilder = AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity();
+ tagModifier(&ecdsaBuilder);
+ errorCode = GenerateKey(ecdsaBuilder, &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
EXPECT_EQ(expectedReturn, errorCode);
return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
}
@@ -290,6 +316,16 @@
long challenge_;
};
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+ const char* prop) {
+ std::string prop_value = ::android::base::GetProperty(prop, /* default= */ "");
+ if (!prop_value.empty()) {
+ tags->Authorization(ttag, prop_value.data(), prop_value.size());
+ }
+}
+
vector<uint8_t> build_serial_blob(const uint64_t serial_int);
void verify_subject(const X509* cert, const string& subject, bool self_signed);
void verify_serial(X509* cert, const uint64_t expected_serial);
@@ -313,7 +349,8 @@
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
-::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
+::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
+ bool strict_issuer_check = true);
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 8b1eb30..caac346 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -18,6 +18,8 @@
#include <cutils/log.h>
#include <signal.h>
+
+#include <algorithm>
#include <iostream>
#include <openssl/ec.h>
@@ -69,6 +71,12 @@
bool check_patchLevels = false;
+// The maximum number of times we'll attempt to verify that corruption
+// of an ecrypted blob results in an error. Retries are necessary as there
+// is a small (roughly 1/256) chance that corrupting ciphertext still results
+// in valid PKCS7 padding.
+constexpr size_t kMaxPaddingCorruptionRetries = 8;
+
template <TagType tag_type, Tag tag, typename ValueT>
bool contains(const vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag,
ValueT expected_value) {
@@ -560,6 +568,7 @@
EXPECT_GT(key_blob.size(), 0U);
CheckSymmetricParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -742,6 +751,7 @@
EXPECT_GT(key_blob.size(), 0U);
CheckSymmetricParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -788,6 +798,7 @@
EXPECT_GT(key_blob.size(), 0U);
CheckSymmetricParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -865,6 +876,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -911,6 +923,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -978,6 +991,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -1108,6 +1122,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -1176,6 +1191,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -1211,6 +1227,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -1266,6 +1283,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
@@ -1352,22 +1370,22 @@
* have correct characteristics.
*/
TEST_P(NewKeyGenerationTest, Ecdsa) {
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto curve : ValidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.SetDefaultValidity(),
&key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
CheckedDeleteKey(&key_blob);
}
@@ -1389,13 +1407,13 @@
uint64_t serial_int = 0xFFFFFFFFFFFFFFFF;
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto curve : ValidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.AttestationChallenge(challenge)
.AttestationApplicationId(app_id)
@@ -1405,12 +1423,12 @@
&key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
@@ -1427,6 +1445,170 @@
}
/*
+ * NewKeyGenerationTest.EcdsaAttestationTags
+ *
+ * Verifies that creation of an attested ECDSA key includes various tags in the
+ * attestation extension.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+ uint64_t serial_int = 0x1010;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+ const AuthorizationSetBuilder base_builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity();
+
+ // Various tags that map to fields in the attestation extension ASN.1 schema.
+ auto extra_tags = AuthorizationSetBuilder()
+ .Authorization(TAG_ROLLBACK_RESISTANCE)
+ .Authorization(TAG_EARLY_BOOT_ONLY)
+ .Authorization(TAG_ACTIVE_DATETIME, 1619621648000)
+ .Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, 1619621648000)
+ .Authorization(TAG_USAGE_EXPIRE_DATETIME, 1619621999000)
+ .Authorization(TAG_USAGE_COUNT_LIMIT, 42)
+ .Authorization(TAG_AUTH_TIMEOUT, 100000)
+ .Authorization(TAG_ALLOW_WHILE_ON_BODY)
+ .Authorization(TAG_TRUSTED_USER_PRESENCE_REQUIRED)
+ .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)
+ .Authorization(TAG_UNLOCKED_DEVICE_REQUIRED)
+ .Authorization(TAG_CREATION_DATETIME, 1619621648000);
+ for (const KeyParameter& tag : extra_tags) {
+ SCOPED_TRACE(testing::Message() << "tag-" << tag);
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ AuthorizationSetBuilder builder = base_builder;
+ builder.push_back(tag);
+ auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+ if (result == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE &&
+ tag.tag == TAG_ROLLBACK_RESISTANCE) {
+ continue;
+ }
+ if (result == ErrorCode::UNSUPPORTED_TAG &&
+ (tag.tag == TAG_ALLOW_WHILE_ON_BODY || tag.tag == TAG_TRUSTED_USER_PRESENCE_REQUIRED)) {
+ // Optional tag not supported by this KeyMint implementation.
+ continue;
+ }
+ ASSERT_EQ(result, ErrorCode::OK);
+ ASSERT_GT(key_blob.size(), 0U);
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ if (tag.tag != TAG_ATTESTATION_APPLICATION_ID) {
+ // Expect to find most of the extra tags in the key characteristics
+ // of the generated key (but not for ATTESTATION_APPLICATION_ID).
+ EXPECT_TRUE(hw_enforced.Contains(tag.tag) || sw_enforced.Contains(tag.tag))
+ << tag << " not in hw:" << hw_enforced << " nor sw:" << sw_enforced;
+ }
+
+ // Verifying the attestation record will check for the specific tag because
+ // it's included in the authorizations.
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
+ SecLevel(), cert_chain_[0].encodedCertificate));
+
+ CheckedDeleteKey(&key_blob);
+ }
+
+ // Device attestation IDs should be rejected for normal attestation requests; these fields
+ // are only used for device unique attestation.
+ auto invalid_tags = AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_ID_BRAND, "brand")
+ .Authorization(TAG_ATTESTATION_ID_DEVICE, "device")
+ .Authorization(TAG_ATTESTATION_ID_PRODUCT, "product")
+ .Authorization(TAG_ATTESTATION_ID_SERIAL, "serial")
+ .Authorization(TAG_ATTESTATION_ID_IMEI, "imei")
+ .Authorization(TAG_ATTESTATION_ID_MEID, "meid")
+ .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer")
+ .Authorization(TAG_ATTESTATION_ID_MODEL, "model");
+ for (const KeyParameter& tag : invalid_tags) {
+ SCOPED_TRACE(testing::Message() << "tag-" << tag);
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ AuthorizationSetBuilder builder =
+ AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity();
+ builder.push_back(tag);
+ ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS,
+ GenerateKey(builder, &key_blob, &key_characteristics));
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAttestationTagNoApplicationId
+ *
+ * Verifies that creation of an attested ECDSA key does not include APPLICATION_ID.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationTagNoApplicationId) {
+ auto challenge = "hello";
+ auto attest_app_id = "foo";
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+ uint64_t serial_int = 0x1010;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ // Earlier versions of the attestation extension schema included a slot:
+ // applicationId [601] EXPLICIT OCTET_STRING OPTIONAL,
+ // This should never have been included, and should never be filled in.
+ // Generate an attested key that include APPLICATION_ID and APPLICATION_DATA,
+ // to confirm that this field never makes it into the attestation extension.
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(attest_app_id)
+ .Authorization(TAG_APPLICATION_ID, "client_id")
+ .Authorization(TAG_APPLICATION_DATA, "appdata")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
+ ASSERT_EQ(result, ErrorCode::OK);
+ ASSERT_GT(key_blob.size(), 0U);
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(challenge, attest_app_id, sw_enforced, hw_enforced,
+ SecLevel(), cert_chain_[0].encodedCertificate));
+
+ // Check that the app id is not in the cert.
+ string app_id = "clientid";
+ std::vector<uint8_t> needle(reinterpret_cast<const uint8_t*>(app_id.data()),
+ reinterpret_cast<const uint8_t*>(app_id.data()) + app_id.size());
+ ASSERT_EQ(std::search(cert_chain_[0].encodedCertificate.begin(),
+ cert_chain_[0].encodedCertificate.end(), needle.begin(), needle.end()),
+ cert_chain_[0].encodedCertificate.end());
+
+ CheckedDeleteKey(&key_blob);
+}
+
+/*
* NewKeyGenerationTest.EcdsaSelfSignAttestation
*
* Verifies that if no challenge is provided to an Ecdsa key generation, then
@@ -1439,12 +1621,12 @@
uint64_t serial_int = 0x123456FFF1234;
vector<uint8_t> serial_blob(build_serial_blob(serial_int));
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto curve : ValidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
.Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
@@ -1452,12 +1634,12 @@
&key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
@@ -1499,11 +1681,11 @@
TEST_P(NewKeyGenerationTest, EcdsaIgnoreAppId) {
auto app_id = "foo";
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto curve : ValidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.AttestationApplicationId(app_id)
.SetDefaultValidity(),
@@ -1511,12 +1693,12 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_EQ(cert_chain_.size(), 1);
@@ -1538,7 +1720,6 @@
*/
TEST_P(NewKeyGenerationTest, AttestationApplicationIDLengthProperlyEncoded) {
auto challenge = "hello";
- auto key_size = 256;
std::vector<uint32_t> app_id_lengths{143, 258};
for (uint32_t length : app_id_lengths) {
@@ -1547,7 +1728,7 @@
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::NONE)
.AttestationChallenge(challenge)
.AttestationApplicationId(app_id)
@@ -1555,12 +1736,12 @@
&key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, EcCurve::P_256)) << "Curve P256 missing";
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
@@ -1582,11 +1763,11 @@
* resulting keys have correct characteristics.
*/
TEST_P(NewKeyGenerationTest, LimitedUsageEcdsa) {
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ for (auto curve : ValidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.Authorization(TAG_USAGE_COUNT_LIMIT, 1)
.SetDefaultValidity(),
@@ -1594,12 +1775,12 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
- EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
- << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
// Check the usage count limit tag appears in the authorizations.
AuthorizationSet auths;
@@ -1616,7 +1797,7 @@
/*
* NewKeyGenerationTest.EcdsaDefaultSize
*
- * Verifies that failing to specify a key size for EC key generation returns
+ * Verifies that failing to specify a curve for EC key generation returns
* UNSUPPORTED_KEY_SIZE.
*/
TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
@@ -1635,20 +1816,23 @@
* UNSUPPORTED_KEY_SIZE.
*/
TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
- for (auto key_size : InvalidKeySizes(Algorithm::EC)) {
+ for (auto curve : InvalidCurves()) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(key_size)
+ .EcdsaSigningKey(curve)
.Digest(Digest::NONE)
.SetDefaultValidity(),
&key_blob, &key_characteristics));
}
- ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(190)
- .Digest(Digest::NONE)
- .SetDefaultValidity()));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .Authorization(TAG_KEY_SIZE, 190)
+ .SigningKey()
+ .Digest(Digest::NONE)
+ .SetDefaultValidity()));
}
/*
@@ -1660,29 +1844,13 @@
TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
if (SecLevel() == SecurityLevel::STRONGBOX) return;
- ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
- GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(224)
- .Authorization(TAG_EC_CURVE, EcCurve::P_256)
- .Digest(Digest::NONE)
- .SetDefaultValidity()));
-}
-
-/*
- * NewKeyGenerationTest.EcdsaAllValidSizes
- *
- * Verifies that keymint supports all required EC key sizes.
- */
-TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
- auto valid_sizes = ValidKeySizes(Algorithm::EC);
- for (size_t size : valid_sizes) {
- EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(size)
- .Digest(Digest::NONE)
- .SetDefaultValidity()))
- << "Failed to generate size: " << size;
- CheckedDeleteKey();
- }
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_KEY_SIZE, 224)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .SetDefaultValidity());
+ ASSERT_TRUE(result == ErrorCode::INVALID_ARGUMENT ||
+ result == ErrorCode::UNSUPPORTED_ALGORITHM);
}
/*
@@ -1726,6 +1894,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -1761,6 +1930,7 @@
ASSERT_GT(key_blob.size(), 0U);
ASSERT_EQ(cert_chain_.size(), 0);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -1791,6 +1961,7 @@
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -2044,6 +2215,9 @@
.Authorization(TAG_APPLICATION_ID, "clientid")
.Authorization(TAG_APPLICATION_DATA, "appdata")
.SetDefaultValidity()));
+
+ CheckAppIdCharacteristics(key_blob_, "clientid", "appdata", key_characteristics_);
+
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
Begin(KeyPurpose::SIGN,
AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
@@ -2449,31 +2623,6 @@
}
/*
- * SigningOperationsTest.EcdsaAllSizesAndHashes
- *
- * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
- */
-TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
- for (auto key_size : ValidKeySizes(Algorithm::EC)) {
- for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
- ErrorCode error = GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(key_size)
- .Digest(digest)
- .SetDefaultValidity());
- EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
- << " and digest " << digest;
- if (error != ErrorCode::OK) continue;
-
- string message(1024, 'a');
- if (digest == Digest::NONE) message.resize(key_size / 8);
- SignMessage(message, AuthorizationSetBuilder().Digest(digest));
- CheckedDeleteKey();
- }
- }
-}
-
-/*
* SigningOperationsTest.EcdsaAllDigestsAndCurves
*
* Verifies ECDSA signature/verification for all digests and curves.
@@ -2538,7 +2687,7 @@
TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::NONE)
.SetDefaultValidity()));
string message(1 * 1024, 'a');
@@ -2553,11 +2702,14 @@
TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::NONE)
.Authorization(TAG_APPLICATION_ID, "clientid")
.Authorization(TAG_APPLICATION_DATA, "appdata")
.SetDefaultValidity()));
+
+ CheckAppIdCharacteristics(key_blob_, "clientid", "appdata", key_characteristics_);
+
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
AbortIfNeeded();
@@ -2587,7 +2739,7 @@
TEST_P(SigningOperationsTest, EcdsaIncompatibleDigest) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::NONE)
.Digest(Digest::SHA1)
.SetDefaultValidity()));
@@ -2975,13 +3127,12 @@
TEST_P(ImportKeyTest, EcdsaSuccess) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity(),
KeyFormat::PKCS8, ec_256_key));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
- CheckCryptoParam(TAG_KEY_SIZE, 256U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
@@ -3002,13 +3153,12 @@
TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity(),
KeyFormat::PKCS8, ec_256_key_rfc5915));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
- CheckCryptoParam(TAG_KEY_SIZE, 256U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
@@ -3028,13 +3178,12 @@
TEST_P(ImportKeyTest, EcdsaP256SEC1Success) {
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity(),
KeyFormat::PKCS8, ec_256_key_sec1));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
- CheckCryptoParam(TAG_KEY_SIZE, 256U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
@@ -3055,13 +3204,12 @@
if (SecLevel() == SecurityLevel::STRONGBOX) return;
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(521)
+ .EcdsaSigningKey(EcCurve::P_521)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity(),
KeyFormat::PKCS8, ec_521_key));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
- CheckCryptoParam(TAG_KEY_SIZE, 521U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521);
CheckOrigin();
@@ -3073,21 +3221,6 @@
}
/*
- * ImportKeyTest.EcdsaSizeMismatch
- *
- * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
- * correct way.
- */
-TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
- ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
- ImportKey(AuthorizationSetBuilder()
- .EcdsaSigningKey(224 /* Doesn't match key */)
- .Digest(Digest::NONE)
- .SetDefaultValidity(),
- KeyFormat::PKCS8, ec_256_key));
-}
-
-/*
* ImportKeyTest.EcdsaCurveMismatch
*
* Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in
@@ -3950,7 +4083,7 @@
TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::NONE)
.SetDefaultValidity()));
auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
@@ -4249,11 +4382,22 @@
string ciphertext = EncryptMessage(message, params);
EXPECT_EQ(16U, ciphertext.size());
EXPECT_NE(ciphertext, message);
- ++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
- string plaintext;
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+ for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+ ++ciphertext[ciphertext.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ ErrorCode error = Finish(message, &plaintext);
+ if (error == ErrorCode::INVALID_INPUT_LENGTH) {
+ // This is the expected error, we can exit the test now.
+ return;
+ } else {
+ // Very small chance we got valid decryption, so try again.
+ ASSERT_EQ(error, ErrorCode::OK);
+ }
+ }
+ FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}
vector<uint8_t> CopyIv(const AuthorizationSet& set) {
@@ -5216,15 +5360,27 @@
string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
EXPECT_EQ(8U, ciphertext.size());
EXPECT_NE(ciphertext, message);
- ++ciphertext[ciphertext.size() / 2];
AuthorizationSetBuilder begin_params;
begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
- string plaintext;
- EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
- EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+
+ for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+ ++ciphertext[ciphertext.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
+ ErrorCode error = Finish(&plaintext);
+ if (error == ErrorCode::INVALID_ARGUMENT) {
+ // This is the expected error, we can exit the test now.
+ return;
+ } else {
+ // Very small chance we got valid decryption, so try again.
+ ASSERT_EQ(error, ErrorCode::OK);
+ }
+ }
+ FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}
struct TripleDesTestVector {
@@ -5552,16 +5708,27 @@
string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
EXPECT_EQ(8U, ciphertext.size());
EXPECT_NE(ciphertext, message);
- ++ciphertext[ciphertext.size() / 2];
auto begin_params = AuthorizationSetBuilder()
.BlockMode(BlockMode::CBC)
.Padding(PaddingMode::PKCS7)
.Authorization(TAG_NONCE, iv);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
- string plaintext;
- EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
- EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+
+ for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
+ ++ciphertext[ciphertext.size() / 2];
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
+ ErrorCode error = Finish(&plaintext);
+ if (error == ErrorCode::INVALID_ARGUMENT) {
+ // This is the expected error, we can exit the test now.
+ return;
+ } else {
+ // Very small chance we got valid decryption, so try again.
+ ASSERT_EQ(error, ErrorCode::OK);
+ }
+ }
+ FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}
/*
@@ -6330,6 +6497,11 @@
auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+ for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
+ ASSERT_GT(keyData.blob.size(), 0U);
+ AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+ EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+ }
CheckedDeleteKey(&aesKeyData.blob);
CheckedDeleteKey(&hmacKeyData.blob);
CheckedDeleteKey(&rsaKeyData.blob);
@@ -6337,7 +6509,30 @@
}
/*
- * EarlyBootKeyTest.UsetEarlyBootKeyFailure
+ * EarlyBootKeyTest.CreateAttestedEarlyBootKey
+ *
+ * Verifies that creating an early boot key with attestation succeeds.
+ */
+TEST_P(EarlyBootKeyTest, CreateAttestedEarlyBootKey) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] = CreateTestKeys(
+ TAG_EARLY_BOOT_ONLY, ErrorCode::OK, [](AuthorizationSetBuilder* builder) {
+ builder->AttestationChallenge("challenge");
+ builder->AttestationApplicationId("app_id");
+ });
+
+ for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
+ ASSERT_GT(keyData.blob.size(), 0U);
+ AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+ EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+ }
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+ CheckedDeleteKey(&rsaKeyData.blob);
+ CheckedDeleteKey(&ecdsaKeyData.blob);
+}
+
+/*
+ * EarlyBootKeyTest.UseEarlyBootKeyFailure
*
* Verifies that using early boot keys at a later stage fails.
*/
@@ -6365,7 +6560,7 @@
ASSERT_EQ(ErrorCode::EARLY_BOOT_ENDED, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
.Authorization(TAG_EARLY_BOOT_ONLY)
- .EcdsaSigningKey(256)
+ .EcdsaSigningKey(EcCurve::P_256)
.Digest(Digest::SHA_2_256)
.SetDefaultValidity(),
KeyFormat::PKCS8, ec_256_key));
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index a2071c2..af951e8 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -29,6 +29,7 @@
#include <openssl/ec_key.h>
#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
+#include <vector>
#include "KeyMintAidlTestBase.h"
@@ -102,8 +103,8 @@
return std::move(corruptSig);
}
-ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
- auto [chain, _, parseErr] = cppbor::parse(eek.chain);
+ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
+ auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
if (!chain || !chain->asArray()) {
return "EekChain parse failed";
}
@@ -125,7 +126,7 @@
corruptChain.add(eekChain->get(ii)->clone());
}
}
- return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
+ return corruptChain.encode();
}
string device_suffix(const string& name) {
@@ -271,14 +272,14 @@
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
protected:
CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
- generateEek(3);
+ generateTestEekChain(3);
}
- void generateEek(size_t eekLength) {
+ void generateTestEekChain(size_t eekLength) {
auto chain = generateEekChain(eekLength, eekId_);
EXPECT_TRUE(chain) << chain.message();
- if (chain) eekChain_ = chain.moveValue();
- eekLength_ = eekLength;
+ if (chain) testEekChain_ = chain.moveValue();
+ testEekLength_ = eekLength;
}
void generateKeys(bool testMode, size_t numKeys) {
@@ -297,7 +298,8 @@
}
void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
- const bytevec& keysToSignMac, const ProtectedData& protectedData) {
+ const bytevec& keysToSignMac, const ProtectedData& protectedData,
+ std::vector<BccEntryData>* bccOutput = nullptr) {
auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
ASSERT_TRUE(parsedProtectedData->asArray());
@@ -307,8 +309,9 @@
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 */);
+ auto sessionKey =
+ x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
+ senderPubkey->first, false /* senderIsA */);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
@@ -335,11 +338,11 @@
ASSERT_TRUE(deviceInfoMap->asMap());
auto& signingKey = bccContents->back().pubKey;
- auto macKey = verifyAndParseCoseSign1(/* ignore_signature = */ false, signedMac->asArray(),
- signingKey,
+ auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
cppbor::Array() // SignedMacAad
.add(challenge_)
.add(std::move(deviceInfoMap))
+ .add(keysToSignMac)
.encode());
ASSERT_TRUE(macKey) << macKey.message();
@@ -354,11 +357,15 @@
auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
ASSERT_TRUE(macPayload) << macPayload.message();
+
+ if (bccOutput) {
+ *bccOutput = std::move(*bccContents);
+ }
}
bytevec eekId_;
- size_t eekLength_;
- EekChain eekChain_;
+ size_t testEekLength_;
+ EekChain testEekChain_;
bytevec challenge_;
std::vector<MacedPublicKey> keysToSign_;
cppbor::Array cborKeysToSign_;
@@ -372,13 +379,13 @@
bool testMode = true;
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
- generateEek(eekLength);
+ generateTestEekChain(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
+ testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
@@ -387,31 +394,62 @@
}
/**
- * 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.
+ * Ensure that test mode outputs a unique BCC root key every time we request a
+ * certificate request. Else, it's possible that the test mode API could be used
+ * to fingerprint devices. Only the GEEK should be allowed to decrypt the same
+ * device public key multiple times.
*/
-TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
- bool testMode = false;
- for (size_t eekLength : {2, 3, 7}) {
- SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
- generateEek(eekLength);
+TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
+ constexpr bool testMode = true;
- bytevec keysToSignMac;
- DeviceInfo deviceInfo;
- ProtectedData protectedData;
- auto status = provisionable_->generateCertificateRequest(
- testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
- &protectedData, &keysToSignMac);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(status.getServiceSpecificError(),
- BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ std::vector<BccEntryData> firstBcc;
+ checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
+ &firstBcc);
+
+ status = provisionable_->generateCertificateRequest(
+ testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+ std::vector<BccEntryData> secondBcc;
+ checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
+ &secondBcc);
+
+ // Verify that none of the keys in the first BCC are repeated in the second one.
+ for (const auto& i : firstBcc) {
+ for (auto& j : secondBcc) {
+ ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
+ << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
+ }
}
}
/**
+ * Generate an empty certificate request in prod mode. This test must be run explicitly, and
+ * is not run by default. Not all devices are GMS devices, and therefore they do not all
+ * trust the Google EEK root.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
+ bool testMode = false;
+
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ EXPECT_TRUE(status.isOk());
+}
+
+/**
* Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
@@ -420,13 +458,13 @@
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
- generateEek(eekLength);
+ generateTestEekChain(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
+ testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
@@ -435,30 +473,21 @@
}
/**
- * 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.
+ * Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
+ * is not run by default. Not all devices are GMS devices, and therefore they do not all
+ * trust the Google EEK root.
*/
-TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
- for (size_t eekLength : {2, 3, 7}) {
- SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
- generateEek(eekLength);
-
- bytevec keysToSignMac;
- DeviceInfo deviceInfo;
- ProtectedData protectedData;
- auto status = provisionable_->generateCertificateRequest(
- testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
- &keysToSignMac);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(status.getServiceSpecificError(),
- BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
- }
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
+ &keysToSignMac);
+ EXPECT_TRUE(status.isOk());
}
/**
@@ -473,8 +502,8 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
- &keysToSignMac);
+ testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -483,7 +512,7 @@
* Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
*/
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
- bool testMode = true;
+ bool testMode = false;
generateKeys(testMode, 1 /* numKeys */);
MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
@@ -491,38 +520,35 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
- &keysToSignMac);
+ testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
- auto rc = status.getServiceSpecificError();
-
- // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
- EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
- rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+ EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
/**
* Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
* Confirm that the request is rejected.
- *
- * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
- * implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
- for (size_t ii = 0; ii < eekLength_; ii++) {
- auto chain = corrupt_sig_chain(eekChain_, ii);
+ auto prodEekChain = getProdEekChain();
+ auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
+ ASSERT_NE(parsedChain, nullptr) << parseErr;
+ ASSERT_NE(parsedChain->asArray(), nullptr);
+
+ for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
+ auto chain = corrupt_sig_chain(prodEekChain, ii);
ASSERT_TRUE(chain) << chain.message();
- EekChain corruptEek = chain.moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
- auto status = provisionable_->generateCertificateRequest(
- testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
- &keysToSignMac);
+ auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
+ challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
@@ -532,9 +558,6 @@
/**
* Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
* Confirm that the request is rejected.
- *
- * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
- * implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
bool testMode = false;
@@ -542,7 +565,7 @@
// Build an EEK chain that omits the first self-signed cert.
auto truncatedChain = cppbor::Array();
- auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
+ auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
ASSERT_TRUE(chain);
auto eekChain = chain->asArray();
ASSERT_NE(eekChain, nullptr);
@@ -571,7 +594,7 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
+ true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
@@ -589,7 +612,7 @@
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
- false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
+ false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 718133a..9e218b6 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -57,8 +57,28 @@
"include",
],
shared_libs: [
+ "libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
+ "libjsoncpp",
+ ],
+}
+
+cc_test {
+ name: "libkeymint_remote_prov_support_test",
+ srcs: ["remote_prov_utils_test.cpp"],
+ static_libs: [
+ "libgmock",
+ "libgtest_main",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcppbor_external",
+ "libcppcose_rkp",
+ "libcrypto",
+ "libjsoncpp",
+ "libkeymaster_portable",
+ "libkeymint_remote_prov_support",
],
}
diff --git a/security/keymint/support/attestation_record.cpp b/security/keymint/support/attestation_record.cpp
index a48f770..2462228 100644
--- a/security/keymint/support/attestation_record.cpp
+++ b/security/keymint/support/attestation_record.cpp
@@ -64,6 +64,7 @@
} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+// Fields ordered in tag order.
typedef struct km_auth_list {
ASN1_INTEGER_SET* purpose;
ASN1_INTEGER* algorithm;
@@ -72,32 +73,38 @@
ASN1_INTEGER_SET* padding;
ASN1_INTEGER* ec_curve;
ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER_SET* mgf_digest;
+ ASN1_NULL* rollback_resistance;
+ ASN1_NULL* early_boot_only;
ASN1_INTEGER* active_date_time;
ASN1_INTEGER* origination_expire_date_time;
ASN1_INTEGER* usage_expire_date_time;
+ ASN1_INTEGER* usage_count_limit;
ASN1_NULL* no_auth_required;
ASN1_INTEGER* user_auth_type;
ASN1_INTEGER* auth_timeout;
ASN1_NULL* allow_while_on_body;
- ASN1_NULL* all_applications;
- ASN1_OCTET_STRING* application_id;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
ASN1_INTEGER* creation_date_time;
ASN1_INTEGER* origin;
- ASN1_NULL* rollback_resistance;
KM_ROOT_OF_TRUST* root_of_trust;
ASN1_INTEGER* os_version;
ASN1_INTEGER* os_patchlevel;
ASN1_OCTET_STRING* attestation_application_id;
- ASN1_NULL* trusted_user_presence_required;
- ASN1_NULL* trusted_confirmation_required;
- ASN1_NULL* unlocked_device_required;
+ ASN1_OCTET_STRING* attestation_id_brand;
+ ASN1_OCTET_STRING* attestation_id_device;
+ ASN1_OCTET_STRING* attestation_id_product;
+ ASN1_OCTET_STRING* attestation_id_serial;
+ ASN1_OCTET_STRING* attestation_id_imei;
+ ASN1_OCTET_STRING* attestation_id_meid;
+ ASN1_OCTET_STRING* attestation_id_manufacturer;
+ ASN1_OCTET_STRING* attestation_id_model;
ASN1_INTEGER* vendor_patchlevel;
ASN1_INTEGER* boot_patchlevel;
- ASN1_NULL* early_boot_only;
ASN1_NULL* device_unique_attestation;
- ASN1_NULL* storage_key;
ASN1_NULL* identity_credential;
- ASN1_INTEGER* usage_count_limit;
} KM_AUTH_LIST;
ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -109,13 +116,18 @@
ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, mgf_digest, ASN1_INTEGER,
+ TAG_RSA_OAEP_MGF_DIGEST.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_count_limit, ASN1_INTEGER,
+ TAG_USAGE_COUNT_LIMIT.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
@@ -133,19 +145,31 @@
ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_BRAND.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_IMEI.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MEID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_ID_MODEL.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
TAG_VENDOR_PATCHLEVEL.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
- TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
- ASN1_EXP_OPT(KM_AUTH_LIST, usage_count_limit, ASN1_INTEGER,
- TAG_USAGE_COUNT_LIMIT.maskedTag()),
} ASN1_SEQUENCE_END(KM_AUTH_LIST);
IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
@@ -155,9 +179,9 @@
ASN1_INTEGER* keymint_version;
ASN1_ENUMERATED* keymint_security_level;
ASN1_OCTET_STRING* attestation_challenge;
+ ASN1_INTEGER* unique_id;
KM_AUTH_LIST* software_enforced;
KM_AUTH_LIST* tee_enforced;
- ASN1_INTEGER* unique_id;
} KM_KEY_DESCRIPTION;
ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
@@ -253,41 +277,52 @@
}
// Extract the values from the specified ASN.1 record and place them in auth_list.
+// Does nothing with root-of-trust field.
static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
if (!record) return ErrorCode::OK;
- copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
- copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
- copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
- copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
- copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
- copyAuthTag(record->digest, TAG_DIGEST, auth_list);
- copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
- copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
- copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
- copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
- copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
- copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
- copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
- copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ // Fields ordered in tag order.
copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
- copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->mgf_digest, TAG_RSA_OAEP_MGF_DIGEST, auth_list);
+ copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->usage_count_limit, TAG_USAGE_COUNT_LIMIT, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
- copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
- copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
- copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->allow_while_on_body, TAG_ALLOW_WHILE_ON_BODY, auth_list);
copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
auth_list);
copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
auth_list);
copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
- copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ // root_of_trust dealt with separately
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+ copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+ copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+ copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+ copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+ copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+ copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+ copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list);
+ copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+ copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
- copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
- copyAuthTag(record->usage_count_limit, TAG_USAGE_COUNT_LIMIT, auth_list);
return ErrorCode::OK;
}
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index e4261f3..406b7a9 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -27,6 +27,31 @@
extern bytevec kTestMacKey;
+// The Google root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedRootCert[] = {
+ 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x2a, 0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06,
+ 0x21, 0x58, 0x20, 0x99, 0xb9, 0xee, 0xdd, 0x5e, 0xe4, 0x52, 0xf6, 0x85, 0xc6, 0x4c, 0x62,
+ 0xdc, 0x3e, 0x61, 0xab, 0x57, 0x48, 0x7d, 0x75, 0x37, 0x29, 0xad, 0x76, 0x80, 0x32, 0xd2,
+ 0xb3, 0xcb, 0x63, 0x58, 0xd9, 0x58, 0x40, 0x1e, 0x22, 0x08, 0x4b, 0xa4, 0xb7, 0xa4, 0xc8,
+ 0xd7, 0x4e, 0x03, 0x0e, 0xfe, 0xb8, 0xaf, 0x14, 0x4c, 0xa7, 0x3b, 0x6f, 0xa5, 0xcd, 0xdc,
+ 0xda, 0x79, 0xc6, 0x2b, 0x64, 0xfe, 0x99, 0x39, 0xaf, 0x76, 0xe7, 0x80, 0xfa, 0x66, 0x00,
+ 0x85, 0x0d, 0x07, 0x98, 0x2a, 0xac, 0x91, 0x5c, 0xa7, 0x25, 0x14, 0x49, 0x06, 0x34, 0x75,
+ 0xca, 0x8a, 0x27, 0x7a, 0xd9, 0xe3, 0x5a, 0x49, 0xeb, 0x02, 0x03};
+
+// The Google Endpoint Encryption Key certificate, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedGeekCert[] = {
+ 0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x4e, 0xa5, 0x01, 0x01, 0x02, 0x58, 0x20,
+ 0xd0, 0xae, 0xc1, 0x15, 0xca, 0x2a, 0xcf, 0x73, 0xae, 0x6b, 0xcc, 0xcb, 0xd1, 0x96,
+ 0x1d, 0x65, 0xe8, 0xb1, 0xdd, 0xd7, 0x4a, 0x1a, 0x37, 0xb9, 0x43, 0x3a, 0x97, 0xd5,
+ 0x99, 0xdf, 0x98, 0x08, 0x03, 0x38, 0x18, 0x20, 0x04, 0x21, 0x58, 0x20, 0xbe, 0x85,
+ 0xe7, 0x46, 0xc4, 0xa3, 0x42, 0x5a, 0x40, 0xd9, 0x36, 0x3a, 0xa6, 0x15, 0xd0, 0x2c,
+ 0x58, 0x7e, 0x3d, 0xdc, 0x33, 0x02, 0x32, 0xd2, 0xfc, 0x5e, 0x1e, 0x87, 0x25, 0x5f,
+ 0x72, 0x60, 0x58, 0x40, 0x9b, 0xcf, 0x90, 0xe2, 0x2e, 0x4b, 0xab, 0xd1, 0x18, 0xb1,
+ 0x0e, 0x8e, 0x5d, 0x20, 0x27, 0x4b, 0x84, 0x58, 0xfe, 0xfc, 0x32, 0x90, 0x7e, 0x72,
+ 0x05, 0x83, 0xbc, 0xd7, 0x82, 0xbe, 0xfa, 0x64, 0x78, 0x2d, 0x54, 0x10, 0x4b, 0xc0,
+ 0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
+ 0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
+
/**
* Generates random bytes.
*/
@@ -44,6 +69,11 @@
*/
ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+/**
+ * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
+ */
+bytevec getProdEekChain();
+
struct BccEntryData {
bytevec pubKey;
};
@@ -57,4 +87,26 @@
*/
ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc);
+struct JsonOutput {
+ static JsonOutput Ok(std::string json) { return {std::move(json), ""}; }
+ static JsonOutput Error(std::string error) { return {"", std::move(error)}; }
+
+ std::string output;
+ std::string error; // if non-empty, this describes what went wrong
+};
+
+/**
+ * Take a given certificate request and output a JSON blob containing both the
+ * build fingerprint and certificate request. This data may be serialized, then
+ * later uploaded to the remote provisioning service. The input csr is not
+ * validated, only encoded.
+ *
+ * Output format:
+ * {
+ * "build_fingerprint": <string>
+ * "csr": <base64 CBOR CSR>
+ * }
+ */
+JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr);
+
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/keymint_utils.cpp b/security/keymint/support/keymint_utils.cpp
index 2dbdfa8..1e0733f 100644
--- a/security/keymint/support/keymint_utils.cpp
+++ b/security/keymint/support/keymint_utils.cpp
@@ -32,10 +32,11 @@
constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch";
-constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$";
constexpr size_t kYearMatch = 1;
constexpr size_t kMonthMatch = 2;
-constexpr size_t kPatchlevelMatchCount = kMonthMatch + 1;
+constexpr size_t kDayMatch = 3;
+constexpr size_t kPatchlevelMatchCount = kDayMatch + 1;
uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
if (match.rm_so == -1) return 0;
@@ -53,8 +54,6 @@
return prop_value;
}
-} // anonymous namespace
-
uint32_t getOsVersion(const char* version_str) {
regex_t regex;
if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
@@ -76,12 +75,9 @@
return (major * 100 + minor) * 100 + subminor;
}
-uint32_t getOsVersion() {
- std::string version = wait_and_get_property(kPlatformVersionProp);
- return getOsVersion(version.c_str());
-}
+enum class PatchlevelOutput { kYearMonthDay, kYearMonth };
-uint32_t getPatchlevel(const char* patchlevel_str) {
+uint32_t getPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) {
regex_t regex;
if (regcomp(®ex, kPatchlevelRegex, REG_EXTENDED) != 0) {
return 0;
@@ -100,17 +96,35 @@
if (month < 1 || month > 12) {
return 0;
}
- return year * 100 + month;
+
+ switch (detail) {
+ case PatchlevelOutput::kYearMonthDay: {
+ uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]);
+ if (day < 1 || day > 31) {
+ return 0;
+ }
+ return year * 10000 + month * 100 + day;
+ }
+ case PatchlevelOutput::kYearMonth:
+ return year * 100 + month;
+ }
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
}
uint32_t getOsPatchlevel() {
std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
- return getPatchlevel(patchlevel.c_str());
+ return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonth);
}
uint32_t getVendorPatchlevel() {
std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp);
- return getPatchlevel(patchlevel.c_str());
+ return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay);
}
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index da10eb2..0cbee51 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-#include <remote_prov/remote_prov_utils.h>
+#include <iterator>
+#include <tuple>
-#include <openssl/rand.h>
-
+#include <android-base/properties.h>
#include <cppbor.h>
+#include <json/json.h>
+#include <openssl/base64.h>
+#include <openssl/rand.h>
+#include <remote_prov/remote_prov_utils.h>
namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -31,6 +35,10 @@
}
ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+ if (length < 2) {
+ return "EEK chain must contain at least 2 certs.";
+ }
+
auto eekChain = cppbor::Array();
bytevec prev_priv_key;
@@ -78,7 +86,19 @@
return EekChain{eekChain.encode(), pub_key, priv_key};
}
-ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(bool ignoreSignature, const cppbor::Array* coseSign1,
+bytevec getProdEekChain() {
+ bytevec prodEek;
+ prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));
+
+ // In CBOR encoding, 0x82 indicates an array of two items
+ prodEek.push_back(0x82);
+ prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
+ prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));
+
+ return prodEek;
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
const bytevec& signingCoseKey, const bytevec& aad) {
if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
return "Invalid COSE_Sign1";
@@ -115,27 +135,22 @@
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();
+ 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();
+ 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";
- }
+ 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";
@@ -148,8 +163,7 @@
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 */);
+ auto payload = verifyAndParseCoseSign1Cwt(entry, std::move(prevKey), bytevec{} /* AAD */);
if (!payload) {
return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage();
}
@@ -168,4 +182,36 @@
return result;
}
+JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr) {
+ const std::string kFingerprintProp = "ro.build.fingerprint";
+
+ if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
+ return JsonOutput::Error("Unable to read build fingerprint");
+ }
+
+ bytevec csrCbor = csr.encode();
+ size_t base64Length;
+ int rc = EVP_EncodedLength(&base64Length, csrCbor.size());
+ if (!rc) {
+ return JsonOutput::Error("Error getting base64 length. Size overflow?");
+ }
+
+ std::vector<char> base64(base64Length);
+ rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), csrCbor.data(), csrCbor.size());
+ ++rc; // Account for NUL, which BoringSSL does not for some reason.
+ if (rc != base64Length) {
+ return JsonOutput::Error("Error writing base64. Expected " + std::to_string(base64Length) +
+ " bytes to be written, but " + std::to_string(rc) +
+ " bytes were actually written.");
+ }
+
+ Json::Value json(Json::objectValue);
+ json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
+ json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
+
+ Json::StreamWriterBuilder factory;
+ factory["indentation"] = ""; // disable pretty formatting
+ return JsonOutput::Ok(Json::writeString(factory, json));
+}
+
} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
new file mode 100644
index 0000000..8697c51
--- /dev/null
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 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 <android-base/properties.h>
+#include <cppbor_parse.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/remote_provisioning_utils.h>
+#include <openssl/curve25519.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <cstdint>
+#include "cppbor.h"
+#include "keymaster/cppcose/cppcose.h"
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+namespace {
+
+using ::keymaster::KeymasterBlob;
+using ::keymaster::validateAndExtractEekPubAndId;
+using ::testing::ElementsAreArray;
+
+TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) {
+ ASSERT_FALSE(generateEekChain(1, /*eekId=*/{}));
+}
+
+TEST(RemoteProvUtilsTest, GenerateEekChain) {
+ bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
+ for (size_t length : {2, 3, 31}) {
+ auto get_eek_result = generateEekChain(length, kTestEekId);
+ ASSERT_TRUE(get_eek_result) << get_eek_result.message();
+
+ auto& [chain, pubkey, privkey] = *get_eek_result;
+
+ auto validation_result = validateAndExtractEekPubAndId(
+ /*testMode=*/true, KeymasterBlob(chain.data(), chain.size()));
+ ASSERT_TRUE(validation_result.isOk());
+
+ auto& [eekPub, eekId] = *validation_result;
+ EXPECT_THAT(eekId, ElementsAreArray(kTestEekId));
+ EXPECT_THAT(eekPub, ElementsAreArray(pubkey));
+ }
+}
+
+TEST(RemoteProvUtilsTest, GetProdEekChain) {
+ auto chain = getProdEekChain();
+
+ auto validation_result = validateAndExtractEekPubAndId(
+ /*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
+ ASSERT_TRUE(validation_result.isOk()) << "Error: " << validation_result.moveError();
+
+ auto& [eekPub, eekId] = *validation_result;
+
+ auto [geekCert, ignoredNewPos, error] =
+ cppbor::parse(kCoseEncodedGeekCert, sizeof(kCoseEncodedGeekCert));
+ ASSERT_NE(geekCert, nullptr) << "Error: " << error;
+ ASSERT_NE(geekCert->asArray(), nullptr);
+
+ auto& encodedGeekCoseKey = geekCert->asArray()->get(kCoseSign1Payload);
+ ASSERT_NE(encodedGeekCoseKey, nullptr);
+ ASSERT_NE(encodedGeekCoseKey->asBstr(), nullptr);
+
+ auto geek = CoseKey::parse(encodedGeekCoseKey->asBstr()->value());
+ ASSERT_TRUE(geek) << "Error: " << geek.message();
+
+ const std::vector<uint8_t> empty;
+ EXPECT_THAT(eekId, ElementsAreArray(geek->getBstrValue(CoseKey::KEY_ID).value_or(empty)));
+ EXPECT_THAT(eekPub, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_X).value_or(empty)));
+}
+
+TEST(RemoteProvUtilsTest, JsonEncodeCsr) {
+ cppbor::Array array;
+ array.add(1);
+
+ auto [json, error] = jsonEncodeCsrWithBuild(array);
+
+ ASSERT_TRUE(error.empty()) << error;
+
+ std::string expected = R"({"build_fingerprint":")" +
+ ::android::base::GetProperty("ro.build.fingerprint", /*default=*/"") +
+ R"(","csr":"gQE="})";
+
+ ASSERT_EQ(json, expected);
+}
+
+} // namespace
+} // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/secureclock/aidl/Android.bp b/security/secureclock/aidl/Android.bp
index c78be3b..6a2b753 100644
--- a/security/secureclock/aidl/Android.bp
+++ b/security/secureclock/aidl/Android.bp
@@ -26,6 +26,10 @@
},
rust: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ ],
},
},
}
diff --git a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
index 31f4854..bf332d5 100644
--- a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
+++ b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
@@ -114,6 +114,7 @@
EXPECT_EQ(ErrorCode::OK, result1.error);
EXPECT_EQ(1U, result1.token.challenge);
EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+ EXPECT_EQ(32U, result1.token.mac.size());
unsigned long time_to_sleep = 200;
sleep_ms(time_to_sleep);
@@ -123,6 +124,7 @@
EXPECT_EQ(ErrorCode::OK, result2.error);
EXPECT_EQ(2U, result2.token.challenge);
EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+ EXPECT_EQ(32U, result2.token.mac.size());
auto host_time_delta = result2_time - result1_time;
@@ -153,6 +155,7 @@
EXPECT_EQ(ErrorCode::OK, result1.error);
EXPECT_EQ(0U, result1.token.challenge);
EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+ EXPECT_EQ(32U, result1.token.mac.size());
unsigned long time_to_sleep = 200;
sleep_ms(time_to_sleep);
@@ -162,6 +165,7 @@
EXPECT_EQ(ErrorCode::OK, result2.error);
EXPECT_EQ(1U, result2.token.challenge);
EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+ EXPECT_EQ(32U, result2.token.mac.size());
auto host_time_delta = result2_time - result1_time;
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 8426120..51938ba 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -48,6 +48,9 @@
SharedSecretParameters params;
auto error = GetReturnErrorCode(sharedSecret->getSharedSecretParameters(¶ms));
EXPECT_EQ(ErrorCode::OK, error);
+ EXPECT_TRUE(params.seed.size() == 0 || params.seed.size() == 32);
+ EXPECT_TRUE(params.nonce.size() == 32);
+
GetParamsResult result;
result.tie() = std::tie(error, params);
return result;
@@ -234,6 +237,51 @@
}
}
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortNonce) {
+ auto sharedSecrets = allSharedSecrets();
+ if (sharedSecrets.empty()) {
+ GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
+ }
+ auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+
+ auto params = getAllSharedSecretParameters();
+ ASSERT_EQ(sharedSecrets.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 and shorten that nonce by one.
+ size_t param_to_tweak = rand() % params.size();
+ auto& to_tweak = params[param_to_tweak].nonce;
+ ASSERT_TRUE(to_tweak.size() == 32);
+ to_tweak.resize(31);
+
+ 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 {
+ // Other services *may* succeed, or may notice the invalid size for the nonce.
+ // However, if another service completes the computation, it should get the 'wrong'
+ // answer.
+ if (responses[i].error == ErrorCode::OK) {
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different shared secret, due to the tweaked "
+ "nonce.";
+ } else {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error);
+ }
+ }
+ }
+}
+
TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
auto sharedSecrets = allSharedSecrets();
if (sharedSecrets.empty()) {
@@ -275,6 +323,51 @@
}
}
}
+
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortSeed) {
+ auto sharedSecrets = allSharedSecrets();
+ if (sharedSecrets.empty()) {
+ GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
+ }
+ auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+ auto params = getAllSharedSecretParameters();
+ ASSERT_EQ(sharedSecrets.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 to be of (invalid) length 31.
+ 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);
+ to_tweak.resize(31);
+
+ 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 {
+ // Other services *may* succeed, or may notice the invalid size for the seed.
+ // However, if another service completes the computation, it should get the 'wrong'
+ // answer.
+ if (responses[i].error == ErrorCode::OK) {
+ EXPECT_NE(correct_response, responses[i].sharing_check)
+ << "Others should calculate a different shared secret, due to the tweaked "
+ "seed.";
+ } else {
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error);
+ }
+ }
+ }
+}
+
} // namespace aidl::android::hardware::security::sharedsecret::test
int main(int argc, char** argv) {
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
index 0b3d4c2..8867a1a 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -2,6 +2,6 @@
class hal
user system
group system wakelock context_hub
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
index fc99ee7..f47e060 100644
--- a/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
+++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
@@ -2,6 +2,6 @@
class hal
user system
group system wakelock context_hub
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10
diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp
index 4d544e1..75d1193 100644
--- a/tests/extension/vibrator/aidl/Android.bp
+++ b/tests/extension/vibrator/aidl/Android.bp
@@ -24,6 +24,9 @@
// This is agreeing to keep the interface stable.
stability: "vintf",
+ // This is a testing-purpose interface. Fine to use unstable version on REL platform.
+ owner: "test",
+
// This happens to use types from a core interface, so we import it, but
// this won't always be needed.
imports: [
diff --git a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
index ad4ef12..ea9bcb5 100644
--- a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
+++ b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
@@ -469,7 +469,7 @@
}
}
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTestBase);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlTestV1_0_HalNotStarted);
INSTANTIATE_TEST_CASE_P(
PerInstance, OffloadControlTestV1_0_HalNotStarted,
testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
@@ -478,7 +478,7 @@
IOffloadControl::descriptor))),
android::hardware::PrintInstanceTupleNameToString<>);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlTestV1_0_HalStarted);
INSTANTIATE_TEST_CASE_P(
PerInstance, OffloadControlTestV1_0_HalStarted,
testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/tetheroffload/control/1.1/Android.bp b/tetheroffload/control/1.1/Android.bp
index e87ff5c..7871c2c 100644
--- a/tetheroffload/control/1.1/Android.bp
+++ b/tetheroffload/control/1.1/Android.bp
@@ -21,5 +21,9 @@
"android.hardware.tetheroffload.control@1.0",
"android.hidl.base@1.0",
],
+ apex_available: [
+ "//apex_available:platform", // Used by InProcessTethering
+ "com.android.tethering",
+ ],
gen_java: true,
}
diff --git a/tv/cec/1.0/default/Android.bp b/tv/cec/1.0/default/Android.bp
index fc4298d..b4053df 100644
--- a/tv/cec/1.0/default/Android.bp
+++ b/tv/cec/1.0/default/Android.bp
@@ -12,12 +12,16 @@
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
- srcs: ["HdmiCec.cpp"],
+ srcs: [
+ "HdmiCec.cpp",
+ "HdmiCecDefault.cpp",
+ ],
shared_libs: [
"libhidlbase",
"liblog",
"libbase",
+ "libcutils",
"libutils",
"libhardware",
"android.hardware.tv.cec@1.0",
diff --git a/tv/cec/1.0/default/HdmiCec.cpp b/tv/cec/1.0/default/HdmiCec.cpp
index 171bdfe..74de785 100644
--- a/tv/cec/1.0/default/HdmiCec.cpp
+++ b/tv/cec/1.0/default/HdmiCec.cpp
@@ -20,6 +20,7 @@
#include <hardware/hardware.h>
#include <hardware/hdmi_cec.h>
#include "HdmiCec.h"
+#include "HdmiCecDefault.h"
namespace android {
namespace hardware {
@@ -390,6 +391,15 @@
return mDevice->is_connected(mDevice, portId) > 0;
}
+IHdmiCec* getHdmiCecDefault() {
+ HdmiCecDefault* hdmiCecDefault = new HdmiCecDefault();
+ Result result = hdmiCecDefault->init();
+ if (result == Result::SUCCESS) {
+ return hdmiCecDefault;
+ }
+ LOG(ERROR) << "Failed to load default HAL.";
+ return nullptr;
+}
IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) {
hdmi_cec_device_t* hdmi_cec_device;
@@ -410,7 +420,7 @@
return new HdmiCec(hdmi_cec_device);
} else {
LOG(ERROR) << "Passthrough failed to load legacy HAL.";
- return nullptr;
+ return getHdmiCecDefault();
}
}
diff --git a/tv/cec/1.0/default/HdmiCecDefault.cpp b/tv/cec/1.0/default/HdmiCecDefault.cpp
new file mode 100644
index 0000000..299bcf0
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecDefault.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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 "android.hardware.tv.cec@1.0-impl"
+#include <android-base/logging.h>
+
+#include <cutils/properties.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/cec.h>
+#include <linux/ioctl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+#include <algorithm>
+
+#include "HdmiCecDefault.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+// When set to false, all the CEC commands are discarded. True by default after initialization.
+bool mCecEnabled;
+/*
+ * When set to false, HAL does not wake up the system upon receiving <Image View On> or
+ * <Text View On>. True by default after initialization.
+ */
+bool mWakeupEnabled;
+
+int mCecFd;
+int mExitFd;
+pthread_t mEventThread;
+sp<IHdmiCecCallback> mCallback;
+
+HdmiCecDefault::HdmiCecDefault() {
+ mCecFd = -1;
+ mExitFd = -1;
+ mCecEnabled = false;
+ mWakeupEnabled = false;
+ mCallback = nullptr;
+}
+
+HdmiCecDefault::~HdmiCecDefault() {
+ release();
+}
+
+// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+Return<Result> HdmiCecDefault::addLogicalAddress(CecLogicalAddress addr) {
+ if (addr < CecLogicalAddress::TV || addr >= CecLogicalAddress::BROADCAST) {
+ LOG(ERROR) << "Add logical address failed, Invalid address";
+ return Result::FAILURE_INVALID_ARGS;
+ }
+
+ struct cec_log_addrs cecLogAddrs;
+ int ret = ioctl(mCecFd, CEC_ADAP_G_LOG_ADDRS, &cecLogAddrs);
+ if (ret) {
+ LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno);
+ return Result::FAILURE_BUSY;
+ }
+
+ cecLogAddrs.cec_version = getCecVersion();
+ cecLogAddrs.vendor_id = getVendorId();
+
+ unsigned int logAddrType = CEC_LOG_ADDR_TYPE_UNREGISTERED;
+ unsigned int allDevTypes = 0;
+ unsigned int primDevType = 0xff;
+ switch (addr) {
+ case CecLogicalAddress::TV:
+ primDevType = CEC_OP_PRIM_DEVTYPE_TV;
+ logAddrType = CEC_LOG_ADDR_TYPE_TV;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_TV;
+ break;
+ case CecLogicalAddress::RECORDER_1:
+ case CecLogicalAddress::RECORDER_2:
+ case CecLogicalAddress::RECORDER_3:
+ primDevType = CEC_OP_PRIM_DEVTYPE_RECORD;
+ logAddrType = CEC_LOG_ADDR_TYPE_RECORD;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_RECORD;
+ break;
+ case CecLogicalAddress::TUNER_1:
+ case CecLogicalAddress::TUNER_2:
+ case CecLogicalAddress::TUNER_3:
+ case CecLogicalAddress::TUNER_4:
+ primDevType = CEC_OP_PRIM_DEVTYPE_TUNER;
+ logAddrType = CEC_LOG_ADDR_TYPE_TUNER;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_TUNER;
+ break;
+ case CecLogicalAddress::PLAYBACK_1:
+ case CecLogicalAddress::PLAYBACK_2:
+ case CecLogicalAddress::PLAYBACK_3:
+ primDevType = CEC_OP_PRIM_DEVTYPE_PLAYBACK;
+ logAddrType = CEC_LOG_ADDR_TYPE_PLAYBACK;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_PLAYBACK;
+ cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU;
+ break;
+ case CecLogicalAddress::AUDIO_SYSTEM:
+ primDevType = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
+ logAddrType = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
+ break;
+ case CecLogicalAddress::FREE_USE:
+ primDevType = CEC_OP_PRIM_DEVTYPE_PROCESSOR;
+ logAddrType = CEC_LOG_ADDR_TYPE_SPECIFIC;
+ allDevTypes = CEC_OP_ALL_DEVTYPE_SWITCH;
+ break;
+ case CecLogicalAddress::UNREGISTERED:
+ cecLogAddrs.flags |= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK;
+ break;
+ }
+
+ int logAddrIndex = cecLogAddrs.num_log_addrs;
+
+ cecLogAddrs.num_log_addrs += 1;
+ cecLogAddrs.log_addr[logAddrIndex] = static_cast<cec_logical_address_t>(addr);
+ cecLogAddrs.log_addr_type[logAddrIndex] = logAddrType;
+ cecLogAddrs.primary_device_type[logAddrIndex] = primDevType;
+ cecLogAddrs.all_device_types[logAddrIndex] = allDevTypes;
+ cecLogAddrs.features[logAddrIndex][0] = 0;
+ cecLogAddrs.features[logAddrIndex][1] = 0;
+
+ ret = ioctl(mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
+ if (ret) {
+ LOG(ERROR) << "Add logical address failed, Error = " << strerror(errno);
+ return Result::FAILURE_BUSY;
+ }
+ return Result::SUCCESS;
+}
+
+Return<void> HdmiCecDefault::clearLogicalAddress() {
+ struct cec_log_addrs cecLogAddrs;
+ memset(&cecLogAddrs, 0, sizeof(cecLogAddrs));
+ int ret = ioctl(mCecFd, CEC_ADAP_S_LOG_ADDRS, &cecLogAddrs);
+ if (ret) {
+ LOG(ERROR) << "Clear logical Address failed, Error = " << strerror(errno);
+ }
+ return Void();
+}
+
+Return<void> HdmiCecDefault::getPhysicalAddress(getPhysicalAddress_cb callback) {
+ uint16_t addr;
+ int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
+ if (ret) {
+ LOG(ERROR) << "Get physical address failed, Error = " << strerror(errno);
+ callback(Result::FAILURE_INVALID_STATE, addr);
+ return Void();
+ }
+ callback(Result::SUCCESS, addr);
+ return Void();
+}
+
+Return<SendMessageResult> HdmiCecDefault::sendMessage(const CecMessage& message) {
+ if (!mCecEnabled) {
+ return SendMessageResult::FAIL;
+ }
+
+ struct cec_msg cecMsg;
+ memset(&cecMsg, 0, sizeof(cec_msg));
+
+ int initiator = static_cast<cec_logical_address_t>(message.initiator);
+ int destination = static_cast<cec_logical_address_t>(message.destination);
+
+ cecMsg.msg[0] = (initiator << 4) | destination;
+ for (size_t i = 0; i < message.body.size(); ++i) {
+ cecMsg.msg[i + 1] = message.body[i];
+ }
+ cecMsg.len = message.body.size() + 1;
+
+ int ret = ioctl(mCecFd, CEC_TRANSMIT, &cecMsg);
+
+ if (ret) {
+ LOG(ERROR) << "Send message failed, Error = " << strerror(errno);
+ return SendMessageResult::FAIL;
+ }
+
+ if (cecMsg.tx_status != CEC_TX_STATUS_OK) {
+ LOG(ERROR) << "Send message tx_status = " << cecMsg.tx_status;
+ }
+
+ switch (cecMsg.tx_status) {
+ case CEC_TX_STATUS_OK:
+ return SendMessageResult::SUCCESS;
+ case CEC_TX_STATUS_ARB_LOST:
+ return SendMessageResult::BUSY;
+ case CEC_TX_STATUS_NACK:
+ return SendMessageResult::NACK;
+ default:
+ return SendMessageResult::FAIL;
+ }
+}
+
+Return<void> HdmiCecDefault::setCallback(const sp<IHdmiCecCallback>& callback) {
+ if (mCallback != nullptr) {
+ mCallback->unlinkToDeath(this);
+ mCallback = nullptr;
+ }
+
+ if (callback != nullptr) {
+ mCallback = callback;
+ mCallback->linkToDeath(this, 0 /*cookie*/);
+ }
+ return Void();
+}
+
+Return<int32_t> HdmiCecDefault::getCecVersion() {
+ return property_get_int32("ro.hdmi.cec_version", CEC_OP_CEC_VERSION_1_4);
+}
+
+Return<uint32_t> HdmiCecDefault::getVendorId() {
+ return property_get_int32("ro.hdmi.vendor_id", 0x000c03 /* HDMI LLC vendor ID */);
+}
+
+Return<void> HdmiCecDefault::getPortInfo(getPortInfo_cb callback) {
+ uint16_t addr;
+ int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
+ if (ret) {
+ LOG(ERROR) << "Get port info failed, Error = " << strerror(errno);
+ }
+
+ unsigned int type = property_get_int32("ro.hdmi.device_type", CEC_DEVICE_PLAYBACK);
+ hidl_vec<HdmiPortInfo> portInfos(1);
+ portInfos[0] = {.type = (type == CEC_DEVICE_TV ? HdmiPortType::INPUT : HdmiPortType::OUTPUT),
+ .portId = 1,
+ .cecSupported = true,
+ .arcSupported = false,
+ .physicalAddress = addr};
+ callback(portInfos);
+ return Void();
+}
+
+Return<void> HdmiCecDefault::setOption(OptionKey key, bool value) {
+ switch (key) {
+ case OptionKey::ENABLE_CEC:
+ LOG(DEBUG) << "setOption: Enable CEC: " << value;
+ mCecEnabled = value;
+ break;
+ case OptionKey::WAKEUP:
+ LOG(DEBUG) << "setOption: WAKEUP: " << value;
+ mWakeupEnabled = value;
+ break;
+ default:
+ break;
+ }
+ return Void();
+}
+
+Return<void> HdmiCecDefault::setLanguage(const hidl_string& /*language*/) {
+ return Void();
+}
+
+Return<void> HdmiCecDefault::enableAudioReturnChannel(int32_t /*portId*/, bool /*enable*/) {
+ return Void();
+}
+
+Return<bool> HdmiCecDefault::isConnected(int32_t /*portId*/) {
+ uint16_t addr;
+ int ret = ioctl(mCecFd, CEC_ADAP_G_PHYS_ADDR, &addr);
+ if (ret) {
+ LOG(ERROR) << "Is connected failed, Error = " << strerror(errno);
+ return false;
+ }
+ if (addr == CEC_PHYS_ADDR_INVALID) {
+ return false;
+ }
+ return true;
+}
+
+// Initialise the cec file descriptor
+Return<Result> HdmiCecDefault::init() {
+ const char* path = "/dev/cec0";
+ mCecFd = open(path, O_RDWR);
+ if (mCecFd < 0) {
+ LOG(ERROR) << "Failed to open " << path << ", Error = " << strerror(errno);
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+ mExitFd = eventfd(0, EFD_NONBLOCK);
+ if (mExitFd < 0) {
+ LOG(ERROR) << "Failed to open eventfd, Error = " << strerror(errno);
+ release();
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+
+ // Ensure the CEC device supports required capabilities
+ struct cec_caps caps = {};
+ int ret = ioctl(mCecFd, CEC_ADAP_G_CAPS, &caps);
+ if (ret) {
+ LOG(ERROR) << "Unable to query cec adapter capabilities, Error = " << strerror(errno);
+ release();
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+
+ if (!(caps.capabilities & (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH))) {
+ LOG(ERROR) << "Wrong cec adapter capabilities " << caps.capabilities;
+ release();
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+
+ uint32_t mode = CEC_MODE_INITIATOR | CEC_MODE_EXCL_FOLLOWER_PASSTHRU;
+ ret = ioctl(mCecFd, CEC_S_MODE, &mode);
+ if (ret) {
+ LOG(ERROR) << "Unable to set initiator mode, Error = " << strerror(errno);
+ release();
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+
+ /* thread loop for receiving cec messages and hotplug events*/
+ if (pthread_create(&mEventThread, NULL, event_thread, NULL)) {
+ LOG(ERROR) << "Can't create event thread: " << strerror(errno);
+ release();
+ return Result::FAILURE_NOT_SUPPORTED;
+ }
+
+ mCecEnabled = true;
+ mWakeupEnabled = true;
+ return Result::SUCCESS;
+}
+
+Return<void> HdmiCecDefault::release() {
+ if (mExitFd > 0) {
+ uint64_t tmp = 1;
+ write(mExitFd, &tmp, sizeof(tmp));
+ pthread_join(mEventThread, NULL);
+ }
+ if (mExitFd > 0) {
+ close(mExitFd);
+ }
+ if (mCecFd > 0) {
+ close(mCecFd);
+ }
+ mCecEnabled = false;
+ mWakeupEnabled = false;
+ setCallback(nullptr);
+ return Void();
+}
+
+void* HdmiCecDefault::event_thread(void*) {
+ struct pollfd ufds[3] = {
+ {mCecFd, POLLIN, 0},
+ {mCecFd, POLLERR, 0},
+ {mExitFd, POLLIN, 0},
+ };
+
+ while (1) {
+ ufds[0].revents = 0;
+ ufds[1].revents = 0;
+ ufds[2].revents = 0;
+
+ int ret = poll(ufds, /* size(ufds) = */ 3, /* timeout = */ -1);
+
+ if (ret <= 0) {
+ continue;
+ }
+
+ if (ufds[2].revents == POLLIN) { /* Exit */
+ break;
+ }
+
+ if (ufds[1].revents == POLLERR) { /* CEC Event */
+ struct cec_event ev;
+ ret = ioctl(mCecFd, CEC_DQEVENT, &ev);
+
+ if (!mCecEnabled) {
+ continue;
+ }
+
+ if (ret) {
+ LOG(ERROR) << "CEC_DQEVENT failed, Error = " << strerror(errno);
+ continue;
+ }
+
+ if (ev.event == CEC_EVENT_STATE_CHANGE) {
+ if (mCallback != nullptr) {
+ HotplugEvent hotplugEvent{
+ .connected = (ev.state_change.phys_addr != CEC_PHYS_ADDR_INVALID),
+ .portId = 1};
+ mCallback->onHotplugEvent(hotplugEvent);
+ } else {
+ LOG(ERROR) << "No event callback for hotplug";
+ }
+ }
+ }
+
+ if (ufds[0].revents == POLLIN) { /* CEC Driver */
+ struct cec_msg msg = {};
+ ret = ioctl(mCecFd, CEC_RECEIVE, &msg);
+
+ if (!mCecEnabled) {
+ continue;
+ }
+
+ if (ret) {
+ LOG(ERROR) << "CEC_RECEIVE failed, Error = " << strerror(errno);
+ continue;
+ }
+
+ if (msg.rx_status != CEC_RX_STATUS_OK) {
+ LOG(ERROR) << "msg rx_status = " << msg.rx_status;
+ continue;
+ }
+
+ if (!mWakeupEnabled && isWakeupMessage(msg)) {
+ LOG(DEBUG) << "Filter wakeup message";
+ continue;
+ }
+
+ if (mCallback != nullptr) {
+ size_t length = std::min(msg.len - 1, (uint32_t)MaxLength::MESSAGE_BODY);
+ CecMessage cecMessage{
+ .initiator = static_cast<CecLogicalAddress>(msg.msg[0] >> 4),
+ .destination = static_cast<CecLogicalAddress>(msg.msg[0] & 0xf),
+ };
+ cecMessage.body.resize(length);
+ for (size_t i = 0; i < length; ++i) {
+ cecMessage.body[i] = static_cast<uint8_t>(msg.msg[i + 1]);
+ }
+ mCallback->onCecMessage(cecMessage);
+ } else {
+ LOG(ERROR) << "no event callback for message";
+ }
+ }
+ }
+ return NULL;
+}
+
+int HdmiCecDefault::getOpcode(struct cec_msg message) {
+ return (static_cast<uint8_t>(message.msg[1]) & 0xff);
+}
+
+bool HdmiCecDefault::isWakeupMessage(struct cec_msg message) {
+ int opcode = getOpcode(message);
+ switch (opcode) {
+ case CEC_MESSAGE_TEXT_VIEW_ON:
+ case CEC_MESSAGE_IMAGE_VIEW_ON:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/cec/1.0/default/HdmiCecDefault.h b/tv/cec/1.0/default/HdmiCecDefault.h
new file mode 100644
index 0000000..c1bb2c7
--- /dev/null
+++ b/tv/cec/1.0/default/HdmiCecDefault.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <hardware/hdmi_cec.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_0 {
+namespace implementation {
+
+struct HdmiCecDefault : public IHdmiCec, public hidl_death_recipient {
+ HdmiCecDefault();
+ ~HdmiCecDefault();
+ // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+ Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
+ Return<void> clearLogicalAddress() override;
+ Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
+ Return<SendMessageResult> sendMessage(const CecMessage& message) override;
+ Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override;
+ Return<int32_t> getCecVersion() override;
+ Return<uint32_t> getVendorId() override;
+ Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
+ Return<void> setOption(OptionKey key, bool value) override;
+ Return<void> setLanguage(const hidl_string& language) override;
+ Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
+ Return<bool> isConnected(int32_t portId) override;
+
+ virtual void serviceDied(uint64_t, const wp<::android::hidl::base::V1_0::IBase>&) {
+ setCallback(nullptr);
+ }
+
+ Return<Result> init();
+ Return<void> release();
+ static void* event_thread(void*);
+ static int getOpcode(struct cec_msg message);
+ static bool isWakeupMessage(struct cec_msg message);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cec
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
index ad72fae..ed62cee 100644
--- a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service-lazy.rc
@@ -6,4 +6,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+ task_profiles ProcessCapacityHigh
diff --git a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
index 6d59ed7..5d5b943 100644
--- a/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
+++ b/tv/tuner/1.0/default/android.hardware.tv.tuner@1.0-service.rc
@@ -3,4 +3,4 @@
user media
group mediadrm drmrpc
ioprio rt 4
- writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
+ task_profiles ProcessCapacityHigh
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index c446afd..322833b 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -125,6 +125,11 @@
ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
int32_t* durationMs) {
+ std::vector<CompositePrimitive> supported;
+ getSupportedPrimitives(&supported);
+ if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
if (primitive != CompositePrimitive::NOOP) {
*durationMs = 100;
} else {