Merge "Allow users to switch between FE source and DVR source when testing record/descrambling/broadcast"
diff --git a/atrace/1.0/default/AtraceDevice.cpp b/atrace/1.0/default/AtraceDevice.cpp
index 4e82b0a..9f0c4c4 100644
--- a/atrace/1.0/default/AtraceDevice.cpp
+++ b/atrace/1.0/default/AtraceDevice.cpp
@@ -16,6 +16,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "AtraceDevice.h"
@@ -39,15 +40,11 @@
// gfx
{
"gfx",
- {"Graphics",
- {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
- {"/sys/kernel/debug/tracing/events/sde/enable", false},
- {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
+ {"Graphics", {{"mdss", false}, {"sde", false}, {"mali_systrace", false}}},
},
{
"ion",
- {"ION allocation",
- {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", false}}},
+ {"ION allocation", {{"kmem/ion_alloc_buffer_start", false}}},
},
};
@@ -65,16 +62,31 @@
return Void();
}
+AtraceDevice::AtraceDevice() {
+ struct stat st;
+
+ tracefs_event_root_ = "/sys/kernel/tracing/events/";
+ if (stat(tracefs_event_root_.c_str(), &st) != 0) {
+ tracefs_event_root_ = "/sys/kernel/debug/tracing/events/";
+ CHECK(stat(tracefs_event_root_.c_str(), &st) == 0) << "tracefs must be mounted at either"
+ "/sys/kernel/tracing or "
+ "/sys/kernel/debug/tracing";
+ }
+}
+
Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::enableCategories(
- const hidl_vec<hidl_string>& categories) {
+ const hidl_vec<hidl_string>& categories) {
if (!categories.size()) {
return Status::ERROR_INVALID_ARGUMENT;
}
+
for (auto& c : categories) {
if (kTracingMap.count(c)) {
for (auto& p : kTracingMap.at(c).paths) {
- if (!android::base::WriteStringToFile("1", p.first)) {
- LOG(ERROR) << "Failed to enable tracing on: " << p.first;
+ std::string tracefs_event_enable_path = android::base::StringPrintf(
+ "%s%s/enable", tracefs_event_root_.c_str(), p.first.c_str());
+ if (!android::base::WriteStringToFile("1", tracefs_event_enable_path)) {
+ LOG(ERROR) << "Failed to enable tracing on: " << tracefs_event_enable_path;
if (p.second) {
// disable before return
disableAllCategories();
@@ -91,10 +103,13 @@
Return<::android::hardware::atrace::V1_0::Status> AtraceDevice::disableAllCategories() {
auto ret = Status::SUCCESS;
+
for (auto& c : kTracingMap) {
for (auto& p : c.second.paths) {
- if (!android::base::WriteStringToFile("0", p.first)) {
- LOG(ERROR) << "Failed to disable tracing on: " << p.first;
+ std::string tracefs_event_enable_path = android::base::StringPrintf(
+ "%s%s/enable", tracefs_event_root_.c_str(), p.first.c_str());
+ if (!android::base::WriteStringToFile("0", tracefs_event_enable_path)) {
+ LOG(ERROR) << "Failed to disable tracing on: " << tracefs_event_enable_path;
if (p.second) {
ret = Status::ERROR_TRACING_POINT;
}
diff --git a/atrace/1.0/default/AtraceDevice.h b/atrace/1.0/default/AtraceDevice.h
index e700f89..ab87c65 100644
--- a/atrace/1.0/default/AtraceDevice.h
+++ b/atrace/1.0/default/AtraceDevice.h
@@ -36,12 +36,16 @@
using ::android::hardware::Void;
struct AtraceDevice : public IAtraceDevice {
+ AtraceDevice();
// Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
Return<void> listCategories(listCategories_cb _hidl_cb) override;
Return<::android::hardware::atrace::V1_0::Status> enableCategories(
const hidl_vec<hidl_string>& categories) override;
Return<::android::hardware::atrace::V1_0::Status> disableAllCategories() override;
+ private:
+ std::string tracefs_event_root_;
+
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
diff --git a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
index eb54c39..7110b45 100644
--- a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
+++ b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc
@@ -1,10 +1,14 @@
on late-init
# vendor graphics trace points
chmod 0666 /sys/kernel/debug/tracing/events/sde/enable
+ chmod 0666 /sys/kernel/tracing/events/sde/enable
chmod 0666 /sys/kernel/debug/tracing/events/mdss/enable
+ chmod 0666 /sys/kernel/tracing/events/mdss/enable
chmod 0666 /sys/kernel/debug/tracing/events/mali_systrace/enable
+ chmod 0666 /sys/kernel/tracing/events/mali_systrace/enable
# ion allocation trace point
chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable
+ chmod 0666 /sys/kernel/tracing/events/kmem/ion_alloc_buffer_start/enable
service vendor.atrace-hal-1-0 /vendor/bin/hw/android.hardware.atrace@1.0-service
interface android.hardware.atrace@1.0::IAtraceDevice default
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
index eb8c2dd..b5b3925 100644
--- a/audio/7.0/config/api/current.txt
+++ b/audio/7.0/config/api/current.txt
@@ -45,6 +45,8 @@
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_NONE;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+ enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd
index 007e250..4f5614b 100644
--- a/audio/7.0/config/audio_policy_configuration.xsd
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -504,6 +504,8 @@
<xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
<xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
<xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
<xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
<xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
<xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
diff --git a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
index 7d83556..fe3e4ea 100644
--- a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
+++ b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
@@ -94,6 +94,7 @@
case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT4:
case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_12:
return 12;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_13POINT_360RA:
case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_13:
return 13;
case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_14:
@@ -116,6 +117,7 @@
return 22;
case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_23:
return 23;
+ case AudioChannelMask::AUDIO_CHANNEL_OUT_22POINT2:
case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_24:
return 24;
case AudioChannelMask::UNKNOWN:
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index f24b1f5..c13efde 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -91,13 +91,13 @@
"impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
"impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
"impl/vhal_v2_0/GeneratorHub.cpp",
+ "impl/vhal_v2_0/qemu_pipe.cpp",
],
local_include_dirs: ["common/include/vhal_v2_0"],
export_include_dirs: ["impl"],
whole_static_libs: [
"android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
"android.hardware.automotive.vehicle@2.0-manager-lib",
- "libqemu_pipe",
],
shared_libs: [
"libbase",
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
index f024287..81e7c78 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
@@ -18,9 +18,9 @@
#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <log/log.h>
-#include <qemu_pipe.h>
#include "PipeComm.h"
+#include "qemu_pipe.h"
#define CAR_SERVICE_NAME "pipe:qemud:car"
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.cpp
new file mode 100644
index 0000000..cf1a002
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 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 "qemu_pipe.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+
+using android::base::ReadFully;
+using android::base::WriteFully;
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+#define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+int qemu_pipe_open(const char* pipeName) {
+ if (!pipeName) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ if (WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+
+ // now, add 'pipe:' prefix and try again
+ // Note: host side will wait for the trailing '\0' to start
+ // service lookup.
+ const char pipe_prefix[] = "pipe:";
+ if (WriteFully(fd, pipe_prefix, strlen(pipe_prefix)) &&
+ WriteFully(fd, pipeName, pipeNameLen + 1U)) {
+ return fd;
+ }
+ QEMU_PIPE_DEBUG("%s: Could not write to %s pipe service: %s", __FUNCTION__, pipeName,
+ strerror(errno));
+ close(fd);
+ return -1;
+}
+
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04zx", len);
+ if (!WriteFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ if (!WriteFully(fd, buff, len)) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ if (!ReadFully(fd, header, 4)) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size, len);
+ return -1;
+ }
+ if (!ReadFully(fd, buff, size)) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return size;
+}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.h
new file mode 100644
index 0000000..0987498
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/qemu_pipe.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+#define ANDROID_CORE_INCLUDE_QEMU_PIPE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and should begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+// For backward compatibility, the 'pipe:' prefix can be omitted, and in
+// that case, qemu_pipe_open will add it for you.
+
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+int qemu_pipe_open(const char* pipeName);
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+int qemu_pipe_frame_send(int fd, const void* buff, size_t len);
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+int qemu_pipe_frame_recv(int fd, void* buff, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_CORE_INCLUDE_QEMU_PIPE_H */
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 4806fef..768142c 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -31,6 +31,7 @@
"android.hardware.bluetooth@1.0",
"libbluetooth-types",
],
+ test_config: "VtsHalBluetoothV1_0TargetTest.xml",
test_suites: [
"general-tests",
"vts",
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
new file mode 100644
index 0000000..09463c9
--- /dev/null
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalBluetoothV1_0TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="bluetooth" value="off" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalBluetoothV1_0TargetTest->/data/local/tmp/VtsHalBluetoothV1_0TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalBluetoothV1_0TargetTest" />
+ </test>
+</configuration>
diff --git a/bluetooth/1.1/vts/functional/Android.bp b/bluetooth/1.1/vts/functional/Android.bp
index e64d5a9..7f56647 100644
--- a/bluetooth/1.1/vts/functional/Android.bp
+++ b/bluetooth/1.1/vts/functional/Android.bp
@@ -32,5 +32,6 @@
"android.hardware.bluetooth@1.0",
"libbluetooth-types",
],
+ test_config: "VtsHalBluetoothV1_1TargetTest.xml",
test_suites: ["general-tests", "vts"],
}
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
new file mode 100644
index 0000000..d64751a
--- /dev/null
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalBluetoothV1_1TargetTest.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="bluetooth" value="off" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalBluetoothV1_1TargetTest->/data/local/tmp/VtsHalBluetoothV1_1TargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalBluetoothV1_1TargetTest" />
+ </test>
+</configuration>
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
new file mode 100644
index 0000000..a438031
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.common;
+@VintfStability
+parcelable Ashmem {
+ ParcelFileDescriptor fd;
+ long size;
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
new file mode 100644
index 0000000..394ea8f
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.common;
+@VintfStability
+parcelable MappableFile {
+ long length;
+ int prot;
+ ParcelFileDescriptor fd;
+ long offset;
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
index f37b7d5..2ed5c0b 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/common/aidl/android/hardware/common/Ashmem.aidl b/common/aidl/android/hardware/common/Ashmem.aidl
new file mode 100644
index 0000000..8e40266
--- /dev/null
+++ b/common/aidl/android/hardware/common/Ashmem.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Type that holds same memory as the "ashmem" hidl_memory type from HIDL.
+ */
+@VintfStability
+parcelable Ashmem {
+ /**
+ * A handle to a memory region.
+ */
+ ParcelFileDescriptor fd;
+ /**
+ * Size of the memory region in bytes.
+ */
+ long size;
+}
diff --git a/common/aidl/android/hardware/common/MappableFile.aidl b/common/aidl/android/hardware/common/MappableFile.aidl
new file mode 100644
index 0000000..a7763ea
--- /dev/null
+++ b/common/aidl/android/hardware/common/MappableFile.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * A region of a file that can be mapped into memory.
+ *
+ * In Linux, MappableFile may be used with mmap as `MAP_SHARED`.
+ *
+ * MappableFile is compatible with ::android::base::MappedFile.
+ */
+@VintfStability
+parcelable MappableFile {
+ /**
+ * Length of the mapping region in bytes.
+ */
+ long length;
+ /**
+ * The desired memory protection for the mapping.
+ *
+ * In Linux, prot is either `PROT_NONE` (indicating that mapped pages may not be accessed) or
+ * the bitwise OR of one or more of the following flags:
+ * - `PROT_READ` (indicating that the mapped pages may be read)
+ * - `PROT_WRITE` (indicating that the mapped pages may be written)
+ */
+ int prot;
+ /**
+ * A handle to a mappable file.
+ */
+ ParcelFileDescriptor fd;
+ /**
+ * The offset in the file to the beginning of the mapping region in number of bytes.
+ *
+ * Note: Some mapping functions require that the offset is aligned to the page size.
+ */
+ long offset;
+}
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 8aea306..730798d 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -18,6 +18,11 @@
"android.hardware.common-V2-ndk_platform",
"libcutils",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.neuralnetworks",
+ ],
+ min_sdk_version: "29",
}
cc_test {
diff --git a/current.txt b/current.txt
index 454d43e..0b6f698 100644
--- a/current.txt
+++ b/current.txt
@@ -776,8 +776,8 @@
dabe23dde7c9e3ad65c61def7392f186d7efe7f4216f9b6f9cf0863745b1a9f4 android.hardware.keymaster@4.1::IKeymasterDevice
cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
f729ee6a5f136b25d79ea6895d24700fce413df555baaecf2c39e4440d15d043 android.hardware.neuralnetworks@1.0::types
-a84f8dac7a9b75de1cc2936a9b429b9b62b32a31ea88ca52c29f98f5ddc0fa95 android.hardware.neuralnetworks@1.2::types
-cd331b92312d16ab89f475c39296abbf539efc4114a8c5c2b136ad99b904ef33 android.hardware.neuralnetworks@1.3::types
+38c1a3eb5c3dfa4cc40b7cf4be0e9850440e2c57197fba7407081679b358aa22 android.hardware.neuralnetworks@1.2::types
+550619f876cadbea1f718edce120f0e1dd4a6f4bd4c28b59d479677dc86b0aec android.hardware.neuralnetworks@1.3::types
c3fec5bd470984402997f78a74b6511efc4063b270f2bd9ee7b78f48b683a1bb android.hardware.neuralnetworks@1.3::IDevice
0fdfad62c2ec33b52e6687004e5a1971c02d10b93ee4d26df5ccff7ce032494a android.hardware.neuralnetworks@1.3::IPreparedModel
e8c86c69c438da8d1549856c1bb3e2d1b8da52722f8235ff49a30f2cce91742c android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
@@ -793,5 +793,45 @@
2b5afef68e3e2ff1dab63e4f2ee57337ef2635ec812f49080cadfce966d33b52 android.hardware.radio@1.2::IRadio
# HALs released in Android S
-# NOTE: waiting to freeze HALs until later in the release
-# NOTE: new HALs are recommended to be in AIDL
+59fa68432e374c8d3b7ec098a91a1e023a2c728110bb733237c551afa5929725 android.hardware.audio@7.0::IDevice
+2207948ca127b801c94f667c99dfd139f150b50671e1408d3e855d03efbf631d android.hardware.audio@7.0::IDevicesFactory
+1d201e15c553cd44c62864ac8d7039351ddf048a7ee61e380f6efb0904442eb8 android.hardware.audio@7.0::IPrimaryDevice
+38afa920e6d36013b5a800e8c82eefeebd24602de24441e2f8ce5b3bdf62d3af android.hardware.audio@7.0::IStream
+77d84330418abba5a92b0cdc4e27fa7c85c27344eaf7eeef441b8e88829ee475 android.hardware.audio@7.0::IStreamIn
+9e4d79ed8f3c7e18455f371342ea1802f080bae38f64db746cc433305ee1978b android.hardware.audio@7.0::IStreamOut
+54cbc3c637fe8d4b889ccb5690e5e3069ca8efd9c6607ce1d021a3f47576c67e android.hardware.audio@7.0::IStreamOutCallback
+8036ae0a68a698a79207218018de5f41aed344723f644112ffc99e20e5e2e9ff android.hardware.audio@7.0::IStreamOutEventCallback
+84978dbd15d4fa8be6073d0974755f7718ee0cde519ce71449fb734f53cee46b android.hardware.audio@7.0::types
+6a03a9d8cc917da00e8b88f4abc42db2f741e2d50901e8ab6dea32084a238fbd android.hardware.audio.common@7.0::types
+842b4485a00005fb938f674b12445cb592cd1636f56c7cc447966119070811bd android.hardware.audio.effect@7.0::IAcousticEchoCancelerEffect
+b62a85e5d745dc35b5a60464c6b33a5bb7a2b8b95863a1374aee77ea29cf8f49 android.hardware.audio.effect@7.0::IAutomaticGainControlEffect
+c8d5e30848191713db7cffccc482e4427816f33c98a24734c8769962f79f855b android.hardware.audio.effect@7.0::IBassBoostEffect
+7d021ecdf5bb6a61eb9ad193585d4986d1a64cb7fb4b52f219d7380145f2c6f1 android.hardware.audio.effect@7.0::IDownmixEffect
+7fee1e7c7bb3d513a524c8963d1f8f7c2ad856f26c745b4ebc286b40d503264a android.hardware.audio.effect@7.0::IEffect
+7596050ccc00234458dcb4e692056ed3c16f3618c11d7b17cb749cfd5713705d android.hardware.audio.effect@7.0::IEffectBufferProviderCallback
+f2e41467bcf1140a11b219c2e8f77981b955c2941befe66e1cc685b7863ae4c9 android.hardware.audio.effect@7.0::IEffectsFactory
+af66fb4addbc477f9fea65fb63475203122a9189624ca8d14e757bc7826d60a4 android.hardware.audio.effect@7.0::IEnvironmentalReverbEffect
+2878d007ed55e1a4149ddcd29606962c948d8610642276f91dffd5ed32281824 android.hardware.audio.effect@7.0::IEqualizerEffect
+0260ef9e2a3e077de366ebebc0c117c7ee13f46a1eabd4abd66cc6245d0bed98 android.hardware.audio.effect@7.0::ILoudnessEnhancerEffect
+3586bbc3a7cbe30f9aff0a522524eea9b78eea78280f09c35d43dbab48a1193e android.hardware.audio.effect@7.0::INoiseSuppressionEffect
+a7d74d7e7e0b1e3b739f233b7776bf01e868856a536f5cdac0f307e9c2850e64 android.hardware.audio.effect@7.0::IPresetReverbEffect
+b4cbc1f2d38787f2ad069a8e4d10c0896287531a2596f0de0283e390b0ecf05d android.hardware.audio.effect@7.0::IVirtualizerEffect
+2b5681e1ea6a2db0dc1e84edb96d3de2f7daf306046543e7956be76dcb8f20fb android.hardware.audio.effect@7.0::IVisualizerEffect
+fa1e2d78e66fd662de93cb479ffd55947fe54f51cb53915814b3d3e3036c86a5 android.hardware.audio.effect@7.0::types
+4baf8e0eca4aa896cc9ceb7bb676aaf4fa21372ef8b49eed68eced1221c3dc0d android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvider
+d417a9212c8f96e3a06a2f221c8c5756c765355b2b81de2b2a65d4c9eee85401 android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvidersFactory
+c17d9e27abd37ae5a8ff8da08fc5c9b13a264670feef6bbbc9d3ab1915216130 android.hardware.bluetooth.audio@2.1::types
+6763dd2273b1b47f3ac68af9b66870287eba33fb5b4d66e8fe1d30ae18ce24cb android.hardware.boot@1.2::IBootControl
+0c0657fad2239c2c7ec363d3b13f2e002d1c267ca89d2cc96d2b1de0475386cb android.hardware.fastboot@1.1::IFastboot
+3e8866987de4ecb48807c09d4c88ec38365930a22415f1b74edf8b14da17846b android.hardware.radio@1.6::IRadio
+715789427a44cc78f9d123b0ceb9e035e4ac2b1049501337c23a512e85b87850 android.hardware.radio@1.6::IRadioIndication
+2e9c08c4bc9539d8da28d7de33500f87148f7fa2e377238ee898b41752ac4f29 android.hardware.radio@1.6::IRadioResponse
+6475887a9cd5cc8cb803e3a78956d84d7a5fde571407ede2396f3ea5e0c0d3ad android.hardware.radio@1.6::types
+f22813615be1445ddd817655c054fc69dc9efea56c9035cd0757f3cbed190641 android.hardware.radio.config@1.3::IRadioConfig
+c9ad18729268593d14681d88ffad1c97e707444a45e1b4ed804dab949edbd84f android.hardware.radio.config@1.3::IRadioConfigResponse
+78dcb9a6975e8b377cb90bbe952078162960941468c992dcd2e1830a477b8c03 android.hardware.radio.config@1.3::types
+fd43298c43f70130c747a642ee43b0c242ac0cebffb377faa24f2725f0aa6caf android.hardware.tetheroffload.control@1.1::IOffloadControl
+fe18c9032e4063efca3fff3c377dd69780de1f96e8e2bc3f7d100a5d8bd467b4 android.hardware.tetheroffload.control@1.1::ITetheringOffloadCallback
+e34b4c7bec5e032c14804707ca924dd6b99ed5ba139da7505fe7d698d0fe178f android.hardware.tetheroffload.control@1.1::types
+
+# There should be no more HIDL HALs - please use AIDL instead.
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 2db3607..e6d4e84 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -124,7 +124,11 @@
return Void();
}
- if (source.offset + offset + source.size > sourceBase->getSize()) {
+ size_t totalSize = 0;
+ if (__builtin_add_overflow(source.offset, offset, &totalSize) ||
+ __builtin_add_overflow(totalSize, source.size, &totalSize) ||
+ totalSize > sourceBase->getSize()) {
+ android_errorWriteLog(0x534e4554, "176496160");
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
return Void();
}
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 2a46f9d..cadd13c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -34,6 +34,7 @@
apex_available: [
"//apex_available:platform",
"com.android.media.swcodec",
+ "com.android.neuralnetworks",
],
min_sdk_version: "29",
},
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl
index 8b12169..232e023 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -21,7 +21,7 @@
int width;
int height;
int layers;
- android.hardware.graphics.common.PixelFormat format;
- android.hardware.graphics.common.BufferUsage usage;
+ android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
+ android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
int stride;
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
index e1e3492..078c512 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -29,7 +29,7 @@
int width;
int height;
int layers;
- PixelFormat format;
- BufferUsage usage;
+ PixelFormat format = PixelFormat.UNSPECIFIED;
+ BufferUsage usage = BufferUsage.CPU_READ_NEVER;
int stride;
}
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 50f282f..46f95dd 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -73,10 +73,15 @@
IComposerClient::Rect getFrameRect() const { return {0, 0, mDisplayWidth, mDisplayHeight}; }
+ void setDimensions(int32_t displayWidth, int32_t displayHeight) {
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ }
+
private:
const Display mDisplay;
- const int32_t mDisplayWidth;
- const int32_t mDisplayHeight;
+ int32_t mDisplayWidth;
+ int32_t mDisplayHeight;
};
class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
@@ -194,6 +199,31 @@
const std::vector<ContentType>& capabilities,
const ContentType& contentType, const char* contentTypeStr);
+ Error setActiveConfigWithConstraints(
+ VtsDisplay& display, Config config,
+ const IComposerClient::VsyncPeriodChangeConstraints& constraints,
+ VsyncPeriodChangeTimeline* timeline) {
+ const auto error = mComposerClient->setActiveConfigWithConstraints(display.get(), config,
+ constraints, timeline);
+ if (error == Error::NONE) {
+ const int32_t displayWidth = mComposerClient->getDisplayAttribute_2_4(
+ display.get(), config, IComposerClient::Attribute::WIDTH);
+ const int32_t displayHeight = mComposerClient->getDisplayAttribute_2_4(
+ display.get(), config, IComposerClient::Attribute::HEIGHT);
+ display.setDimensions(displayWidth, displayHeight);
+ }
+ return error;
+ }
+
+ void setActiveConfig(VtsDisplay& display, Config config) {
+ mComposerClient->setActiveConfig(display.get(), config);
+ const int32_t displayWidth = mComposerClient->getDisplayAttribute_2_4(
+ display.get(), config, IComposerClient::Attribute::WIDTH);
+ const int32_t displayHeight = mComposerClient->getDisplayAttribute_2_4(
+ display.get(), config, IComposerClient::Attribute::HEIGHT);
+ display.setDimensions(displayWidth, displayHeight);
+ }
+
private:
// use the slot count usually set by SF
static constexpr uint32_t kBufferSlotCount = 64;
@@ -347,7 +377,7 @@
}
TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) {
- for (const auto& display : mDisplays) {
+ for (VtsDisplay& display : mDisplays) {
for (Config config : mComposerClient->getDisplayConfigs(display.get())) {
VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4(
display.get(), config,
@@ -358,8 +388,8 @@
constraints.desiredTimeNanos = systemTime();
constraints.seamlessRequired = false;
- EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
- display.get(), config, constraints, &timeline));
+ EXPECT_EQ(Error::NONE,
+ setActiveConfigWithConstraints(display, config, constraints, &timeline));
if (timeline.refreshRequired) {
sendRefreshFrame(display, &timeline);
@@ -411,11 +441,10 @@
constraints.seamlessRequired = false;
constraints.desiredTimeNanos = systemTime();
- for (const auto& display : mDisplays) {
+ for (VtsDisplay& display : mDisplays) {
Config invalidConfigId = GetInvalidConfigId(display.get());
EXPECT_EQ(Error::BAD_CONFIG,
- mComposerClient->setActiveConfigWithConstraints(display.get(), invalidConfigId,
- constraints, &timeline));
+ setActiveConfigWithConstraints(display, invalidConfigId, constraints, &timeline));
}
}
@@ -426,7 +455,7 @@
constraints.seamlessRequired = true;
constraints.desiredTimeNanos = systemTime();
- for (const auto& display : mDisplays) {
+ for (VtsDisplay& display : mDisplays) {
forEachTwoConfigs(display.get(), [&](Config config1, Config config2) {
const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4(
display.get(), config1,
@@ -435,11 +464,10 @@
display.get(), config2,
IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
if (configGroup1 != configGroup2) {
- mComposerClient->setActiveConfig(display.get(), config1);
+ setActiveConfig(display, config1);
sendRefreshFrame(display, nullptr);
EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
- mComposerClient->setActiveConfigWithConstraints(display.get(), config2,
- constraints, &timeline));
+ setActiveConfigWithConstraints(display, config2, constraints, &timeline));
}
});
}
@@ -502,6 +530,8 @@
mWriter->presentDisplay();
execute();
+
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(display.get(), layer));
}
void GraphicsComposerHidlTest::waitForVsyncPeriodChange(Display display,
@@ -523,9 +553,9 @@
}
void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints(const TestParameters& params) {
- for (const auto& display : mDisplays) {
+ for (VtsDisplay& display : mDisplays) {
forEachTwoConfigs(display.get(), [&](Config config1, Config config2) {
- mComposerClient->setActiveConfig(display.get(), config1);
+ setActiveConfig(display, config1);
sendRefreshFrame(display, nullptr);
int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4(
@@ -543,8 +573,8 @@
IComposerClient::VsyncPeriodChangeConstraints constraints = {
.desiredTimeNanos = systemTime() + params.delayForChange,
.seamlessRequired = false};
- EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
- display.get(), config2, constraints, &timeline));
+ EXPECT_EQ(Error::NONE,
+ setActiveConfigWithConstraints(display, config2, constraints, &timeline));
EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
// Refresh rate should change within a reasonable time
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index a097895..3224e4b 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -43,8 +43,8 @@
void startRetrieval(in android.hardware.identity.SecureAccessControlProfile[] accessControlProfiles, in android.hardware.keymaster.HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);
byte[] retrieveEntryValue(in byte[] encryptedContent);
- void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
- android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
+ @SuppressWarnings(value={"out-array"}) void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
+ @SuppressWarnings(value={"out-array"}) android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
byte[] deleteCredentialWithChallenge(in byte[] challenge);
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
index a713462..19a29ec 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -38,6 +38,6 @@
android.hardware.identity.SecureAccessControlProfile addAccessControlProfile(in int id, in android.hardware.identity.Certificate readerCertificate, in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId);
void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize);
byte[] addEntryValue(in byte[] content);
- void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature);
+ @SuppressWarnings(value={"out-array"}) void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature);
void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index d23f88c..8ae293b 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -324,6 +324,7 @@
*
* @param out deviceNameSpaces the bytes of DeviceNameSpaces.
*/
+ @SuppressWarnings(value={"out-array"})
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
/**
@@ -376,6 +377,7 @@
*
* @return an X.509 certificate for the new signing key, signed by the credential key.
*/
+ @SuppressWarnings(value={"out-array"})
Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
/**
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 5f878ee..22bcf61 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -320,6 +320,7 @@
* "accessControlProfiles" : [ * uint ],
* }
*/
+ @SuppressWarnings(value={"out-array"})
void finishAddingEntries(out byte[] credentialData,
out byte[] proofOfProvisioningSignature);
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 05b3662..7c68aee 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -31,7 +31,8 @@
],
static_libs: [
"libbase",
- "libcppbor",
+ "libcppbor_external",
+ "libcppcose_rkp",
"libutils",
"libsoft_attestation_cert",
"libkeymaster_portable",
@@ -91,7 +92,8 @@
],
static_libs: [
"libbase",
- "libcppbor",
+ "libcppbor_external",
+ "libcppcose_rkp",
"libutils",
"libsoft_attestation_cert",
"libkeymaster_portable",
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index c8ee0dd..95557b5 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -488,7 +488,7 @@
}
for (size_t n = 0; n < nsMap->size(); n++) {
- auto [nsKeyItem, nsValueItem] = (*nsMap)[n];
+ auto& [nsKeyItem, nsValueItem] = (*nsMap)[n];
const cppbor::Tstr* nsKey = nsKeyItem->asTstr();
const cppbor::Map* nsInnerMap = nsValueItem->asMap();
if (nsKey == nullptr || nsInnerMap == nullptr) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 9913b86..ef9d133 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -27,7 +27,7 @@
#include <string>
#include <vector>
-#include <cppbor/cppbor.h>
+#include <cppbor.h>
#include "IdentityCredentialStore.h"
#include "SecureHardwareProxy.h"
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 2d897c7..25f129b 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -23,8 +23,8 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include <cppbor/cppbor.h>
-#include <cppbor/cppbor_parse.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
#include <utility>
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 82c4011..61d15d2 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -34,7 +34,8 @@
"libcrypto",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
+ "libcppcose_rkp",
"libkeymaster_portable",
"libpuresoftkeymasterdevice",
"android.hardware.keymaster@4.0",
diff --git a/identity/aidl/vts/AuthenticationKeyTests.cpp b/identity/aidl/vts/AuthenticationKeyTests.cpp
index bda3e70..25d74d4 100644
--- a/identity/aidl/vts/AuthenticationKeyTests.cpp
+++ b/identity/aidl/vts/AuthenticationKeyTests.cpp
@@ -118,7 +118,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/DeleteCredentialTests.cpp b/identity/aidl/vts/DeleteCredentialTests.cpp
index 1d30067..d3addf4 100644
--- a/identity/aidl/vts/DeleteCredentialTests.cpp
+++ b/identity/aidl/vts/DeleteCredentialTests.cpp
@@ -126,7 +126,7 @@
optional<vector<uint8_t>> proofOfDeletion =
support::coseSignGetPayload(proofOfDeletionSignature);
ASSERT_TRUE(proofOfDeletion);
- string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', true, ]", cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {}, // Additional data
credentialPubKey_));
@@ -153,7 +153,7 @@
optional<vector<uint8_t>> proofOfDeletion =
support::coseSignGetPayload(proofOfDeletionSignature);
ASSERT_TRUE(proofOfDeletion);
- string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', {0x41, 0x42, 0x43}, true, ]",
cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {}, // Additional data
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 5798b4c..67db915 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -231,7 +231,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -339,8 +339,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes =
@@ -353,7 +353,7 @@
.add("Home address", true))
.add("Image", cppbor::Map().add("Portrait image", false)))
.encode();
- cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
+ cborPretty = cppbor::prettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
EXPECT_EQ(
"{\n"
" 'nameSpaces' : {\n"
@@ -373,10 +373,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerKey, {}, // content
encodedReaderAuthenticationBytes, // detached content
@@ -443,7 +443,7 @@
vector<uint8_t> mac;
vector<uint8_t> deviceNameSpacesEncoded;
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ(
"{\n"
" 'PersonalData' : {\n"
@@ -462,10 +462,11 @@
string docType = "org.iso.18013-5.2019.mdl";
optional<vector<uint8_t>> readerEphemeralPrivateKey =
support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
- optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
- readerEphemeralPrivateKey.value(), // Private Key
- signingPubKey.value(), // Public Key
- cppbor::Semantic(24, sessionTranscript.encode()).encode()); // SessionTranscriptBytes
+ optional<vector<uint8_t>> eMacKey =
+ support::calcEMacKey(readerEphemeralPrivateKey.value(), // Private Key
+ signingPubKey.value(), // Public Key
+ cppbor::SemanticTag(24, sessionTranscript.encode())
+ .encode()); // SessionTranscriptBytes
optional<vector<uint8_t>> calculatedMac =
support::calcMac(sessionTranscript.encode(), // SessionTranscript
docType, // DocType
@@ -486,7 +487,7 @@
testEntriesEntryCounts)
.isOk());
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
@@ -508,7 +509,7 @@
testEntriesEntryCounts)
.isOk());
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
diff --git a/identity/aidl/vts/ProveOwnershipTests.cpp b/identity/aidl/vts/ProveOwnershipTests.cpp
index d1a3d39..fa0e293 100644
--- a/identity/aidl/vts/ProveOwnershipTests.cpp
+++ b/identity/aidl/vts/ProveOwnershipTests.cpp
@@ -131,7 +131,7 @@
optional<vector<uint8_t>> proofOfOwnership =
support::coseSignGetPayload(proofOfOwnershipSignature);
ASSERT_TRUE(proofOfOwnership);
- string cborPretty = support::cborPrettyPrint(proofOfOwnership.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfOwnership.value(), 32, {});
EXPECT_EQ("['ProofOfOwnership', 'org.iso.18013-5.2019.mdl', {0x11, 0x12}, true, ]", cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfOwnershipSignature, {}, // Additional data
credentialPubKey_));
diff --git a/identity/aidl/vts/ReaderAuthTests.cpp b/identity/aidl/vts/ReaderAuthTests.cpp
index 7656c8e..c4a58c3 100644
--- a/identity/aidl/vts/ReaderAuthTests.cpp
+++ b/identity/aidl/vts/ReaderAuthTests.cpp
@@ -262,8 +262,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
@@ -293,10 +293,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerPrivateKey, // private key for reader
@@ -517,8 +517,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
@@ -535,10 +535,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
optional<vector<uint8_t>> readerSignature =
diff --git a/identity/aidl/vts/TestCredentialTests.cpp b/identity/aidl/vts/TestCredentialTests.cpp
index d53de3b..46c2229 100644
--- a/identity/aidl/vts/TestCredentialTests.cpp
+++ b/identity/aidl/vts/TestCredentialTests.cpp
@@ -114,7 +114,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UpdateCredentialTests.cpp b/identity/aidl/vts/UpdateCredentialTests.cpp
index 9c5ca55..e05bb3b 100644
--- a/identity/aidl/vts/UpdateCredentialTests.cpp
+++ b/identity/aidl/vts/UpdateCredentialTests.cpp
@@ -114,7 +114,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -195,7 +195,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UserAuthTests.cpp b/identity/aidl/vts/UserAuthTests.cpp
index ef89d1c..edd1725 100644
--- a/identity/aidl/vts/UserAuthTests.cpp
+++ b/identity/aidl/vts/UserAuthTests.cpp
@@ -160,8 +160,8 @@
// Let SessionTranscript be a map here (it's an array in EndToEndTest) just
// to check that the implementation can deal with either.
cppbor::Map sessionTranscript;
- sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes));
- sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes));
+ sessionTranscript.add(42, cppbor::SemanticTag(24, deviceEngagementBytes));
+ sessionTranscript.add(43, cppbor::SemanticTag(24, eReaderPubBytes));
return sessionTranscript;
}
@@ -209,7 +209,7 @@
vector<uint8_t> dataToSign = cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript_.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
}
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index cc63c48..bc37020 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -338,8 +338,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty =
- support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -449,9 +448,9 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(),
- 32, //
- {"readerCertificate"});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(),
+ 32, //
+ {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index d00f59a..db1a945 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -35,6 +35,7 @@
"android.hardware.keymaster@4.0",
"libcrypto",
"libbase",
+ "libcppcose_rkp",
"libhidlbase",
"libhardware",
"libkeymaster_portable",
@@ -42,7 +43,7 @@
"libpuresoftkeymasterdevice",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
],
}
@@ -59,7 +60,7 @@
"libhardware",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
"libgmock",
],
test_suites: ["general-tests"],
@@ -89,7 +90,7 @@
"tests/cppbor_test.cpp",
],
shared_libs: [
- "libcppbor",
+ "libcppbor_external",
"libbase",
],
static_libs: [
@@ -104,7 +105,7 @@
"tests/cppbor_test.cpp",
],
shared_libs: [
- "libcppbor",
+ "libcppbor_external",
"libbase",
],
static_libs: [
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index aba89c1..4547624 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -148,199 +148,6 @@
}
// ---------------------------------------------------------------------------
-// CBOR utilities.
-// ---------------------------------------------------------------------------
-
-static bool cborAreAllElementsNonCompound(const cppbor::CompoundItem* compoundItem) {
- if (compoundItem->type() == cppbor::ARRAY) {
- const cppbor::Array* array = compoundItem->asArray();
- for (size_t n = 0; n < array->size(); n++) {
- const cppbor::Item* entry = (*array)[n].get();
- switch (entry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- }
- } else {
- const cppbor::Map* map = compoundItem->asMap();
- for (size_t n = 0; n < map->size(); n++) {
- auto [keyEntry, valueEntry] = (*map)[n];
- switch (keyEntry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- switch (valueEntry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- }
- }
- return true;
-}
-
-static bool cborPrettyPrintInternal(const cppbor::Item* item, string& out, size_t indent,
- size_t maxBStrSize, const vector<string>& mapKeysToNotPrint) {
- char buf[80];
-
- string indentString(indent, ' ');
-
- switch (item->type()) {
- case cppbor::UINT:
- snprintf(buf, sizeof(buf), "%" PRIu64, item->asUint()->unsignedValue());
- out.append(buf);
- break;
-
- case cppbor::NINT:
- snprintf(buf, sizeof(buf), "%" PRId64, item->asNint()->value());
- out.append(buf);
- break;
-
- case cppbor::BSTR: {
- const cppbor::Bstr* bstr = item->asBstr();
- const vector<uint8_t>& value = bstr->value();
- if (value.size() > maxBStrSize) {
- unsigned char digest[SHA_DIGEST_LENGTH];
- SHA_CTX ctx;
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, value.data(), value.size());
- SHA1_Final(digest, &ctx);
- char buf2[SHA_DIGEST_LENGTH * 2 + 1];
- for (size_t n = 0; n < SHA_DIGEST_LENGTH; n++) {
- snprintf(buf2 + n * 2, 3, "%02x", digest[n]);
- }
- snprintf(buf, sizeof(buf), "<bstr size=%zd sha1=%s>", value.size(), buf2);
- out.append(buf);
- } else {
- out.append("{");
- for (size_t n = 0; n < value.size(); n++) {
- if (n > 0) {
- out.append(", ");
- }
- snprintf(buf, sizeof(buf), "0x%02x", value[n]);
- out.append(buf);
- }
- out.append("}");
- }
- } break;
-
- case cppbor::TSTR:
- out.append("'");
- {
- // TODO: escape "'" characters
- out.append(item->asTstr()->value().c_str());
- }
- out.append("'");
- break;
-
- case cppbor::ARRAY: {
- const cppbor::Array* array = item->asArray();
- if (array->size() == 0) {
- out.append("[]");
- } else if (cborAreAllElementsNonCompound(array)) {
- out.append("[");
- for (size_t n = 0; n < array->size(); n++) {
- if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(", ");
- }
- out.append("]");
- } else {
- out.append("[\n" + indentString);
- for (size_t n = 0; n < array->size(); n++) {
- out.append(" ");
- if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(",\n" + indentString);
- }
- out.append("]");
- }
- } break;
-
- case cppbor::MAP: {
- const cppbor::Map* map = item->asMap();
-
- if (map->size() == 0) {
- out.append("{}");
- } else {
- out.append("{\n" + indentString);
- for (size_t n = 0; n < map->size(); n++) {
- out.append(" ");
-
- auto [map_key, map_value] = (*map)[n];
-
- if (!cborPrettyPrintInternal(map_key.get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(" : ");
- if (map_key->type() == cppbor::TSTR &&
- std::find(mapKeysToNotPrint.begin(), mapKeysToNotPrint.end(),
- map_key->asTstr()->value()) != mapKeysToNotPrint.end()) {
- out.append("<not printed>");
- } else {
- if (!cborPrettyPrintInternal(map_value.get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- }
- out.append(",\n" + indentString);
- }
- out.append("}");
- }
- } break;
-
- case cppbor::SEMANTIC: {
- const cppbor::Semantic* semantic = item->asSemantic();
- snprintf(buf, sizeof(buf), "tag %" PRIu64 " ", semantic->value());
- out.append(buf);
- cborPrettyPrintInternal(semantic->child().get(), out, indent, maxBStrSize,
- mapKeysToNotPrint);
- } break;
-
- case cppbor::SIMPLE:
- const cppbor::Bool* asBool = item->asSimple()->asBool();
- const cppbor::Null* asNull = item->asSimple()->asNull();
- if (asBool != nullptr) {
- out.append(asBool->value() ? "true" : "false");
- } else if (asNull != nullptr) {
- out.append("null");
- } else {
- LOG(ERROR) << "Only boolean/null is implemented for SIMPLE";
- return false;
- }
- break;
- }
-
- return true;
-}
-
-string cborPrettyPrint(const vector<uint8_t>& encodedCbor, size_t maxBStrSize,
- const vector<string>& mapKeysToNotPrint) {
- auto [item, _, message] = cppbor::parse(encodedCbor);
- if (item == nullptr) {
- LOG(ERROR) << "Data to pretty print is not valid CBOR: " << message;
- return "";
- }
-
- string out;
- cborPrettyPrintInternal(item.get(), out, 0, maxBStrSize, mapKeysToNotPrint);
- return out;
-}
-
-// ---------------------------------------------------------------------------
// Crypto functionality / abstraction.
// ---------------------------------------------------------------------------
@@ -2140,7 +1947,7 @@
}
for (size_t n = 0; n < protectedHeaders->size(); n++) {
- auto [keyItem, valueItem] = (*protectedHeaders)[n];
+ auto& [keyItem, valueItem] = (*protectedHeaders)[n];
const cppbor::Int* number = keyItem->asInt();
if (number == nullptr) {
LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2183,7 +1990,7 @@
}
for (size_t n = 0; n < unprotectedHeaders->size(); n++) {
- auto [keyItem, valueItem] = (*unprotectedHeaders)[n];
+ auto& [keyItem, valueItem] = (*unprotectedHeaders)[n];
const cppbor::Int* number = keyItem->asInt();
if (number == nullptr) {
LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2335,9 +2142,9 @@
.add("DeviceAuthentication")
.add(std::move(sessionTranscriptItem))
.add(docType)
- .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+ .add(cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
vector<uint8_t> deviceAuthenticationBytes =
- cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+ cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
optional<vector<uint8_t>> calculatedMac =
support::coseMac0(eMacKey, {}, // payload
deviceAuthenticationBytes); // detached content
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index 509133c..4c9b87a 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -55,99 +55,6 @@
EXPECT_FALSE(support::decodeHex("012"));
}
-TEST(IdentityCredentialSupport, CborPrettyPrint) {
- EXPECT_EQ("'Some text'", support::cborPrettyPrint(cppbor::Tstr("Some text").encode()));
-
- EXPECT_EQ("''", support::cborPrettyPrint(cppbor::Tstr("").encode()));
-
- EXPECT_EQ("{0x01, 0x00, 0x02, 0xf0, 0xff, 0x40}",
- support::cborPrettyPrint(
- cppbor::Bstr(vector<uint8_t>({1, 0, 2, 240, 255, 64})).encode()));
-
- EXPECT_EQ("{}", support::cborPrettyPrint(cppbor::Bstr(vector<uint8_t>()).encode()));
-
- EXPECT_EQ("true", support::cborPrettyPrint(cppbor::Bool(true).encode()));
-
- EXPECT_EQ("false", support::cborPrettyPrint(cppbor::Bool(false).encode()));
-
- EXPECT_EQ("42", support::cborPrettyPrint(cppbor::Uint(42).encode()));
-
- EXPECT_EQ("9223372036854775807", // 0x7fff ffff ffff ffff
- support::cborPrettyPrint(cppbor::Uint(std::numeric_limits<int64_t>::max()).encode()));
-
- EXPECT_EQ("-42", support::cborPrettyPrint(cppbor::Nint(-42).encode()));
-
- EXPECT_EQ("-9223372036854775808", // -0x8000 0000 0000 0000
- support::cborPrettyPrint(cppbor::Nint(std::numeric_limits<int64_t>::min()).encode()));
-}
-
-TEST(IdentityCredentialSupport, CborPrettyPrintCompound) {
- cppbor::Array array = cppbor::Array("foo", "bar", "baz");
- EXPECT_EQ("['foo', 'bar', 'baz', ]", support::cborPrettyPrint(array.encode()));
-
- cppbor::Map map = cppbor::Map().add("foo", 42).add("bar", 43).add("baz", 44);
- EXPECT_EQ(
- "{\n"
- " 'foo' : 42,\n"
- " 'bar' : 43,\n"
- " 'baz' : 44,\n"
- "}",
- support::cborPrettyPrint(map.encode()));
-
- cppbor::Array array2 = cppbor::Array(cppbor::Tstr("Some text"), cppbor::Nint(-42));
- EXPECT_EQ("['Some text', -42, ]", support::cborPrettyPrint(array2.encode()));
-
- cppbor::Map map2 = cppbor::Map().add(42, "foo").add(43, "bar").add(44, "baz");
- EXPECT_EQ(
- "{\n"
- " 42 : 'foo',\n"
- " 43 : 'bar',\n"
- " 44 : 'baz',\n"
- "}",
- support::cborPrettyPrint(map2.encode()));
-
- cppbor::Array deeplyNestedArrays =
- cppbor::Array(cppbor::Array(cppbor::Array("a", "b", "c")),
- cppbor::Array(cppbor::Array("d", "e", cppbor::Array("f", "g"))));
- EXPECT_EQ(
- "[\n"
- " ['a', 'b', 'c', ],\n"
- " [\n 'd',\n"
- " 'e',\n"
- " ['f', 'g', ],\n"
- " ],\n"
- "]",
- support::cborPrettyPrint(deeplyNestedArrays.encode()));
-
- EXPECT_EQ(
- "[\n"
- " {0x0a, 0x0b},\n"
- " 'foo',\n"
- " 42,\n"
- " ['foo', 'bar', 'baz', ],\n"
- " {\n"
- " 'foo' : 42,\n"
- " 'bar' : 43,\n"
- " 'baz' : 44,\n"
- " },\n"
- " {\n"
- " 'deep1' : ['Some text', -42, ],\n"
- " 'deep2' : {\n"
- " 42 : 'foo',\n"
- " 43 : 'bar',\n"
- " 44 : 'baz',\n"
- " },\n"
- " },\n"
- "]",
- support::cborPrettyPrint(cppbor::Array(cppbor::Bstr(vector<uint8_t>{10, 11}),
- cppbor::Tstr("foo"), cppbor::Uint(42),
- std::move(array), std::move(map),
- (cppbor::Map()
- .add("deep1", std::move(array2))
- .add("deep2", std::move(map2))))
- .encode()));
-}
-
TEST(IdentityCredentialSupport, Signatures) {
vector<uint8_t> data = {1, 2, 3};
@@ -219,7 +126,7 @@
ASSERT_EQ(data, payload.value());
// Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
- string out = support::cborPrettyPrint(coseSign1.value());
+ string out = cppbor::prettyPrint(coseSign1.value());
out = replaceLine(out, -2, " [] // Signature Removed");
EXPECT_EQ(
"[\n"
@@ -250,7 +157,7 @@
ASSERT_EQ(0, payload.value().size());
// Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
- string out = support::cborPrettyPrint(coseSign1.value());
+ string out = cppbor::prettyPrint(coseSign1.value());
out = replaceLine(out, -2, " [] // Signature Removed");
EXPECT_EQ(
"[\n"
@@ -411,7 +318,7 @@
"0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
"0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
"]",
- support::cborPrettyPrint(mac.value()));
+ cppbor::prettyPrint(mac.value()));
}
TEST(IdentityCredentialSupport, CoseMac0DetachedContent) {
@@ -433,7 +340,7 @@
"0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
"0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
"]",
- support::cborPrettyPrint(mac.value()));
+ cppbor::prettyPrint(mac.value()));
}
// Generates a private key in DER format for a small value of 'd'.
@@ -460,8 +367,8 @@
const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
// TODO: Need cast until libcppbor's Map::get() is marked as const
- auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
- if (!found) {
+ const auto& item = map->get(keyValue);
+ if (!item) {
return nullptr;
}
return item.get();
@@ -483,12 +390,13 @@
return item->asMap();
}
-const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+const cppbor::SemanticTag* findSemanticValueForTstr(const cppbor::Map* map,
+ const string& keyValue) {
const cppbor::Item* item = findValueForTstr(map, keyValue);
if (item == nullptr) {
return nullptr;
}
- return item->asSemantic();
+ return item->asSemanticTag();
}
const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
@@ -576,11 +484,11 @@
auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
ASSERT_NE(sessionEstablishment, nullptr);
- const cppbor::Semantic* eReaderKeyBytes =
+ const cppbor::SemanticTag* eReaderKeyBytes =
findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
ASSERT_NE(eReaderKeyBytes, nullptr);
- ASSERT_EQ(eReaderKeyBytes->value(), 24);
- const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+ ASSERT_EQ(eReaderKeyBytes->semanticTag(), 24);
+ const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->asBstr();
ASSERT_NE(eReaderKeyBstr, nullptr);
vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
// TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
@@ -605,12 +513,12 @@
// SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
//
cppbor::Array sessionTranscript;
- sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
- sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+ sessionTranscript.add(cppbor::SemanticTag(24, deviceEngagementEncoded));
+ sessionTranscript.add(cppbor::SemanticTag(24, eReaderKeyEncoded));
sessionTranscript.add(cppbor::Null());
vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
vector<uint8_t> sessionTranscriptBytes =
- cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+ cppbor::SemanticTag(24, sessionTranscriptEncoded).encode();
// The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
//
@@ -696,11 +604,11 @@
// Dig out the encoded form of DeviceNameSpaces
//
- const cppbor::Semantic* deviceNameSpacesBytes =
+ const cppbor::SemanticTag* deviceNameSpacesBytes =
findSemanticValueForTstr(deviceSigned, "nameSpaces");
ASSERT_NE(deviceNameSpacesBytes, nullptr);
- ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
- const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+ ASSERT_EQ(deviceNameSpacesBytes->semanticTag(), 24);
+ const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->asBstr();
ASSERT_NE(deviceNameSpacesBstr, nullptr);
vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
index db1df2b..4f21cba 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -21,7 +21,7 @@
long challenge;
long userId;
long authenticatorId;
- android.hardware.keymaster.HardwareAuthenticatorType authenticatorType;
+ android.hardware.keymaster.HardwareAuthenticatorType authenticatorType = android.hardware.keymaster.HardwareAuthenticatorType.NONE;
android.hardware.keymaster.Timestamp timestamp;
byte[] mac;
}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
index 0633765..b116dac 100644
--- a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
@@ -20,6 +20,6 @@
parcelable VerificationToken {
long challenge;
android.hardware.keymaster.Timestamp timestamp;
- android.hardware.keymaster.SecurityLevel securityLevel;
+ android.hardware.keymaster.SecurityLevel securityLevel = android.hardware.keymaster.SecurityLevel.SOFTWARE;
byte[] mac;
}
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
index 58602aa..99b036a 100644
--- a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -55,7 +55,7 @@
* authenticatorType describes the type of authentication that took place, e.g. password or
* fingerprint.
*/
- HardwareAuthenticatorType authenticatorType;
+ HardwareAuthenticatorType authenticatorType = HardwareAuthenticatorType.NONE;
/**
* timestamp indicates when the user authentication took place, in milliseconds since some
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
index f053254..5efd937 100644
--- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -43,7 +43,7 @@
/**
* SecurityLevel of the secure environment that generated the token.
*/
- SecurityLevel securityLevel;
+ SecurityLevel securityLevel = SecurityLevel.SOFTWARE;
/**
* 32-byte HMAC-SHA256 of the above values, computed as:
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
index 4681b9e..db3b2ad 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
@@ -52,7 +52,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp
index bb31a26..93bd81a 100644
--- a/neuralnetworks/1.0/utils/src/Device.cpp
+++ b/neuralnetworks/1.0/utils/src/Device.cpp
@@ -106,10 +106,6 @@
return nn::DeviceType::OTHER;
}
-bool Device::isUpdatable() const {
- return false;
-}
-
const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
index 3aec8ee..5e224b5 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
@@ -52,7 +52,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp
index d2ef57f..3197ef4 100644
--- a/neuralnetworks/1.1/utils/src/Device.cpp
+++ b/neuralnetworks/1.1/utils/src/Device.cpp
@@ -106,10 +106,6 @@
return nn::DeviceType::UNKNOWN;
}
-bool Device::isUpdatable() const {
- return false;
-}
-
const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 03aed86..f5b6ead 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -3618,7 +3618,7 @@
* front of dimension i.
* padding[i, 1] specifies the number of elements to be padded after
* the end of dimension i.
- * * 2: An scalar specifying the value to use for padding input0.
+ * * 2: A scalar specifying the value to use for padding input0.
* For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
* pad value must be of {@link OperandType::FLOAT16}.
* For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
index 489f857..b4bef5e 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -71,7 +71,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
index 1954dfa..9fe0de2 100644
--- a/neuralnetworks/1.2/utils/src/Device.cpp
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -199,10 +199,6 @@
return kDeviceType;
}
-bool Device::isUpdatable() const {
- return false;
-}
-
const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index a5dbd5e..a26b858 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -3834,7 +3834,7 @@
* front of dimension i.
* padding[i, 1] specifies the number of elements to be padded after
* the end of dimension i.
- * * 2: An scalar specifying the value to use for padding input0.
+ * * 2: A scalar specifying the value to use for padding input0.
* For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
* pad value must be of {@link OperandType::FLOAT16}.
* For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
index f36b6c0..84f606a 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
@@ -54,7 +54,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
index 87c9f32..d710b85 100644
--- a/neuralnetworks/1.3/utils/src/Device.cpp
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -150,10 +150,6 @@
return kDeviceType;
}
-bool Device::isUpdatable() const {
- return false;
-}
-
const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index b1860e2..ebf4654 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -16,6 +16,7 @@
stability: "vintf",
imports: [
"android.hardware.common",
+ "android.hardware.graphics.common",
],
backend: {
java: {
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
index 634f39e..eb3d0b0 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
@@ -34,6 +34,6 @@
package android.hardware.neuralnetworks;
@VintfStability
interface IBurst {
- android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
+ android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
void releaseMemoryResource(in long memoryIdentifierToken);
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
index b328b29..c9c67f2 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
@@ -41,8 +41,8 @@
boolean[] getSupportedOperations(in android.hardware.neuralnetworks.Model model);
android.hardware.neuralnetworks.DeviceType getType();
String getVersionString();
- void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
- void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+ void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+ void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
const int MAX_NUMBER_OF_CACHE_FILES = 32;
const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
index 52882cd..fccb5dc 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -34,8 +34,8 @@
package android.hardware.neuralnetworks;
@VintfStability
interface IPreparedModel {
- android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
- android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadline, in long loopTimeoutDuration, in long duration);
+ android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
+ android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs, in long durationNs);
android.hardware.neuralnetworks.IBurst configureExecutionBurst();
const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
index 8207b25..37fa102 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
@@ -33,8 +33,8 @@
package android.hardware.neuralnetworks;
@VintfStability
-parcelable Memory {
- android.hardware.common.NativeHandle handle;
- long size;
- String name;
+union Memory {
+ android.hardware.common.Ashmem ashmem;
+ android.hardware.common.MappableFile mappableFile;
+ android.hardware.graphics.common.HardwareBuffer hardwareBuffer;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
index 5a9f4ff..1d9bdd8 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operand.aidl
@@ -34,11 +34,11 @@
package android.hardware.neuralnetworks;
@VintfStability
parcelable Operand {
- android.hardware.neuralnetworks.OperandType type;
+ android.hardware.neuralnetworks.OperandType type = android.hardware.neuralnetworks.OperandType.FLOAT32;
int[] dimensions;
float scale;
int zeroPoint;
- android.hardware.neuralnetworks.OperandLifeTime lifetime;
+ android.hardware.neuralnetworks.OperandLifeTime lifetime = android.hardware.neuralnetworks.OperandLifeTime.TEMPORARY_VARIABLE;
android.hardware.neuralnetworks.DataLocation location;
@nullable android.hardware.neuralnetworks.OperandExtraParams extraParams;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
index de93d8b..ebb361b 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperandPerformance.aidl
@@ -34,6 +34,6 @@
package android.hardware.neuralnetworks;
@VintfStability
parcelable OperandPerformance {
- android.hardware.neuralnetworks.OperandType type;
+ android.hardware.neuralnetworks.OperandType type = android.hardware.neuralnetworks.OperandType.FLOAT32;
android.hardware.neuralnetworks.PerformanceInfo info;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
index 33fcd60..a4a3fbe 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Operation.aidl
@@ -34,7 +34,7 @@
package android.hardware.neuralnetworks;
@VintfStability
parcelable Operation {
- android.hardware.neuralnetworks.OperationType type;
+ android.hardware.neuralnetworks.OperationType type = android.hardware.neuralnetworks.OperationType.ADD;
int[] inputs;
int[] outputs;
}
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
index 9690e01..bcc83cf 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
@@ -34,6 +34,6 @@
package android.hardware.neuralnetworks;
@VintfStability
parcelable Timing {
- long timeOnDevice;
- long timeInDriver;
+ long timeOnDeviceNs;
+ long timeInDriverNs;
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
index 861b6f0..df015ca 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -22,8 +22,20 @@
@VintfStability
@Backing(type="int")
enum FusedActivationFunc {
+ /**
+ * No activation.
+ */
NONE,
+ /**
+ * ReLU(x) = max(0, x)
+ */
RELU,
+ /**
+ * ReLU1(x) = min(1, max(-1, x))
+ */
RELU1,
+ /**
+ * ReLU6(x) = min(6, max(0, x))
+ */
RELU6,
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
index 85d2a03..decdc48 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
@@ -77,18 +77,18 @@
* @param measure Specifies whether or not to measure duration of the execution. The duration
* runs from the time the driver sees the call to the executeSynchronously
* function to the time the driver returns from the function.
- * @param deadline The time by which the execution is expected to complete. The time is measured
- * in nanoseconds since epoch of the steady clock (as from
- * std::chrono::steady_clock). If the execution cannot be finished by the
- * deadline, the execution may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
- * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
- * executing a {@link OperationType::WHILE} operation. If a loop
- * condition model does not output false within this duration, the
- * execution must be aborted. If -1 is provided, the maximum amount
- * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
- * negative values are invalid. When provided, the duration must not
- * exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since epoch of the steady clock (as from
+ * std::chrono::steady_clock). If the execution cannot be finished by the
+ * deadline, the execution may be aborted. Passing -1 means the deadline is
+ * omitted. Other negative values are invalid.
+ * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+ * executing a {@link OperationType::WHILE} operation. If a loop
+ * condition model does not output false within this duration, the
+ * execution must be aborted. If -1 is provided, the maximum amount
+ * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+ * negative values are invalid. When provided, the duration must
+ * not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
* @return ExecutionResult parcelable, containing the status of the execution, output shapes and
* timing information.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -100,7 +100,7 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
ExecutionResult executeSynchronously(in Request request, in long[] memoryIdentifierTokens,
- in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
+ in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
/**
* releaseMemoryResource is used by the client to signal to the service that a memory buffer
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
index c5b4ab1..72e2623 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
@@ -306,11 +306,11 @@
* @param preference Indicates the intended execution behavior of a prepared model.
* @param priority The priority of the prepared model relative to other prepared models owned by
* the client.
- * @param deadline The time by which the model is expected to be prepared. The time is measured
- * in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts)
- * or ::android::base::boot_clock). If the model cannot be prepared by the
- * deadline, the preparation may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
+ * @param deadlineNs The time by which the model is expected to be prepared. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the model cannot be prepared by
+ * the deadline, the preparation may be aborted. Passing -1 means the deadline
+ * is omitted. Other negative values are invalid.
* @param modelCache A vector of file descriptors for the security-sensitive cache. The length
* of the vector must either be 0 indicating that caching information is not
* provided, or match the numModelCache returned from
@@ -344,7 +344,7 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
void prepareModel(in Model model, in ExecutionPreference preference, in Priority priority,
- in long deadline, in ParcelFileDescriptor[] modelCache,
+ in long deadlineNs, in ParcelFileDescriptor[] modelCache,
in ParcelFileDescriptor[] dataCache, in byte[] token,
in IPreparedModelCallback callback);
@@ -395,11 +395,11 @@
* with a set of inputs to the model. Note that the same prepared model object may be used with
* different shapes of inputs on different (possibly concurrent) executions.
*
- * @param deadline The time by which the model is expected to be prepared. The time is measured
- * in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
- * ::android::base::boot_clock). If the model cannot be prepared by the
- * deadline, the preparation may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
+ * @param deadlineNs The time by which the model is expected to be prepared. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the model cannot be prepared by
+ * the deadline, the preparation may be aborted. Passing -1 means the deadline
+ * is omitted. Other negative values are invalid.
* @param modelCache A vector of file descriptors for the security-sensitive cache. The length
* of the vector must match the numModelCache returned from
* getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
@@ -426,7 +426,7 @@
* the deadline
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
- void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache,
+ void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache,
in ParcelFileDescriptor[] dataCache, in byte[] token,
in IPreparedModelCallback callback);
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
index bfab906..956b626 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -72,18 +72,18 @@
* @param measure Specifies whether or not to measure duration of the execution. The duration
* runs from the time the driver sees the call to the executeSynchronously
* function to the time the driver returns from the function.
- * @param deadline The time by which the execution is expected to complete. The time is measured
- * in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
- * ::android::base::boot_clock). If the execution cannot be finished by the
- * deadline, the execution may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
- * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
- * executing a {@link OperationType::WHILE} operation. If a loop
- * condition model does not output false within this duration, the
- * execution must be aborted. If -1 is provided, the maximum amount
- * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
- * negative values are invalid. When provided, the duration must not
- * exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
+ * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+ * executing a {@link OperationType::WHILE} operation. If a loop
+ * condition model does not output false within this duration, the
+ * execution must be aborted. If -1 is provided, the maximum amount
+ * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+ * negative values are invalid. When provided, the duration must
+ * not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
* @return ExecutionResult parcelable, containing the status of the execution, output shapes and
* timing information.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -95,7 +95,7 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
ExecutionResult executeSynchronously(in Request request, in boolean measureTiming,
- in long deadline, in long loopTimeoutDuration);
+ in long deadlineNs, in long loopTimeoutDurationNs);
/**
* Launch a fenced asynchronous execution on a prepared model.
@@ -137,22 +137,23 @@
* @param waitFor A vector of sync fence file descriptors. Execution must not start until all
* sync fences have been signaled.
* @param measure Specifies whether or not to measure duration of the execution.
- * @param deadline The time by which the execution is expected to complete. The time is measured
- * in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME, &ts) or
- * ::android::base::boot_clock). If the execution cannot be finished by the
- * deadline, the execution may be aborted. Passing -1 means the deadline is
- * omitted. Other negative values are invalid.
- * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
- * executing a {@link OperationType::WHILE} operation. If a loop
- * condition model does not output false within this duration, the
- * execution must be aborted. If -1 is provided, the maximum amount
- * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
- * negative values are invalid. When provided, the duration must not
- * exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
- * @param duration The length of time in nanoseconds within which the execution is expected to
- * complete after all sync fences in waitFor are signaled. If the execution
- * cannot be finished within the duration, the execution may be aborted. Passing
- * -1 means the duration is omitted. Other negative values are invalid.
+ * @param deadlineNs The time by which the execution is expected to complete. The time is
+ * measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+ * &ts) or ::android::base::boot_clock). If the execution cannot be finished
+ * by the deadline, the execution may be aborted. Passing -1 means the
+ * deadline is omitted. Other negative values are invalid.
+ * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+ * executing a {@link OperationType::WHILE} operation. If a loop
+ * condition model does not output false within this duration, the
+ * execution must be aborted. If -1 is provided, the maximum amount
+ * of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+ * negative values are invalid. When provided, the duration must
+ * not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+ * @param durationNs The length of time in nanoseconds within which the execution is expected to
+ * complete after all sync fences in waitFor are signaled. If the execution
+ * cannot be finished within the duration, the execution may be aborted.
+ * Passing -1 means the duration is omitted. Other negative values are
+ * invalid.
* @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
* sync fence.
* @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -165,8 +166,8 @@
* - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
*/
FencedExecutionResult executeFenced(in Request request, in ParcelFileDescriptor[] waitFor,
- in boolean measureTiming, in long deadline, in long loopTimeoutDuration,
- in long duration);
+ in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs,
+ in long durationNs);
/**
* Configure a Burst object used to execute multiple inferences on a prepared model in rapid
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
index 870f0ae..244ac87 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
@@ -15,16 +15,26 @@
*/
package android.hardware.neuralnetworks;
-import android.hardware.common.NativeHandle;
-import android.os.ParcelFileDescriptor;
+
+import android.hardware.common.Ashmem;
+import android.hardware.common.MappableFile;
+import android.hardware.graphics.common.HardwareBuffer;
/**
- * A type that is used to pass pieces of shared memory between processes.
- * The type structure mimics hidl_memory type from HIDL.
+ * The different types of memory that can be shared across processes.
*/
@VintfStability
-parcelable Memory {
- NativeHandle handle;
- long size;
- String name;
+union Memory {
+ /**
+ * Ashmem hidl_memory type from HIDL.
+ */
+ Ashmem ashmem;
+ /**
+ * File that can be mapped.
+ */
+ MappableFile mappableFile;
+ /**
+ * AIDL representation of AHardwareBuffer.
+ */
+ HardwareBuffer hardwareBuffer;
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
index 4d2260f..998e06d 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operand.aidl
@@ -33,7 +33,7 @@
* {@link IDevice::OPERAND_TYPE_BASE_MAX} is possible and should be interpreted as an extension
* type according to {@link Model::extensionNameToPrefix}.
*/
- OperandType type;
+ OperandType type = OperandType.FLOAT32;
/**
* Dimensions of the operand.
*
@@ -86,7 +86,7 @@
/**
* How the operand is used.
*/
- OperandLifeTime lifetime;
+ OperandLifeTime lifetime = OperandLifeTime.TEMPORARY_VARIABLE;
/**
* Where to find the data for this operand.
* If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT, or NO_VALUE:
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
index 7fd86f9..7f53967 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperandPerformance.aidl
@@ -25,6 +25,6 @@
*/
@VintfStability
parcelable OperandPerformance {
- OperandType type;
+ OperandType type = OperandType.FLOAT32;
PerformanceInfo info;
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
index 0c6032f..366d9a4 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Operation.aidl
@@ -30,7 +30,7 @@
* {@link IDevice::OPERATION_TYPE_BASE_MAX} is possible and should be interpreted as an
* extension type according to {@link Model::extensionNameToPrefix}.
*/
- OperationType type;
+ OperationType type = OperationType.ADD;
/**
* Describes the table that contains the indexes of the inputs of the operation. The offset is
* the index in the operandIndexes table.
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
index 3f49154..e7fb90d 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
@@ -3693,7 +3693,7 @@
* front of dimension i.
* padding[i, 1] specifies the number of elements to be padded after
* the end of dimension i.
- * * 2: An scalar specifying the value to use for padding input0.
+ * * 2: A scalar specifying the value to use for padding input0.
* For input tensor of {@link OperandType::TENSOR_FLOAT16}, the
* pad value must be of {@link OperandType::FLOAT16}.
* For input tensor of {@link OperandType::TENSOR_FLOAT32}, the
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
index 8130e08..5225096 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
@@ -28,9 +28,9 @@
/**
* Execution time on device (not driver, which runs on host processor).
*/
- long timeOnDevice;
+ long timeOnDeviceNs;
/**
* Execution time in driver (including time on device).
*/
- long timeInDriver;
+ long timeInDriverNs;
}
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index ad961cf..0ccc711 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -31,6 +31,8 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.graphics.common-V2-ndk_platform",
+ "libaidlcommonsupport",
"libarect",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
@@ -51,7 +53,9 @@
],
static_libs: [
"android.hardware.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk_platform",
"android.hardware.neuralnetworks-V1-ndk_platform",
+ "libaidlcommonsupport",
"libgmock",
"libneuralnetworks_common",
"neuralnetworks_types",
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
index eb194e3..1457646 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
@@ -54,7 +54,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
new file mode 100644
index 0000000..e66507a
--- /dev/null
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+
+class InvalidDevice : public BnDevice {
+ public:
+ static std::shared_ptr<InvalidDevice> create();
+
+ InvalidDevice(Capabilities capabilities, const NumberOfCacheFiles& numberOfCacheFiles,
+ std::vector<Extension> extensions, DeviceType deviceType,
+ std::string versionString);
+
+ ndk::ScopedAStatus allocate(const BufferDesc& desc,
+ const std::vector<IPreparedModelParcel>& preparedModels,
+ const std::vector<BufferRole>& inputRoles,
+ const std::vector<BufferRole>& outputRoles,
+ DeviceBuffer* deviceBuffer) override;
+ ndk::ScopedAStatus getCapabilities(Capabilities* capabilities) override;
+ ndk::ScopedAStatus getNumberOfCacheFilesNeeded(NumberOfCacheFiles* numberOfCacheFiles) override;
+ ndk::ScopedAStatus getSupportedExtensions(std::vector<Extension>* extensions) override;
+ ndk::ScopedAStatus getSupportedOperations(const Model& model,
+ std::vector<bool>* supportedOperations) override;
+ ndk::ScopedAStatus getType(DeviceType* deviceType) override;
+ ndk::ScopedAStatus getVersionString(std::string* versionString) override;
+ ndk::ScopedAStatus prepareModel(
+ const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+ const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+ const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
+ ndk::ScopedAStatus prepareModelFromCache(
+ int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+ const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
+
+ private:
+ const Capabilities kCapabilities;
+ const NumberOfCacheFiles kNumberOfCacheFiles;
+ const std::vector<Extension> kExtensions;
+ const DeviceType kDeviceType;
+ const std::string kVersionString;
+};
+
+} // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index d5f7f81..4b263ee 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -16,8 +16,13 @@
#include "Conversions.h"
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
#include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
+#include <android-base/mapped_file.h>
#include <android-base/unique_fd.h>
#include <android/binder_auto_utils.h>
#include <android/hardware_buffer.h>
@@ -125,28 +130,17 @@
using UniqueNativeHandle = std::unique_ptr<native_handle_t, NativeHandleDeleter>;
-static GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
- std::vector<base::unique_fd> fds;
- fds.reserve(handle.fds.size());
- for (const auto& fd : handle.fds) {
- auto duplicatedFd = NN_TRY(dupFd(fd.get()));
- fds.emplace_back(duplicatedFd.release());
+GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
+ auto nativeHandle = UniqueNativeHandle(dupFromAidl(handle));
+ if (nativeHandle.get() == nullptr) {
+ return NN_ERROR() << "android::dupFromAidl failed to convert the common::NativeHandle to a "
+ "native_handle_t";
}
-
- 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() << "Failed to create native_handle";
+ if (!std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
+ [](int fd) { return fd >= 0; })) {
+ return NN_ERROR() << "android::dupFromAidl returned an invalid native_handle_t";
}
- 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]);
-
- return UniqueNativeHandle(nativeHandle);
+ return nativeHandle;
}
} // anonymous namespace
@@ -353,75 +347,74 @@
return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
}
-static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
- return (value + multiple - 1) / multiple * multiple;
-}
-
GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& memory) {
- VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative";
- if (memory.size > std::numeric_limits<size_t>::max()) {
- return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
- }
+ using Tag = aidl_hal::Memory::Tag;
+ switch (memory.getTag()) {
+ case Tag::ashmem: {
+ const auto& ashmem = memory.get<Tag::ashmem>();
+ VERIFY_NON_NEGATIVE(ashmem.size) << "Memory size must not be negative";
+ if (ashmem.size > std::numeric_limits<size_t>::max()) {
+ return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+ }
- if (memory.name != "hardware_buffer_blob") {
- return std::make_shared<const Memory>(Memory{
- .handle = NN_TRY(unvalidatedConvertHelper(memory.handle)),
- .size = static_cast<size_t>(memory.size),
- .name = memory.name,
- });
- }
+ auto handle = Memory::Ashmem{
+ .fd = NN_TRY(dupFd(ashmem.fd.get())),
+ .size = static_cast<size_t>(ashmem.size),
+ };
+ return std::make_shared<const Memory>(Memory{.handle = std::move(handle)});
+ }
+ case Tag::mappableFile: {
+ const auto& mappableFile = memory.get<Tag::mappableFile>();
+ VERIFY_NON_NEGATIVE(mappableFile.length) << "Memory size must not be negative";
+ VERIFY_NON_NEGATIVE(mappableFile.offset) << "Memory offset must not be negative";
+ if (mappableFile.length > std::numeric_limits<size_t>::max()) {
+ return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+ }
+ if (mappableFile.offset > std::numeric_limits<size_t>::max()) {
+ return NN_ERROR() << "Memory: offset must be <= std::numeric_limits<size_t>::max()";
+ }
- const auto size = static_cast<uint32_t>(memory.size);
- const auto format = AHARDWAREBUFFER_FORMAT_BLOB;
- const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
- const uint32_t width = size;
- const uint32_t height = 1; // height is always 1 for BLOB mode AHardwareBuffer.
- const uint32_t layers = 1; // layers is always 1 for BLOB mode AHardwareBuffer.
+ const size_t size = static_cast<size_t>(mappableFile.length);
+ const int prot = mappableFile.prot;
+ const int fd = mappableFile.fd.get();
+ const size_t offset = static_cast<size_t>(mappableFile.offset);
- const UniqueNativeHandle handle = NN_TRY(nativeHandleFromAidlHandle(memory.handle));
- const native_handle_t* nativeHandle = handle.get();
+ return createSharedMemoryFromFd(size, prot, fd, offset);
+ }
+ case Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Tag::hardwareBuffer>();
- // AHardwareBuffer_createFromHandle() might fail because an allocator
- // expects a specific stride value. In that case, we try to guess it by
- // aligning the width to small powers of 2.
- // TODO(b/174120849): Avoid stride assumptions.
- AHardwareBuffer* hardwareBuffer = nullptr;
- status_t status = UNKNOWN_ERROR;
- for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) {
- const uint32_t stride = roundUpToMultiple(width, alignment);
- AHardwareBuffer_Desc desc{
- .width = width,
- .height = height,
- .layers = layers,
- .format = format,
- .usage = usage,
- .stride = stride,
- };
- status = AHardwareBuffer_createFromHandle(&desc, nativeHandle,
- AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
- &hardwareBuffer);
- if (status == NO_ERROR) {
- break;
+ const UniqueNativeHandle handle =
+ NN_TRY(nativeHandleFromAidlHandle(hardwareBuffer.handle));
+ const native_handle_t* nativeHandle = handle.get();
+
+ const AHardwareBuffer_Desc desc{
+ .width = static_cast<uint32_t>(hardwareBuffer.description.width),
+ .height = static_cast<uint32_t>(hardwareBuffer.description.height),
+ .layers = static_cast<uint32_t>(hardwareBuffer.description.layers),
+ .format = static_cast<uint32_t>(hardwareBuffer.description.format),
+ .usage = static_cast<uint64_t>(hardwareBuffer.description.usage),
+ .stride = static_cast<uint32_t>(hardwareBuffer.description.stride),
+ };
+ AHardwareBuffer* ahwb = nullptr;
+ const status_t status = AHardwareBuffer_createFromHandle(
+ &desc, nativeHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &ahwb);
+ if (status != NO_ERROR) {
+ return NN_ERROR() << "createFromHandle failed";
+ }
+
+ return createSharedMemoryFromAHWB(ahwb, /*takeOwnership=*/true);
}
}
- if (status != NO_ERROR) {
- return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
- << "Can't create AHardwareBuffer from handle. Error: " << status;
- }
-
- return std::make_shared<const Memory>(Memory{
- .handle = HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
- .size = static_cast<size_t>(memory.size),
- .name = memory.name,
- });
+ return NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag();
}
GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing) {
- if (timing.timeInDriver < -1) {
- return NN_ERROR() << "Timing: timeInDriver must not be less than -1";
+ if (timing.timeInDriverNs < -1) {
+ return NN_ERROR() << "Timing: timeInDriverNs must not be less than -1";
}
- if (timing.timeOnDevice < -1) {
- return NN_ERROR() << "Timing: timeOnDevice must not be less than -1";
+ if (timing.timeOnDeviceNs < -1) {
+ return NN_ERROR() << "Timing: timeOnDeviceNs must not be less than -1";
}
constexpr auto convertTiming = [](int64_t halTiming) -> OptionalDuration {
if (halTiming == kNoTiming) {
@@ -429,8 +422,8 @@
}
return nn::Duration(static_cast<uint64_t>(halTiming));
};
- return Timing{.timeOnDevice = convertTiming(timing.timeOnDevice),
- .timeInDriver = convertTiming(timing.timeInDriver)};
+ return Timing{.timeOnDevice = convertTiming(timing.timeOnDeviceNs),
+ .timeInDriver = convertTiming(timing.timeInDriverNs)};
}
GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues) {
@@ -645,20 +638,95 @@
template <class... Ts>
overloaded(Ts...)->overloaded<Ts...>;
-static nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
- const native_handle_t& handle) {
- common::NativeHandle aidlNativeHandle;
+nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
+ const native_handle_t& nativeHandle) {
+ auto handle = ::android::dupToAidl(&nativeHandle);
+ if (!std::all_of(handle.fds.begin(), handle.fds.end(),
+ [](const ndk::ScopedFileDescriptor& fd) { return fd.get() >= 0; })) {
+ return NN_ERROR() << "android::dupToAidl returned an invalid common::NativeHandle";
+ }
+ return handle;
+}
- aidlNativeHandle.fds.reserve(handle.numFds);
- for (int i = 0; i < handle.numFds; ++i) {
- auto duplicatedFd = NN_TRY(nn::dupFd(handle.data[i]));
- aidlNativeHandle.fds.emplace_back(duplicatedFd.release());
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Ashmem& memory) {
+ if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+ if (memory.size > std::numeric_limits<int64_t>::max()) {
+ return (
+ NN_ERROR()
+ << "Memory::Ashmem: size must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
}
- aidlNativeHandle.ints = std::vector<int>(&handle.data[handle.numFds],
- &handle.data[handle.numFds + handle.numInts]);
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+ auto handle = common::Ashmem{
+ .fd = ndk::ScopedFileDescriptor(fd.release()),
+ .size = static_cast<int64_t>(memory.size),
+ };
+ return Memory::make<Memory::Tag::ashmem>(std::move(handle));
+}
- return aidlNativeHandle;
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Fd& memory) {
+ if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+ if (memory.size > std::numeric_limits<int64_t>::max()) {
+ return (NN_ERROR() << "Memory::Fd: size must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+ if (memory.offset > std::numeric_limits<int64_t>::max()) {
+ return (
+ NN_ERROR()
+ << "Memory::Fd: offset must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+ }
+
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+ auto handle = common::MappableFile{
+ .length = static_cast<int64_t>(memory.size),
+ .prot = memory.prot,
+ .fd = ndk::ScopedFileDescriptor(fd.release()),
+ .offset = static_cast<int64_t>(memory.offset),
+ };
+ return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& memory) {
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(memory.handle.get());
+ if (nativeHandle == nullptr) {
+ return (NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
+ "returned nullptr")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+
+ auto handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle));
+
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(memory.handle.get(), &desc);
+
+ const auto description = graphics::common::HardwareBufferDescription{
+ .width = static_cast<int32_t>(desc.width),
+ .height = static_cast<int32_t>(desc.height),
+ .layers = static_cast<int32_t>(desc.layers),
+ .format = static_cast<graphics::common::PixelFormat>(desc.format),
+ .usage = static_cast<graphics::common::BufferUsage>(desc.usage),
+ .stride = static_cast<int32_t>(desc.stride),
+ };
+
+ auto hardwareBuffer = graphics::common::HardwareBuffer{
+ .description = std::move(description),
+ .handle = std::move(handle),
+ };
+ return Memory::make<Memory::Tag::hardwareBuffer>(std::move(hardwareBuffer));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Unknown& /*memory*/) {
+ return (NN_ERROR() << "Unable to convert Unknown memory type")
+ .
+ operator nn::GeneralResult<Memory>();
}
} // namespace
@@ -693,41 +761,12 @@
}
nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
- CHECK(memory != nullptr);
- if (memory->size > std::numeric_limits<int64_t>::max()) {
- return NN_ERROR() << "Memory size doesn't fit into int64_t.";
+ if (memory == nullptr) {
+ return (NN_ERROR() << "Unable to convert nullptr memory")
+ .
+ operator nn::GeneralResult<Memory>();
}
- if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
- return Memory{
- .handle = NN_TRY(unvalidatedConvert(*handle)),
- .size = static_cast<int64_t>(memory->size),
- .name = memory->name,
- };
- }
-
- const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
- AHardwareBuffer_Desc bufferDesc;
- AHardwareBuffer_describe(ahwb, &bufferDesc);
-
- if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
- CHECK_EQ(memory->size, bufferDesc.width);
- CHECK_EQ(memory->name, "hardware_buffer_blob");
- } else {
- CHECK_EQ(memory->size, 0u);
- CHECK_EQ(memory->name, "hardware_buffer");
- }
-
- const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
- if (nativeHandle == nullptr) {
- return NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
- "returned nullptr";
- }
-
- return Memory{
- .handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle)),
- .size = static_cast<int64_t>(memory->size),
- .name = memory->name,
- };
+ return std::visit([](const auto& x) { return unvalidatedConvert(x); }, memory->handle);
}
nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
@@ -925,8 +964,8 @@
nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
return Timing{
- .timeOnDevice = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
- .timeInDriver = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
+ .timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
+ .timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
};
}
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index 02ca861..0fd453b 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -178,10 +178,6 @@
return kDeviceType;
}
-bool Device::isUpdatable() const {
- return false;
-}
-
const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
new file mode 100644
index 0000000..c9d9955
--- /dev/null
+++ b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "InvalidDevice"
+
+#include "InvalidDevice.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+namespace {
+
+ndk::ScopedAStatus toAStatus(ErrorStatus errorStatus, const std::string& errorMessage) {
+ if (errorStatus == ErrorStatus::NONE) {
+ return ndk::ScopedAStatus::ok();
+ }
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(errorStatus), errorMessage.c_str());
+}
+
+} // namespace
+
+std::shared_ptr<InvalidDevice> InvalidDevice::create() {
+ constexpr auto perf = PerformanceInfo{
+ .execTime = std::numeric_limits<float>::max(),
+ .powerUsage = std::numeric_limits<float>::max(),
+ };
+ auto capabilities = Capabilities{
+ .relaxedFloat32toFloat16PerformanceScalar = perf,
+ .relaxedFloat32toFloat16PerformanceTensor = perf,
+ .operandPerformance = {},
+ .ifPerformance = perf,
+ .whilePerformance = perf,
+ };
+ constexpr auto numberOfCacheFiles = NumberOfCacheFiles{
+ .numModelCache = 0,
+ .numDataCache = 0,
+ };
+ std::vector<Extension> extensions{};
+ constexpr auto deviceType = DeviceType::OTHER;
+ std::string versionString = "invalid";
+
+ return ndk::SharedRefBase::make<InvalidDevice>(std::move(capabilities), numberOfCacheFiles,
+ std::move(extensions), deviceType,
+ std::move(versionString));
+}
+
+InvalidDevice::InvalidDevice(Capabilities capabilities,
+ const NumberOfCacheFiles& numberOfCacheFiles,
+ std::vector<Extension> extensions, DeviceType deviceType,
+ std::string versionString)
+ : kCapabilities(std::move(capabilities)),
+ kNumberOfCacheFiles(numberOfCacheFiles),
+ kExtensions(std::move(extensions)),
+ kDeviceType(deviceType),
+ kVersionString(std::move(versionString)) {}
+
+ndk::ScopedAStatus InvalidDevice::allocate(
+ const BufferDesc& /*desc*/, const std::vector<IPreparedModelParcel>& /*preparedModels*/,
+ const std::vector<BufferRole>& /*inputRoles*/,
+ const std::vector<BufferRole>& /*outputRoles*/, DeviceBuffer* /*deviceBuffer*/) {
+ return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+ndk::ScopedAStatus InvalidDevice::getCapabilities(Capabilities* capabilities) {
+ *capabilities = kCapabilities;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getNumberOfCacheFilesNeeded(
+ NumberOfCacheFiles* numberOfCacheFiles) {
+ *numberOfCacheFiles = kNumberOfCacheFiles;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedExtensions(std::vector<Extension>* extensions) {
+ *extensions = kExtensions;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedOperations(const Model& model,
+ std::vector<bool>* supportedOperations) {
+ if (const auto result = utils::validate(model); !result.ok()) {
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ *supportedOperations = std::vector<bool>(model.main.operations.size(), false);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getType(DeviceType* deviceType) {
+ *deviceType = kDeviceType;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getVersionString(std::string* versionString) {
+ *versionString = kVersionString;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModel(
+ const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+ const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ if (callback.get() == nullptr) {
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "invalid callback passed to InvalidDevice::prepareModel");
+ }
+ if (const auto result = utils::validate(model); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (const auto result = utils::validate(preference); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (const auto result = utils::validate(priority); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (deadline < -1) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid deadline " + std::to_string(deadline));
+ }
+ if (modelCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numModelCache)) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid modelCache, size = " + std::to_string(modelCache.size()));
+ }
+ if (dataCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numDataCache)) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid modelCache, size = " + std::to_string(dataCache.size()));
+ }
+ if (token.size() != IDevice::BYTE_SIZE_OF_CACHE_TOKEN) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(
+ ErrorStatus::INVALID_ARGUMENT,
+ "Invalid cache token, size = " + std::to_string(IDevice::BYTE_SIZE_OF_CACHE_TOKEN));
+ }
+ callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModelFromCache(
+ int64_t /*deadline*/, const std::vector<ndk::ScopedFileDescriptor>& /*modelCache*/,
+ const std::vector<ndk::ScopedFileDescriptor>& /*dataCache*/,
+ const std::vector<uint8_t>& /*token*/,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+ return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+} // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/src/Service.cpp b/neuralnetworks/aidl/utils/src/Service.cpp
index 511de55..ac182a2 100644
--- a/neuralnetworks/aidl/utils/src/Service.cpp
+++ b/neuralnetworks/aidl/utils/src/Service.cpp
@@ -16,6 +16,7 @@
#include "Service.h"
+#include <AndroidVersionUtil.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -35,13 +36,23 @@
hal::utils::ResilientDevice::Factory makeDevice =
[instanceName,
name = std::move(fullName)](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
- const auto& getService =
- blocking ? AServiceManager_getService : AServiceManager_checkService;
+ std::add_pointer_t<AIBinder*(const char*)> getService;
+ if (blocking) {
+ if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
+ getService = AServiceManager_waitForService;
+ } else {
+ getService = AServiceManager_getService;
+ }
+ } else {
+ getService = AServiceManager_checkService;
+ }
+
auto service = IDevice::fromBinder(ndk::SpAIBinder(getService(name.c_str())));
if (service == nullptr) {
- return NN_ERROR() << (blocking ? "AServiceManager_getService"
- : "AServiceManager_checkService")
- << " returned nullptr";
+ return NN_ERROR()
+ << (blocking ? "AServiceManager_waitForService (or AServiceManager_getService)"
+ : "AServiceManager_checkService")
+ << " returned nullptr";
}
ABinderProcess_startThreadPool();
return Device::create(instanceName, std::move(service));
diff --git a/neuralnetworks/aidl/utils/src/Utils.cpp b/neuralnetworks/aidl/utils/src/Utils.cpp
index 95516c8..03407be 100644
--- a/neuralnetworks/aidl/utils/src/Utils.cpp
+++ b/neuralnetworks/aidl/utils/src/Utils.cpp
@@ -16,12 +16,20 @@
#include "Utils.h"
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <android/binder_auto_utils.h>
#include <android/binder_status.h>
#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
namespace aidl::android::hardware::neuralnetworks::utils {
namespace {
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd);
+using utils::clone;
+
template <typename Type>
nn::GeneralResult<std::vector<Type>> cloneVec(const std::vector<Type>& arguments) {
std::vector<Type> clonedObjects;
@@ -37,24 +45,52 @@
return cloneVec(arguments);
}
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd) {
+ auto duplicatedFd = NN_TRY(nn::dupFd(fd.get()));
+ return ndk::ScopedFileDescriptor(duplicatedFd.release());
+}
+
+nn::GeneralResult<common::NativeHandle> clone(const common::NativeHandle& handle) {
+ return common::NativeHandle{
+ .fds = NN_TRY(cloneVec(handle.fds)),
+ .ints = handle.ints,
+ };
+}
+
} // namespace
nn::GeneralResult<Memory> clone(const Memory& memory) {
- common::NativeHandle nativeHandle;
- nativeHandle.ints = memory.handle.ints;
- nativeHandle.fds.reserve(memory.handle.fds.size());
- for (const auto& fd : memory.handle.fds) {
- const int newFd = dup(fd.get());
- if (newFd < 0) {
- return NN_ERROR() << "Couldn't dup a file descriptor";
+ switch (memory.getTag()) {
+ case Memory::Tag::ashmem: {
+ const auto& ashmem = memory.get<Memory::Tag::ashmem>();
+ auto handle = common::Ashmem{
+ .fd = NN_TRY(clone(ashmem.fd)),
+ .size = ashmem.size,
+ };
+ return Memory::make<Memory::Tag::ashmem>(std::move(handle));
}
- nativeHandle.fds.emplace_back(newFd);
+ case Memory::Tag::mappableFile: {
+ const auto& memFd = memory.get<Memory::Tag::mappableFile>();
+ auto handle = common::MappableFile{
+ .length = memFd.length,
+ .prot = memFd.prot,
+ .fd = NN_TRY(clone(memFd.fd)),
+ .offset = memFd.offset,
+ };
+ return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+ }
+ case Memory::Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+ auto handle = graphics::common::HardwareBuffer{
+ .description = hardwareBuffer.description,
+ .handle = NN_TRY(clone(hardwareBuffer.handle)),
+ };
+ return Memory::make<Memory::Tag::hardwareBuffer>(std::move(handle));
+ }
}
- return Memory{
- .handle = std::move(nativeHandle),
- .size = memory.size,
- .name = memory.name,
- };
+ return (NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag())
+ .
+ operator nn::GeneralResult<Memory>();
}
nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool) {
diff --git a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
index 630a460..ff98a7d 100644
--- a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
@@ -39,7 +39,7 @@
using ::testing::SetArgPointee;
const std::shared_ptr<IPreparedModel> kInvalidPreparedModel;
-constexpr auto kNoTiming = Timing{.timeOnDevice = -1, .timeInDriver = -1};
+constexpr auto kNoTiming = Timing{.timeOnDeviceNs = -1, .timeInDriverNs = -1};
constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 7804c2a..d5b150a 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -50,9 +50,11 @@
],
static_libs: [
"android.hardware.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk_platform",
"android.hardware.neuralnetworks-V1-ndk_platform",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libaidlcommonsupport",
"libgmock",
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index 1440429..d3b041d 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -547,7 +547,7 @@
makeOutputInsufficientSize(kInsufficientOutputIndex, &request);
}
- int64_t loopTimeoutDuration = kOmittedTimeoutDuration;
+ int64_t loopTimeoutDurationNs = kOmittedTimeoutDuration;
// OutputType::MISSED_DEADLINE is only used by
// TestKind::INTINITE_LOOP_TIMEOUT tests to verify that an infinite loop is
// aborted after a timeout.
@@ -555,7 +555,7 @@
// Override the default loop timeout duration with a small value to
// speed up test execution.
constexpr int64_t kMillisecond = 1'000'000;
- loopTimeoutDuration = 1 * kMillisecond;
+ loopTimeoutDurationNs = 1 * kMillisecond;
}
ErrorStatus executionStatus;
@@ -568,7 +568,7 @@
ExecutionResult executionResult;
// execute
const auto ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDuration,
+ kNoDeadline, loopTimeoutDurationNs,
&executionResult);
ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
@@ -608,7 +608,7 @@
ExecutionResult executionResult;
// execute
ret = burst->executeSynchronously(request, slots, testConfig.measureTiming, kNoDeadline,
- loopTimeoutDuration, &executionResult);
+ loopTimeoutDurationNs, &executionResult);
ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
if (ret.isOk()) {
@@ -635,7 +635,7 @@
ErrorStatus result = ErrorStatus::NONE;
FencedExecutionResult executionResult;
auto ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDuration, kNoDuration,
+ kNoDeadline, loopTimeoutDurationNs, kNoDuration,
&executionResult);
ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
@@ -649,7 +649,7 @@
waitFor.emplace_back(dupFd);
// If a sync fence is returned, try start another run waiting for the sync fence.
ret = preparedModel->executeFenced(request, waitFor, testConfig.measureTiming,
- kNoDeadline, loopTimeoutDuration, kNoDuration,
+ kNoDeadline, loopTimeoutDurationNs, kNoDuration,
&executionResult);
ASSERT_TRUE(ret.isOk());
waitForSyncFence(executionResult.syncFence.get());
@@ -686,8 +686,8 @@
if (!testConfig.measureTiming) {
EXPECT_EQ(timing, kNoTiming);
} else {
- if (timing.timeOnDevice != -1 && timing.timeInDriver != -1) {
- EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+ if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
+ EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
}
}
diff --git a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
index 596f8ae..e8313f1 100644
--- a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "neuralnetworks_aidl_hal_test"
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
@@ -659,10 +660,26 @@
return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {});
}
+ size_t getSize(const Memory& memory) {
+ switch (memory.getTag()) {
+ case Memory::Tag::ashmem:
+ return memory.get<Memory::Tag::ashmem>().size;
+ case Memory::Tag::mappableFile:
+ return memory.get<Memory::Tag::mappableFile>().length;
+ case Memory::Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+ const bool isBlob =
+ hardwareBuffer.description.format == graphics::common::PixelFormat::BLOB;
+ return isBlob ? hardwareBuffer.description.width : 0;
+ }
+ }
+ return 0;
+ }
+
Memory allocateSharedMemory(uint32_t size) {
const auto sharedMemory = nn::createSharedMemory(size).value();
auto memory = utils::convert(sharedMemory).value();
- EXPECT_EQ(memory.size, size);
+ EXPECT_EQ(getSize(memory), size);
return memory;
}
@@ -690,7 +707,7 @@
void initializeDeviceMemory(const std::shared_ptr<IBuffer>& buffer) {
Memory memory = allocateSharedMemory(kTestOperandDataSize);
- ASSERT_EQ(memory.size, kTestOperandDataSize);
+ ASSERT_EQ(getSize(memory), kTestOperandDataSize);
testCopyFrom(buffer, memory, utils::toSigned(kTestOperand.dimensions).value(),
ErrorStatus::NONE);
}
diff --git a/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
index e803e38..bbba887 100644
--- a/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
@@ -53,7 +53,7 @@
using ExecutionFunction =
std::function<MaybeResults(const std::shared_ptr<IPreparedModel>& preparedModel,
- const Request& request, int64_t deadline)>;
+ const Request& request, int64_t deadlineNs)>;
static int64_t makeDeadline(DeadlineBoundType deadlineBoundType) {
const auto getNanosecondsSinceEpoch = [](const auto& time) -> int64_t {
@@ -79,9 +79,9 @@
void runPrepareModelTest(const std::shared_ptr<IDevice>& device, const Model& model,
Priority priority, std::optional<DeadlineBoundType> deadlineBound) {
- int64_t deadline = kNoDeadline;
+ int64_t deadlineNs = kNoDeadline;
if (deadlineBound.has_value()) {
- deadline = makeDeadline(deadlineBound.value());
+ deadlineNs = makeDeadline(deadlineBound.value());
}
// see if service can handle model
@@ -96,8 +96,8 @@
const std::shared_ptr<PreparedModelCallback> preparedModelCallback =
ndk::SharedRefBase::make<PreparedModelCallback>();
const auto prepareLaunchStatus =
- device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline,
- {}, {}, kEmptyCacheToken, preparedModelCallback);
+ device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, priority,
+ deadlineNs, {}, {}, kEmptyCacheToken, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk())
<< "prepareLaunchStatus: " << prepareLaunchStatus.getDescription();
@@ -156,13 +156,13 @@
}
static MaybeResults executeSynchronously(const std::shared_ptr<IPreparedModel>& preparedModel,
- const Request& request, int64_t deadline) {
+ const Request& request, int64_t deadlineNs) {
SCOPED_TRACE("synchronous");
const bool measure = false;
// run execution
ExecutionResult executionResult;
- const auto ret = preparedModel->executeSynchronously(request, measure, deadline,
+ const auto ret = preparedModel->executeSynchronously(request, measure, deadlineNs,
kOmittedTimeoutDuration, &executionResult);
EXPECT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
@@ -182,7 +182,7 @@
}
static MaybeResults executeBurst(const std::shared_ptr<IPreparedModel>& preparedModel,
- const Request& request, int64_t deadline) {
+ const Request& request, int64_t deadlineNs) {
SCOPED_TRACE("burst");
const bool measure = false;
@@ -200,7 +200,7 @@
// run execution
ExecutionResult executionResult;
- ret = burst->executeSynchronously(request, slots, measure, deadline, kOmittedTimeoutDuration,
+ ret = burst->executeSynchronously(request, slots, measure, deadlineNs, kOmittedTimeoutDuration,
&executionResult);
EXPECT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
<< ret.getDescription();
@@ -224,10 +224,10 @@
const ExecutionContext& context, bool synchronous,
DeadlineBoundType deadlineBound) {
const ExecutionFunction execute = synchronous ? executeSynchronously : executeBurst;
- const auto deadline = makeDeadline(deadlineBound);
+ const auto deadlineNs = makeDeadline(deadlineBound);
// Perform execution and unpack results.
- const auto results = execute(preparedModel, request, deadline);
+ const auto results = execute(preparedModel, request, deadlineNs);
if (!results.has_value()) return;
const auto& [status, outputShapes, timing] = results.value();
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index 266301c..77085a7 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -43,7 +43,7 @@
inline constexpr Priority kDefaultPriority = Priority::MEDIUM;
-inline constexpr Timing kNoTiming = {.timeOnDevice = -1, .timeInDriver = -1};
+inline constexpr Timing kNoTiming = {.timeOnDeviceNs = -1, .timeInDriverNs = -1};
inline constexpr int64_t kNoDeadline = -1;
inline constexpr int64_t kOmittedTimeoutDuration = -1;
inline constexpr int64_t kNoDuration = -1;
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index 94d3daf..698c054 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -259,12 +259,16 @@
size_t sizeForBinder(const Memory& memory) {
// This is just a guess.
- size_t size = 0;
- const NativeHandle& handle = memory.handle;
- size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
- size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
- size += sizeForBinder(memory.name);
- size += sizeof(memory);
+ size_t size = sizeof(Memory);
+
+ // Only hardwareBuffer type memory has dynamic memory that needs to be accounted for (in the
+ // form of a NativeHandle type). The other other types of memory (MappableFile, Ashmem) use a
+ // single file descriptor (with metadata) instead.
+ if (memory.getTag() == Memory::Tag::hardwareBuffer) {
+ const NativeHandle& handle = memory.get<Memory::Tag::hardwareBuffer>().handle;
+ size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
+ size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
+ }
return size;
}
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
index 0c3a196..ee7cf89 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
@@ -94,7 +94,7 @@
}
static NamedDevice makeNamedDevice(const std::string& name) {
- ndk::SpAIBinder binder(AServiceManager_getService(name.c_str()));
+ ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
return {name, IDevice::fromBinder(binder)};
}
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
index d843526..5e62b9a 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
@@ -32,7 +32,7 @@
class InvalidDevice final : public nn::IDevice {
public:
InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
- nn::DeviceType type, bool isUpdatable, std::vector<nn::Extension> extensions,
+ nn::DeviceType type, std::vector<nn::Extension> extensions,
nn::Capabilities capabilities,
std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded);
@@ -40,7 +40,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
@@ -71,7 +70,6 @@
const std::string kVersionString;
const nn::Version kFeatureLevel;
const nn::DeviceType kType;
- const bool kIsUpdatable;
const std::vector<nn::Extension> kExtensions;
const nn::Capabilities kCapabilities;
const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
index 8199c52..84ae799 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
@@ -53,7 +53,6 @@
const std::string& getVersionString() const override;
nn::Version getFeatureLevel() const override;
nn::DeviceType getType() const override;
- bool isUpdatable() const override;
const std::vector<nn::Extension>& getSupportedExtensions() const override;
const nn::Capabilities& getCapabilities() const override;
std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 924ecb2..4d26795 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -89,6 +89,59 @@
});
}
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+ const std::vector<int32_t>& ints) {
+ constexpr size_t kIntMax = std::numeric_limits<int>::max();
+ CHECK_LE(ints.size(), kIntMax);
+ native_handle_t* nativeHandle = native_handle_create(1, 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);
+
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+ return handle;
+}
+
+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), {}));
+ return hidl_memory("ashmem", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Fd& memory) {
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+
+ const auto [lowOffsetBits, highOffsetBits] = nn::getIntsFromOffset(memory.offset);
+ const std::vector<int> ints = {memory.prot, lowOffsetBits, highOffsetBits};
+
+ auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), ints));
+ return hidl_memory("mmap_fd", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::HardwareBuffer& memory) {
+ const auto* ahwb = memory.handle.get();
+ AHardwareBuffer_Desc bufferDesc;
+ AHardwareBuffer_describe(ahwb, &bufferDesc);
+
+ const bool isBlob = bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB;
+ const size_t size = isBlob ? bufferDesc.width : 0;
+ const char* const name = isBlob ? "hardware_buffer_blob" : "hardware_buffer";
+
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
+ const hidl_handle hidlHandle(nativeHandle);
+ hidl_handle copiedHandle(hidlHandle);
+
+ return hidl_memory(name, std::move(copiedHandle), size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Unknown& memory) {
+ return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
+}
+
} // anonymous namespace
nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
@@ -255,27 +308,7 @@
if (memory == nullptr) {
return NN_ERROR() << "Memory must be non-empty";
}
- if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
- return hidl_memory(memory->name, NN_TRY(hidlHandleFromSharedHandle(*handle)), memory->size);
- }
-
- const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
- AHardwareBuffer_Desc bufferDesc;
- AHardwareBuffer_describe(ahwb, &bufferDesc);
-
- if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
- CHECK_EQ(memory->size, bufferDesc.width);
- CHECK_EQ(memory->name, "hardware_buffer_blob");
- } else {
- CHECK_EQ(memory->size, 0u);
- CHECK_EQ(memory->name, "hardware_buffer");
- }
-
- const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
- const hidl_handle hidlHandle(nativeHandle);
- hidl_handle handle(hidlHandle);
-
- return hidl_memory(memory->name, std::move(handle), memory->size);
+ return std::visit([](const auto& x) { return createHidlMemoryFrom(x); }, memory->handle);
}
static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
@@ -283,14 +316,53 @@
}
nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory) {
- CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+ CHECK_LE(memory.size(), std::numeric_limits<size_t>::max());
+ if (!memory.valid()) {
+ return NN_ERROR() << "Unable to convert invalid hidl_memory";
+ }
+
+ if (memory.name() == "ashmem") {
+ if (memory.handle()->numFds != 1) {
+ return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+ << memory.handle()->numFds << " numFds, but expected 1";
+ }
+ if (memory.handle()->numInts != 0) {
+ return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+ << memory.handle()->numInts << " numInts, but expected 0";
+ }
+ auto handle = nn::Memory::Ashmem{
+ .fd = NN_TRY(nn::dupFd(memory.handle()->data[0])),
+ .size = static_cast<size_t>(memory.size()),
+ };
+ return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
+ }
+
+ if (memory.name() == "mmap_fd") {
+ if (memory.handle()->numFds != 1) {
+ return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+ << memory.handle()->numFds << " numFds, but expected 1";
+ }
+ if (memory.handle()->numInts != 3) {
+ return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+ << memory.handle()->numInts << " numInts, but expected 3";
+ }
+
+ const int fd = memory.handle()->data[0];
+ const int prot = memory.handle()->data[1];
+ const int lower = memory.handle()->data[2];
+ const int higher = memory.handle()->data[3];
+ const size_t offset = nn::getOffsetFromInts(lower, higher);
+
+ return nn::createSharedMemoryFromFd(static_cast<size_t>(memory.size()), prot, fd, offset);
+ }
if (memory.name() != "hardware_buffer_blob") {
- return std::make_shared<const nn::Memory>(nn::Memory{
+ auto handle = nn::Memory::Unknown{
.handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
- .size = static_cast<uint32_t>(memory.size()),
+ .size = static_cast<size_t>(memory.size()),
.name = memory.name(),
- });
+ };
+ return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
}
const auto size = memory.size();
@@ -328,11 +400,7 @@
<< "Can't create AHardwareBuffer from handle. Error: " << status;
}
- return std::make_shared<const nn::Memory>(nn::Memory{
- .handle = nn::HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
- .size = static_cast<uint32_t>(memory.size()),
- .name = memory.name(),
- });
+ return nn::createSharedMemoryFromAHWB(hardwareBuffer, /*takeOwnership=*/true);
}
nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
diff --git a/neuralnetworks/utils/common/src/InvalidDevice.cpp b/neuralnetworks/utils/common/src/InvalidDevice.cpp
index 81bca7f..535ccb4 100644
--- a/neuralnetworks/utils/common/src/InvalidDevice.cpp
+++ b/neuralnetworks/utils/common/src/InvalidDevice.cpp
@@ -32,14 +32,13 @@
namespace android::hardware::neuralnetworks::utils {
InvalidDevice::InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
- nn::DeviceType type, bool isUpdatable,
- std::vector<nn::Extension> extensions, nn::Capabilities capabilities,
+ nn::DeviceType type, std::vector<nn::Extension> extensions,
+ nn::Capabilities capabilities,
std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded)
: kName(std::move(name)),
kVersionString(std::move(versionString)),
kFeatureLevel(featureLevel),
kType(type),
- kIsUpdatable(isUpdatable),
kExtensions(std::move(extensions)),
kCapabilities(std::move(capabilities)),
kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded) {}
@@ -60,10 +59,6 @@
return kType;
}
-bool InvalidDevice::isUpdatable() const {
- return kIsUpdatable;
-}
-
const std::vector<nn::Extension>& InvalidDevice::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/utils/common/src/ResilientDevice.cpp b/neuralnetworks/utils/common/src/ResilientDevice.cpp
index 13965af..2023c9a 100644
--- a/neuralnetworks/utils/common/src/ResilientDevice.cpp
+++ b/neuralnetworks/utils/common/src/ResilientDevice.cpp
@@ -122,14 +122,12 @@
};
if (compare(&IDevice::getName) || compare(&IDevice::getVersionString) ||
compare(&IDevice::getFeatureLevel) || compare(&IDevice::getType) ||
- compare(&IDevice::isUpdatable) || compare(&IDevice::getSupportedExtensions) ||
- compare(&IDevice::getCapabilities)) {
+ compare(&IDevice::getSupportedExtensions) || compare(&IDevice::getCapabilities)) {
LOG(ERROR) << "Recovered device has different metadata than what is cached. Marking "
"IDevice object as invalid.";
device = std::make_shared<const InvalidDevice>(
- kName, kVersionString, mDevice->getFeatureLevel(), mDevice->getType(),
- mDevice->isUpdatable(), kExtensions, kCapabilities,
- mDevice->getNumberOfCacheFilesNeeded());
+ kName, kVersionString, mDevice->getFeatureLevel(), mDevice->getType(), kExtensions,
+ kCapabilities, mDevice->getNumberOfCacheFilesNeeded());
mIsValid = false;
}
@@ -153,10 +151,6 @@
return getDevice()->getType();
}
-bool ResilientDevice::isUpdatable() const {
- return getDevice()->isUpdatable();
-}
-
const std::vector<nn::Extension>& ResilientDevice::getSupportedExtensions() const {
return kExtensions;
}
diff --git a/neuralnetworks/utils/common/test/MockDevice.h b/neuralnetworks/utils/common/test/MockDevice.h
index b274716..a9428bc 100644
--- a/neuralnetworks/utils/common/test/MockDevice.h
+++ b/neuralnetworks/utils/common/test/MockDevice.h
@@ -29,7 +29,6 @@
MOCK_METHOD(const std::string&, getVersionString, (), (const, override));
MOCK_METHOD(Version, getFeatureLevel, (), (const, override));
MOCK_METHOD(DeviceType, getType, (), (const, override));
- MOCK_METHOD(bool, isUpdatable, (), (const, override));
MOCK_METHOD(const std::vector<Extension>&, getSupportedExtensions, (), (const, override));
MOCK_METHOD(const Capabilities&, getCapabilities, (), (const, override));
MOCK_METHOD((std::pair<uint32_t, uint32_t>), getNumberOfCacheFilesNeeded, (),
diff --git a/neuralnetworks/utils/service/include/nnapi/hal/Service.h b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
index e339627..2fd5237 100644
--- a/neuralnetworks/utils/service/include/nnapi/hal/Service.h
+++ b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
@@ -22,10 +22,15 @@
#include <memory>
#include <vector>
-namespace android::nn::hal {
+namespace android::hardware::neuralnetworks::service {
-std::vector<nn::SharedDevice> getDevices();
+struct SharedDeviceAndUpdatability {
+ nn::SharedDevice device;
+ bool isDeviceUpdatable = false;
+};
-} // namespace android::nn::hal
+std::vector<SharedDeviceAndUpdatability> getDevices(bool includeUpdatableDrivers);
+
+} // namespace android::hardware::neuralnetworks::service
#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
index c83bcc9..2286288 100644
--- a/neuralnetworks/utils/service/src/Service.cpp
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -16,6 +16,7 @@
#include "Service.h"
+#include <AndroidVersionUtil.h>
#include <aidl/android/hardware/neuralnetworks/IDevice.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
@@ -34,6 +35,7 @@
#include <nnapi/hal/1.2/Service.h>
#include <nnapi/hal/1.3/Service.h>
#include <nnapi/hal/aidl/Service.h>
+#include <nnapi/hal/aidl/Utils.h>
#include <functional>
#include <memory>
@@ -49,7 +51,7 @@
using getDeviceFn = std::add_pointer_t<nn::GeneralResult<nn::SharedDevice>(const std::string&)>;
void getHidlDevicesForVersion(const std::string& descriptor, getDeviceFn getDevice,
- std::vector<nn::SharedDevice>* devices,
+ std::vector<SharedDeviceAndUpdatability>* devices,
std::unordered_set<std::string>* registeredDevices) {
CHECK(devices != nullptr);
CHECK(registeredDevices != nullptr);
@@ -61,7 +63,7 @@
if (maybeDevice.has_value()) {
auto device = std::move(maybeDevice).value();
CHECK(device != nullptr);
- devices->push_back(std::move(device));
+ devices->push_back({.device = std::move(device)});
} else {
LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
<< ": " << maybeDevice.error().message;
@@ -70,8 +72,9 @@
}
}
-void getAidlDevices(std::vector<nn::SharedDevice>* devices,
- std::unordered_set<std::string>* registeredDevices) {
+void getAidlDevices(std::vector<SharedDeviceAndUpdatability>* devices,
+ std::unordered_set<std::string>* registeredDevices,
+ bool includeUpdatableDrivers) {
CHECK(devices != nullptr);
CHECK(registeredDevices != nullptr);
@@ -82,18 +85,27 @@
// Devices with SDK level lower than 31 (Android S) don't have any AIDL drivers available, so
// there is no need for a workaround supported on lower levels.
- if (__builtin_available(android __ANDROID_API_S__, *)) {
+ if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
AServiceManager_forEachDeclaredInstance(aidl_hal::IDevice::descriptor,
static_cast<void*>(&names), callback);
}
for (const auto& name : names) {
+ bool isDeviceUpdatable = false;
+ if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
+ const auto instance = std::string(aidl_hal::IDevice::descriptor) + '/' + name;
+ isDeviceUpdatable = AServiceManager_isUpdatableViaApex(instance.c_str());
+ }
+ if (isDeviceUpdatable && !includeUpdatableDrivers) {
+ continue;
+ }
if (const auto [it, unregistered] = registeredDevices->insert(name); unregistered) {
auto maybeDevice = aidl_hal::utils::getDevice(name);
if (maybeDevice.has_value()) {
auto device = std::move(maybeDevice).value();
CHECK(device != nullptr);
- devices->push_back(std::move(device));
+ devices->push_back(
+ {.device = std::move(device), .isDeviceUpdatable = isDeviceUpdatable});
} else {
LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
<< ": " << maybeDevice.error().message;
@@ -102,11 +114,13 @@
}
}
-std::vector<nn::SharedDevice> getDevices() {
- std::vector<nn::SharedDevice> devices;
+} // namespace
+
+std::vector<SharedDeviceAndUpdatability> getDevices(bool includeUpdatableDrivers) {
+ std::vector<SharedDeviceAndUpdatability> devices;
std::unordered_set<std::string> registeredDevices;
- getAidlDevices(&devices, ®isteredDevices);
+ getAidlDevices(&devices, ®isteredDevices, includeUpdatableDrivers);
getHidlDevicesForVersion(V1_3::IDevice::descriptor, &V1_3::utils::getDevice, &devices,
®isteredDevices);
@@ -120,13 +134,4 @@
return devices;
}
-} // namespace
} // namespace android::hardware::neuralnetworks::service
-
-namespace android::nn::hal {
-
-std::vector<nn::SharedDevice> getDevices() {
- return hardware::neuralnetworks::service::getDevices();
-}
-
-} // namespace android::nn::hal
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index a4e8811..e2d35d0 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -145,7 +145,6 @@
*
* Response function is IRadioResponse.setupDataCallResponse_1_6()
*
- * Note this API is the same as the 1.5
*/
oneway setupDataCall_1_6(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
@@ -177,7 +176,7 @@
* @param serial Serial number of request.
* @param message GsmSmsMessage as defined in types.hal
*
- * Response function is IRadioResponse.sendSMSExpectMoreResponse_1_6()
+ * Response function is IRadioResponse.sendSmsExpectMoreResponse_1_6()
*
* Note this API is the same as the 1.0
*
@@ -185,7 +184,7 @@
* fails. RadioError:SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
* and RadioError:GENERIC_FAILURE means no retry (i.e. error cause is 500)
*/
- oneway sendSMSExpectMore_1_6(int32_t serial, GsmSmsMessage message);
+ oneway sendSmsExpectMore_1_6(int32_t serial, GsmSmsMessage message);
/**
* Send a CDMA SMS message
@@ -267,7 +266,7 @@
* 2. Disable NR dual connectivity {NrDualConnectivityState:DISABLE}
* 3. Disable NR dual connectivity and force secondary cell to be released
* {NrDualConnectivityState:DISABLE_IMMEDIATE}
-
+ *
* Response callback is IRadioResponse.setNRDualConnectivityStateResponse()
*/
oneway setNrDualConnectivityState(int32_t serial,
@@ -372,7 +371,7 @@
*
* Response callback is IRadioResponse.getAllowedNetworkTypesBitmapResponse()
*/
- oneway getAllowedNetworkTypesBitmap(uint32_t serial);
+ oneway getAllowedNetworkTypesBitmap(int32_t serial);
/**
* Control data throttling at modem.
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index 9788345..05a7585 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -107,7 +107,7 @@
/**
* Indicates physical channel configurations.
*
- * An empty configs list indicates that the radio is in idle mode.
+ * An empty configs list shall be returned when the radio is in idle mode (i.e. RRC idle).
*
* @param type Type of radio indication
* @param configs Vector of PhysicalChannelConfigs
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index f2c06b7..a1286a5 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -139,7 +139,7 @@
* RadioError:ACCESS_BARRED
* RadioError:BLOCKED_DUE_TO_CALL
*/
- oneway sendSMSExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+ oneway sendSmsExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
/**
* @param info Response info struct containing response type, serial no. and error
@@ -232,6 +232,7 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:INVALID_STATE
*/
oneway setNrDualConnectivityStateResponse(RadioResponseInfo info);
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index 82c9daa..4b75db5 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -55,9 +55,9 @@
struct QosBandwidth {
/** Maximum bit rate possible on the bearer */
- int32_t maxBitrateKbps;
+ uint32_t maxBitrateKbps;
/** Minimum bit rate that is guaranteed to be provided by the network */
- int32_t guaranteedBitrateKbps;
+ uint32_t guaranteedBitrateKbps;
};
/** LTE/EPS Quality of Service parameters as per 3gpp spec 24.301 sec 9.9.4.3. */
@@ -106,7 +106,7 @@
/**
* Next header protocol numbers defined by IANA, RFC 5237
*/
-enum QosProtocol : int32_t {
+enum QosProtocol : int8_t {
/** No protocol specified */
UNSPECIFIED = -1,
/** Transmission Control Protocol */
@@ -119,14 +119,14 @@
AH = 51,
};
-enum QosFilterDirection : int32_t {
+enum QosFilterDirection : int8_t {
DOWNLINK = 0,
UPLINK = 1,
BIDIRECTIONAL = 2,
};
/** Allowed port numbers */
-enum QosPortRange : int32_t {
+enum QosPortRange : uint16_t {
MIN = 20,
MAX = 65535
};
@@ -248,7 +248,7 @@
};
/** The allowed failure modes on an IWLAN handover failure. */
-enum HandoverFailureMode : int32_t {
+enum HandoverFailureMode : int8_t {
/**
* On data handover failure, fallback to the source data transport when the
* fail cause is due to a hand off preference change.
@@ -379,7 +379,7 @@
/**
* NR Dual connectivity state
*/
-enum NrDualConnectivityState: int32_t {
+enum NrDualConnectivityState: int8_t {
/**
* Enable NR dual connectivity. Enabled state does not mean dual connectivity
* is active. It means device is allowed to connect to both primary and secondary.
@@ -408,7 +408,7 @@
* the estimated maximum sustainable link bandwidth (as would be measured
* at the Upper PDCP or SNDCP SAP). If the DL Aggregate Maximum Bit Rate is known,
* this value shall not exceed the DL-AMBR for the Internet PDN connection.
- * This must be filled with -1 if network is not connected.
+ * This must be filled with 0 if network is not connected.
*/
uint32_t downlinkCapacityKbps;
@@ -418,7 +418,7 @@
* estimated maximum sustainable link bandwidth (as would be measured at the
* Upper PDCP or SNDCP SAP). If the UL Aggregate Maximum Bit Rate is known,
* this value shall not exceed the UL-AMBR for the Internet PDN connection.
- * This must be filled with -1 if network is not connected.
+ * This must be filled with 0 if network is not connected.
*/
uint32_t uplinkCapacityKbps;
@@ -427,7 +427,8 @@
* This bandwidth estimate shall be the estimated maximum sustainable link bandwidth
* (as would be measured at the Upper PDCP or SNDCP SAP). This is valid only
* in if device is connected to both primary and secodary in dual connected
- * mode. This must be filled with -1 if secondary is not connected.
+ * mode. This must be filled with 0 if secondary is not connected or if
+ * modem does not support this feature.
*/
uint32_t secondaryDownlinkCapacityKbps;
@@ -436,12 +437,13 @@
* This bandwidth estimate shall be the estimated
* maximum sustainable link bandwidth (as would be measured at the Upper PDCP or SNDCP SAP).
* This is valid only in if device is connected to both primary and secodary in dual connected
- * mode.This must be filled with -1 if secondary is not connected.
+ * mode.This must be filled with 0 if secondary is not connected or if modem
+ * does not support this feature.
*/
uint32_t secondaryUplinkCapacityKbps;
};
-enum DataThrottlingAction : int32_t {
+enum DataThrottlingAction : int8_t {
/* Clear all existing data throttling. */
NO_DATA_THROTTLING = 0,
@@ -579,9 +581,9 @@
*
* Reference: 3GPP TS 138.214 section 5.2.2.1.
*
- * Range [0, 15], INT_MAX means invalid/unreported.
+ * Range [0, 15], 0xFF means invalid/unreported.
*/
- vec<uint32_t> csiCqiReport;
+ vec<uint8_t> csiCqiReport;
};
/**
@@ -738,22 +740,19 @@
EutranRegistrationInfo eutranInfo;
- struct NgranRegistrationInfo {
- /**
- * Network capabilities for voice over PS services. This info is valid only on NR
- * network and must be present when the device is camped on NR. VopsInfo must be
- * empty when the device is not camped on NR.
- */
- NrVopsInfo nrVopsInfo;
- } ngranInfo;
+ /**
+ * Network capabilities for voice over PS services. This info is valid only on NR
+ * network and must be present when the device is camped on NR. VopsInfo must be
+ * empty when the device is not camped on NR.
+ */
+ NrVopsInfo ngranNrVopsInfo;
- struct GeranRegistrationInfo {
- /**
- * True if the dual transfer mode is supported.
- * Refer to 3GPP TS 44.108 section 3.4.25.3
- */
- bool dtmSupported;
- } geranInfo;
+ /**
+ * True if the dual transfer mode is supported.
+ * Refer to 3GPP TS 44.108 section 3.4.25.3
+ */
+ bool geranDtmSupported;
+
} accessTechnologySpecificInfo;
};
@@ -780,10 +779,10 @@
int32_t uplinkChannelNumber;
/** Downlink cell bandwidth, in kHz */
- int32_t cellBandwidthDownlink;
+ int32_t cellBandwidthDownlinkKhz;
/** Uplink cell bandwidth, in kHz */
- int32_t cellBandwidthUplink;
+ int32_t cellBandwidthUplinkKhz;
/**
* A list of data calls mapped to this physical channel. The context id must match the cid of
@@ -1069,7 +1068,7 @@
SscMode value;
};
-enum SliceStatus : int32_t {
+enum SliceStatus : int8_t {
UNKNOWN,
CONFIGURED, // Configured but not allowed or rejected yet
ALLOWED, // Allowed to be used
@@ -1082,7 +1081,7 @@
* Enum representing session and service continuity mode as defined in
* 3GPP TS 23.501.
*/
-enum SscMode : int32_t {
+enum SscMode : int8_t {
MODE_1 = 1,
MODE_2 = 2,
MODE_3 = 3,
@@ -1091,7 +1090,7 @@
/**
* Public key type from carrier certificate.
*/
-enum PublicKeyType : int32_t {
+enum PublicKeyType : int8_t {
EPDG = 1, // Key type to be used for ePDG
WLAN = 2, // Key type to be used for WLAN
};
@@ -1200,7 +1199,7 @@
* chunk of phonebook data, means this is a last indication with the left
* data.
*/
-enum PbReceivedStatus : int32_t {
+enum PbReceivedStatus : int8_t {
PB_RECEIVED_OK = 1,
PB_RECEIVED_ERROR = 2,
PB_RECEIVED_ABORT = 3,
diff --git a/radio/1.6/vts/functional/Android.bp b/radio/1.6/vts/functional/Android.bp
index 65b0dd0..2bc6af3 100644
--- a/radio/1.6/vts/functional/Android.bp
+++ b/radio/1.6/vts/functional/Android.bp
@@ -28,6 +28,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"radio_hidl_hal_api.cpp",
+ "radio_hidl_hal_misc.cpp",
"radio_hidl_hal_test.cpp",
"radio_response.cpp",
"radio_indication.cpp",
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 a9c21ff..7c05984 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -204,10 +204,10 @@
}
/*
- * Test IRadio_1_6.sendSMSExpectMore() for the response returned.
+ * Test IRadio_1_6.sendSmsExpectMore() for the response returned.
*/
-TEST_P(RadioHidlTest_v1_6, sendSMSExpectMore_1_6) {
- LOG(DEBUG) << "sendSMSExpectMore";
+TEST_P(RadioHidlTest_v1_6, sendSmsExpectMore_1_6) {
+ LOG(DEBUG) << "sendSmsExpectMore";
serial = GetRandomSerialNumber();
GsmSmsMessage msg;
msg.smscPdu = "";
@@ -227,7 +227,7 @@
::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
CHECK_GENERAL_ERROR));
}
- LOG(DEBUG) << "sendSMSExpectMore finished";
+ LOG(DEBUG) << "sendSmsExpectMore finished";
}
/*
@@ -369,7 +369,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -378,6 +378,7 @@
CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
::android::hardware::radio::V1_6::RadioError::NONE}));
}
}
@@ -394,7 +395,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -420,7 +421,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -432,6 +433,8 @@
::android::hardware::radio::V1_6::RadioError::NONE,
::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
}
+
+ sleep(1);
serial = GetRandomSerialNumber();
res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER,
@@ -440,7 +443,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -452,6 +455,8 @@
::android::hardware::radio::V1_6::RadioError::NONE,
::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
}
+
+ sleep(1);
serial = GetRandomSerialNumber();
res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::HOLD, 60000);
@@ -460,7 +465,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -472,6 +477,8 @@
::android::hardware::radio::V1_6::RadioError::NONE,
::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
}
+
+ sleep(1);
serial = GetRandomSerialNumber();
res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60000);
@@ -479,7 +486,7 @@
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().modemReducedFeatureSet1) {
+ if (getRadioHalCapabilities()) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.6/vts/functional/radio_hidl_hal_misc.cpp
new file mode 100644
index 0000000..4222441
--- /dev/null
+++ b/radio/1.6/vts/functional/radio_hidl_hal_misc.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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 <regex>
+
+#include <android-base/logging.h>
+#include <radio_hidl_hal_utils_v1_6.h>
+
+/*
+ * Test IRadio.getAvailableNetworks() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, getAvailableNetworks) {
+ LOG(DEBUG) << "getAvailableNetworks";
+ serial = GetRandomSerialNumber();
+
+ radio_v1_6->getAvailableNetworks(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo_v1_0.serial);
+ ASSERT_TRUE(radioRsp_v1_6->rspInfo_v1_0.type == RadioResponseType::SOLICITED ||
+ radioRsp_v1_6->rspInfo_v1_0.type == RadioResponseType::SOLICITED_ACK_EXP);
+
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_6->rspInfo_v1_0.error,
+ {::android::hardware::radio::V1_0::RadioError::NONE,
+ ::android::hardware::radio::V1_0::RadioError::CANCELLED,
+ ::android::hardware::radio::V1_0::RadioError::DEVICE_IN_USE,
+ ::android::hardware::radio::V1_0::RadioError::MODEM_ERR,
+ ::android::hardware::radio::V1_0::RadioError::OPERATION_NOT_ALLOWED},
+ CHECK_GENERAL_ERROR));
+ } else if (radioRsp_v1_6->rspInfo_v1_0.error ==
+ ::android::hardware::radio::V1_0::RadioError::NONE) {
+ static const std::regex kOperatorNumericRe("^[0-9]{5,6}$");
+ for (OperatorInfo info : radioRsp_v1_6->networkInfos) {
+ if (info.operatorNumeric != nullptr) {
+ ASSERT_TRUE(
+ std::regex_match(std::string(info.operatorNumeric), kOperatorNumericRe));
+ }
+ }
+ }
+
+ LOG(DEBUG) << "getAvailableNetworks finished";
+}
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_test.cpp b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
index 6255f66..5d514a0 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
@@ -86,16 +86,14 @@
* disabled.
* <p/>
* Typical usage within VTS:
- * if (getRadioHalCapabilities().modemReducedFeatureSet) return;
+ * if (getRadioHalCapabilities()) return;
*/
-HalDeviceCapabilities RadioHidlTest_v1_6::getRadioHalCapabilities() {
+bool RadioHidlTest_v1_6::getRadioHalCapabilities() {
sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig_v1_3 =
::android::hardware::radio::config::V1_3::IRadioConfig::getService();
if (radioConfig_v1_3.get() == nullptr) {
// If v1_3 isn't present, the values are initialized to false
- HalDeviceCapabilities radioHalCapabilities;
- memset(&radioHalCapabilities, 0, sizeof(radioHalCapabilities));
- return radioHalCapabilities;
+ return false;
} else {
// Get radioHalDeviceCapabilities from the radio config
sp<RadioConfigResponse> radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
@@ -104,6 +102,6 @@
radioConfig_v1_3->getHalDeviceCapabilities(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
- return radioConfigRsp->halDeviceCapabilities;
+ return radioConfigRsp->modemReducedFeatureSet1;
}
}
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index 4fc17e5..3185f98 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -38,14 +38,12 @@
using namespace ::android::hardware::radio::V1_2;
using namespace ::android::hardware::radio::V1_1;
using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_3;
using ::android::sp;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using ::android::hardware::radio::config::V1_3::HalDeviceCapabilities;
#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
@@ -62,6 +60,7 @@
public:
hidl_vec<RadioBandMode> radioBandModes;
+ hidl_vec<OperatorInfo> networkInfos;
::android::hardware::radio::V1_0::RadioResponseInfo rspInfo_v1_0;
::android::hardware::radio::V1_6::RadioResponseInfo rspInfo;
@@ -762,7 +761,7 @@
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
const SendSmsResult& sms);
- Return<void> sendSMSExpectMoreResponse_1_6(
+ Return<void> sendSmsExpectMoreResponse_1_6(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
const SendSmsResult& sms);
@@ -1115,7 +1114,7 @@
public:
virtual void SetUp() override;
- HalDeviceCapabilities getRadioHalCapabilities();
+ bool getRadioHalCapabilities();
/* radio service handle */
sp<::android::hardware::radio::V1_6::IRadio> radio_v1_6;
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index 2b6d1bb..6e7b86f 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -274,8 +274,11 @@
}
Return<void> RadioResponse_v1_6::getAvailableNetworksResponse(
- const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
- const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
+ const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+ const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos) {
+ rspInfo_v1_0 = info;
+ this->networkInfos = networkInfos;
+ parent_v1_6.notify(info.serial);
return Void();
}
@@ -1090,7 +1093,7 @@
return Void();
}
-Return<void> RadioResponse_v1_6::sendSMSExpectMoreResponse_1_6(
+Return<void> RadioResponse_v1_6::sendSmsExpectMoreResponse_1_6(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
const SendSmsResult& sms) {
rspInfo = info;
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
index cc5944d..dc0d82c 100644
--- a/radio/config/1.3/Android.bp
+++ b/radio/config/1.3/Android.bp
@@ -13,7 +13,6 @@
name: "android.hardware.radio.config@1.3",
root: "android.hardware",
srcs: [
- "types.hal",
"IRadioConfig.hal",
"IRadioConfigResponse.hal",
],
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
index 863754f..f6aee31 100644
--- a/radio/config/1.3/IRadioConfigResponse.hal
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -18,7 +18,6 @@
import android.hardware.radio@1.6::RadioResponseInfo;
import @1.2::IRadioConfigResponse;
-import HalDeviceCapabilities;
/**
* Interface declaring response functions to solicited radio config requests.
@@ -26,8 +25,20 @@
interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
/**
* @param info Response info struct containing response type, serial no. and error
- * @param capabilities Capabilities struct containing the capabilities of the
- * device related to the Radio HAL
+ * @param modemReducedFeatureSet1 True indicates that the modem does NOT support the following
+ * features.
+ * - Providing either
+ * android.hardware.radio@1.6::LinkCapacityEstimate:secondaryDownlinkCapacityKbps
+ * or android.hardware.radio@1.6::LinkCapacityEstimate:secondaryUplinkCapacityKbps
+ * when given from
+ * android.hardware.radio@1.6::RadioIndication:currentLinkCapacityEstimate
+ * - Calling android.hardware.radio@1.6::IRadio.setNrDualConnectivityState
+ * or querying android.hardware.radio@1.6::IRadio.isNrDualConnectivityEnabled
+ * - Requesting android.hardware.radio@1.6::IRadio.setDataThrottling()
+ * - Providing android.hardware.radio@1.6::SlicingConfig through
+ * android.hardware.radio@1.6::getSlicingConfig()
+ * - Providing android.hardware.radio@1.6::PhysicalChannelConfig through
+ * android.hardware.radio@1.6::IRadioIndication.currentPhysicalChannelConfigs_1_6()
*
* Valid errors returned:
* RadioError:NONE
@@ -35,5 +46,5 @@
* RadioError:INTERNAL_ERR
*/
oneway getHalDeviceCapabilitiesResponse(RadioResponseInfo info,
- HalDeviceCapabilities capabilities);
+ bool modemReducedFeatureSet1);
};
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
index 895ae08..7440054 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -29,7 +29,6 @@
#include <android/hardware/radio/config/1.2/types.h>
#include <android/hardware/radio/config/1.3/IRadioConfig.h>
#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
-#include <android/hardware/radio/config/1.3/types.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -47,7 +46,6 @@
using ::android::hardware::radio::config::V1_1::ModemsConfig;
using ::android::hardware::radio::config::V1_1::PhoneCapability;
using ::android::hardware::radio::config::V1_2::SimSlotStatus;
-using ::android::hardware::radio::config::V1_3::HalDeviceCapabilities;
using ::android::hardware::radio::config::V1_3::IRadioConfig;
using ::android::hardware::radio::V1_0::RadioResponseInfo;
@@ -63,7 +61,7 @@
public:
RadioResponseInfo rspInfo;
PhoneCapability phoneCap;
- HalDeviceCapabilities halDeviceCapabilities;
+ bool modemReducedFeatureSet1;
RadioConfigResponse(RadioResponseWaiter& parent);
virtual ~RadioConfigResponse() = default;
@@ -91,7 +89,7 @@
Return<void> getHalDeviceCapabilitiesResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
- const HalDeviceCapabilities& halDeviceCapabilities);
+ bool modemReducedFeatureSet1);
};
/* Callback class for radio config indication */
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
index 11e3cce..6b2d27c 100644
--- a/radio/config/1.3/vts/functional/radio_config_response.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -65,7 +65,7 @@
Return<void> RadioConfigResponse::getHalDeviceCapabilitiesResponse(
const ::android::hardware::radio::V1_6::RadioResponseInfo& /* info */,
- const ::android::hardware::radio::config::V1_3::HalDeviceCapabilities& capabilities) {
- halDeviceCapabilities = capabilities;
+ bool modemReducedFeatures) {
+ modemReducedFeatureSet1 = modemReducedFeatures;
return Void();
}
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
index b9fb2a9..1f67a3e 100644
--- a/rebootescrow/aidl/default/Android.bp
+++ b/rebootescrow/aidl/default/Android.bp
@@ -87,7 +87,9 @@
],
static_libs: [
"libhadamardutils",
- "libgtest_prod",
+ ],
+ header_libs: [
+ "libgtest_prod_headers",
],
shared_libs: [
"liblog",
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index bf30999..3f75af6 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -44,10 +44,9 @@
void deleteKey(in byte[] keyBlob);
void deleteAllKeys();
void destroyAttestationIds();
- android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
+ android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken);
void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
void earlyBootEnded();
byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
- byte[] performOperation(in byte[] request);
const int AUTH_TOKEN_MAC_LENGTH = 32;
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 88c479c..f566462 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -35,6 +35,7 @@
/* @hide */
@VintfStability
interface IRemotelyProvisionedComponent {
+ android.hardware.security.keymint.RpcHardwareInfo getHardwareInfo();
byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
byte[] generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out android.hardware.security.keymint.DeviceInfo deviceInfo, out android.hardware.security.keymint.ProtectedData protectedData);
const int STATUS_FAILED = 1;
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..06bce19
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable RpcHardwareInfo {
+ int versionNumber;
+ @utf8InCpp String rpcAuthorName;
+ int supportedEekCurve = 0;
+ const int CURVE_NONE = 0;
+ const int CURVE_P256 = 1;
+ const int CURVE_25519 = 2;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index 7591318..e310b44 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -48,7 +48,6 @@
RSA_PUBLIC_EXPONENT = 1342177480,
INCLUDE_UNIQUE_ID = 1879048394,
RSA_OAEP_MGF_DIGEST = 536871115,
- BLOB_USAGE_REQUIREMENTS = 268435757,
BOOTLOADER_ONLY = 1879048494,
ROLLBACK_RESISTANCE = 1879048495,
HARDWARE_TYPE = 268435760,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl
index 2304a58..b5336b9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/BeginResult.aidl
@@ -25,7 +25,10 @@
*/
@VintfStability
parcelable BeginResult {
- /* This is the challenge used in verifyAuthorization. It must be a nonce. */
+ /**
+ * This is the challenge used to verify authorization of an operation.
+ * See IKeyMintOperation.aidl entrypoints updateAad() and update().
+ */
long challenge;
/**
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 1c503c2..603e33f 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -107,7 +107,6 @@
*
* - 168-bit keys.
* - CBC and ECB mode.
-
* - CBC and ECB modes must support unpadded and PKCS7 padding modes. With no padding CBC and
* ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a
* multiple of the DES block size.
@@ -150,8 +149,8 @@
*
* The IKeyMintDevice must ignore unknown tags.
*
- * The caller must always provide the current date time in the keyParameter CREATION_DATETIME
- * tags.
+ * The caller may provide the current date time in the keyParameter CREATION_DATETIME tag, but
+ * this is optional and informational only.
*
* All authorization tags and their values enforced by an IKeyMintDevice must be cryptographically
* bound to the private/secret key material such that any modification of the portion of the key
@@ -185,7 +184,7 @@
* startup, preferably by the bootloader. This bitstring must be cryptographically bound to every
* key managed by the IKeyMintDevice. As above, the recommended mechanism for this cryptographic
* binding is to include the Root of Trust data in the input to the key derivation function used to
- * derive a key that is used to encryp the private/secret key material.
+ * derive a key that is used to encrypt the private/secret key material.
*
* The root of trust consists of a bitstring that must be derived from the public key used by
* Verified Boot to verify the signature on the boot image and from the lock state of the
@@ -247,7 +246,7 @@
* Generates a new cryptographic key, specifying associated parameters, which must be
* cryptographically bound to the key. IKeyMintDevice implementations must disallow any use
* of a key in any way inconsistent with the authorizations specified at generation time. With
- * respect to parameters that the secure environment cannot enforce, the secure envionment's
+ * respect to parameters that the secure environment cannot enforce, the secure environment's
* obligation is limited to ensuring that the unenforceable parameters associated with the key
* cannot be modified. In addition, the characteristics returned by generateKey places
* parameters correctly in the tee-enforced and strongbox-enforced lists.
@@ -257,9 +256,6 @@
*
* o Tag::ORIGIN with the value KeyOrigin::GENERATED.
*
- * o Tag::BLOB_USAGE_REQUIREMENTS with the appropriate value (see KeyBlobUsageRequirements in
- * Tag.aidl).
- *
* o Tag::OS_VERSION, Tag::OS_PATCHLEVEL, Tag::VENDOR_PATCHLEVEL and Tag::BOOT_PATCHLEVEL with
* appropriate values.
*
@@ -271,7 +267,7 @@
*
* The following parameters are required to generate an RSA key:
*
- * o Tag::Key_SIZE specifies the size of the public modulus, in bits. If omitted, generateKey
+ * o Tag::KEY_SIZE specifies the size of the public modulus, in bits. If omitted, generateKey
* must return ErrorCode::UNSUPPORTED_KEY_SIZE. Required values for TEE IKeyMintDevice
* implementations are 1024, 2048, 3072 and 4096. StrongBox IKeyMintDevice implementations
* must support 2048.
@@ -288,7 +284,7 @@
* except AGREE_KEY must be supported for RSA keys.
*
* o Tag::DIGEST specifies digest algorithms that may be used with the new key. TEE
- * IKeyMintDevice implementatiosn must support all Digest values (see digest.aidl) for RSA
+ * IKeyMintDevice implementations must support all Digest values (see digest.aidl) for RSA
* keys. StrongBox IKeyMintDevice implementations must support SHA_2_256.
*
* o Tag::PADDING specifies the padding modes that may be used with the new
@@ -298,11 +294,9 @@
*
* == ECDSA Keys ==
*
- * Either Tag::KEY_SIZE or Tag::EC_CURVE must be provided to generate an ECDSA key. If neither
- * is provided, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE. If Tag::KEY_SIZE is
- * provided, the possible values are 224, 256, 384 and 521, and must be mapped to Tag::EC_CURVE
- * values P_224, P_256, P_384 and P_521, respectively. TEE IKeyMintDevice implementations
- * must support all curves. StrongBox implementations must support P_256.
+ * 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.
*
* == AES Keys ==
*
@@ -312,6 +306,10 @@
* If Tag::BLOCK_MODE is specified with value BlockMode::GCM, then the caller must also provide
* Tag::MIN_MAC_LENGTH. If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH.
*
+ * == 3DES Keys ==
+ *
+ * Only Tag::KEY_SIZE is required to generate an 3DES key, and its value must be 168. If
+ * omitted, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.
*
* @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
* provided in params. See above for detailed specifications of which tags are required
@@ -325,6 +323,10 @@
* return ErrorCode::INCOMPATIBLE_PURPOSE. If the provided AttestationKey has an empty
* issuer subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
*
+ * If `attestationKey` is null and `keyParams` contains Tag::ATTESTATION_CHALLENGE but
+ * the KeyMint implementation does not have factory-provisioned attestation keys, it must
+ * return ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
KeyCreationResult generateKey(
@@ -348,13 +350,12 @@
*
* o Tag::ORIGIN (returned in keyCharacteristics) must have the value KeyOrigin::IMPORTED.
*
- * @param inKeyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
+ * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
* provided in params.
*
- * @param inKeyFormat The format of the key material to import. See KeyFormat in
- * keyformat.aidl.
+ * @param keyFormat The format of the key material to import. See KeyFormat in keyformat.aidl.
*
- * @param inKeyData The key material to import, in the format specified in keyFormat.
+ * @param keyData The key material to import, in the format specified in keyFormat.
*
* @param attestationKey, if provided, specifies the key that must be used to sign the
* attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
@@ -364,6 +365,10 @@
* return ErrorCode::INCOMPATIBLE_PURPOSE. If the provided AttestationKey has an empty
* issuer subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
*
+ * If `attestationKey` is null and `keyParams` contains Tag::ATTESTATION_CHALLENGE but
+ * the KeyMint implementation does not have factory-provisioned attestation keys, it must
+ * return ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
KeyCreationResult importKey(in KeyParameter[] keyParams, in KeyFormat keyFormat,
@@ -373,9 +378,8 @@
* Securely imports a key, or key pair, returning a key blob and a description of the imported
* key.
*
- * @param inWrappedKeyData The wrapped key material to import.
- * TODO(seleneh) Decide if we want the wrapped key in DER-encoded ASN.1 format or CBOR
- * format or both. And specify the standarized format.
+ * @param wrappedKeyData The wrapped key material to import, as ASN.1 DER-encoded data
+ * corresponding to the following schema.
*
* KeyDescription ::= SEQUENCE(
* keyFormat INTEGER, # Values from KeyFormat enum.
@@ -393,20 +397,20 @@
*
* Where:
*
- * o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+ * - keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
* key material.
- * o keyParams is the characteristics of the key to be imported (as with generateKey or
+ * - keyParams is the characteristics of the key to be imported (as with generateKey or
* importKey). If the secure import is successful, these characteristics must be
* associated with the key exactly as if the key material had been insecurely imported
- * with the IKeyMintDevice::importKey. See attestKey() for documentation of the
- * AuthorizationList schema.
- * o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+ * with the IKeyMintDevice::importKey. See KeyCreationResult.aidl for documentation of
+ * the AuthorizationList schema.
+ * - encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
* with the wrapping key specified by wrappingKeyBlob.
- * o keyDescription is a KeyDescription, above.
- * o encryptedKey is the key material of the key to be imported, in format keyFormat, and
+ * - keyDescription is a KeyDescription, above.
+ * - encryptedKey is the key material of the key to be imported, in format keyFormat, and
* encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
* representation of keyDescription provided as additional authenticated data.
- * o tag is the tag produced by the AES-GCM encryption of encryptedKey.
+ * - tag is the tag produced by the AES-GCM encryption of encryptedKey.
*
* So, importWrappedKey does the following:
*
@@ -435,7 +439,7 @@
*
* @param passwordSid specifies the password secure ID (SID) of the user that owns the key being
* installed. If the authorization list in wrappedKeyData contains a
- * Tag::USER_SECURE_IDwith a value that has the HardwareAuthenticatorType::PASSWORD bit
+ * Tag::USER_SECURE_ID with a value that has the HardwareAuthenticatorType::PASSWORD bit
* set, the constructed key must be bound to the SID value provided by this argument. If
* the wrappedKeyData does not contain such a tag and value, this argument must be
* ignored.
@@ -478,9 +482,9 @@
* patch level and OS version. This requirement is relaxed for 4.0::IKeymasterDevice and
* IKeyMintDevice, and the OS version in the boot image footer is no longer used.
*
- * @param inKeyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+ * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey().
*
- * @param inUpgradeParams A parameter list containing any parameters needed to complete the
+ * @param upgradeParams A parameter list containing any parameters needed to complete the
* upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
*
* @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
@@ -494,7 +498,9 @@
* render the key permanently unusable. Keys without Tag::ROLLBACK_RESISTANCE may or
* may not be rendered unusable.
*
- * @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @return error See the ErrorCode enum.
*/
void deleteKey(in byte[] keyBlob);
@@ -503,8 +509,6 @@
* this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
* authorization lists must be rendered permanently unusable. Keys without
* Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
- *
- * @return error See the ErrorCode enum.
*/
void deleteAllKeys();
@@ -523,28 +527,27 @@
/**
* Begins a cryptographic operation using the specified key. If all is well, begin() must
- * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls
- * to update(), finish() or abort().
+ * return ErrorCode::OK and create an IKeyMintOperation handle which will be used to perform
+ * the cryptographic operation.
*
- * It is critical that each call to begin() be paired with a subsequent call to finish() or
- * abort(), to allow the IKeyMintDevice implementation to clean up any internal operation
- * state. The caller's failure to do this may leak internal state space or other internal
- * resources and may eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it
- * runs out of space for operations. Any result other than ErrorCode::OK from begin(), update()
- * or finish() implicitly aborts the operation, in which case abort() need not be called (and
- * must return ErrorCode::INVALID_OPERATION_HANDLE if called). IKeyMintDevice implementations
- * must support 32 concurrent operations.
+ * It is critical that each successful call to begin() be paired with a subsequent call to
+ * finish() or abort() on the resulting IKeyMintOperation, to allow the IKeyMintDevice
+ * implementation to clean up any internal operation state. The caller's failure to do this may
+ * leak internal state space or other internal resources and may eventually cause begin() to
+ * return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space for operations. Any result
+ * other than ErrorCode::OK from begin() will not return an IKeyMintOperation (in which case
+ * calling finish() or abort() is neither possible nor necessary). IKeyMintDevice
+ * implementations must support 32 concurrent operations.
*
* If Tag::APPLICATION_ID or Tag::APPLICATION_DATA were specified during key generation or
* import, calls to begin must include those tags with the originally-specified values in the
- * inParams argument to this method. If not, begin() must return ErrorCode::INVALID_KEY_BLOB.
+ * params argument to this method. If not, begin() must return ErrorCode::INVALID_KEY_BLOB.
*
* == Authorization Enforcement ==
*
* The following key authorization parameters must be enforced by the IKeyMintDevice secure
* environment if the tags were returned in the "hardwareEnforced" list in the
- * KeyCharacteristics. Public key operations, meaning KeyPurpose::ENCRYPT and
- * KeyPurpose::VERIFY must be allowed to succeed even if authorization requirements are not met.
+ * KeyCharacteristics.
*
* -- All Key Types --
*
@@ -573,9 +576,9 @@
*
* o Tag::USER_SECURE_ID must be enforced by this method if and only if the key also has
* Tag::AUTH_TIMEOUT (if it does not have Tag::AUTH_TIMEOUT, the Tag::USER_SECURE_ID
- * requirement must be enforced by update() and finish()). If the key has both, then this
- * method must receive a non-empty HardwareAuthToken in the authToken argument. For the auth
- * token to be valid, all of the following have to be true:
+ * requirement must be enforced by updateAad(), update() and finish()). If the key has both,
+ * then this method must receive a non-empty HardwareAuthToken in the authToken argument. For
+ * the auth token to be valid, all of the following have to be true:
*
* o The HMAC field must validate correctly.
*
@@ -602,32 +605,30 @@
*
* -- RSA Keys --
*
- * All RSA key operations must specify exactly one padding mode in inParams. If unspecified or
+ * All RSA key operations must specify exactly one padding mode in params. If unspecified or
* specified more than once, the begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
*
- * RSA signing and verification operations need a digest, as do RSA encryption and decryption
- * operations with OAEP padding mode. For those cases, the caller must specify exactly one
- * digest in inParams. If unspecified or specified more than once, begin() must return
+ * RSA signing operations need a digest, as do RSA encryption and decryption operations with
+ * OAEP padding mode. For those cases, the caller must specify exactly one digest in params.
+ * If unspecified or specified more than once, begin() must return
* ErrorCode::UNSUPPORTED_DIGEST.
*
* Private key operations (KeyPurpose::DECRYPT and KeyPurpose::SIGN) need authorization of
* digest and padding, which means that the key authorizations need to contain the specified
* values. If not, begin() must return ErrorCode::INCOMPATIBLE_DIGEST or
- * ErrorCode::INCOMPATIBLE_PADDING, as appropriate. Public key operations (KeyPurpose::ENCRYPT
- * and KeyPurpose::VERIFY) are permitted with unauthorized digest or padding modes.
+ * ErrorCode::INCOMPATIBLE_PADDING_MODE, as appropriate.
*
* With the exception of PaddingMode::NONE, all RSA padding modes are applicable only to certain
* purposes. Specifically, PaddingMode::RSA_PKCS1_1_5_SIGN and PaddingMode::RSA_PSS only
- * support signing and verification, while PaddingMode::RSA_PKCS1_1_5_ENCRYPT and
- * PaddingMode::RSA_OAEP only support encryption and decryption. begin() must return
- * ErrorCode::UNSUPPORTED_PADDING_MODE if the specified mode does not support the specified
- * purpose.
+ * support signing, while PaddingMode::RSA_PKCS1_1_5_ENCRYPT and PaddingMode::RSA_OAEP only
+ * support encryption and decryption. begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE
+ * if the specified mode does not support the specified purpose.
*
* There are some important interactions between padding modes and digests:
*
- * o PaddingMode::NONE indicates that a "raw" RSA operation is performed. If signing or
- * verifying, Digest::NONE is specified for the digest. No digest is necessary for unpadded
- * encryption or decryption.
+ * o PaddingMode::NONE indicates that a "raw" RSA operation is performed. If signing,
+ * Digest::NONE is specified for the digest. No digest is necessary for unpadded encryption
+ * or decryption.
*
* o PaddingMode::RSA_PKCS1_1_5_SIGN padding requires a digest. The digest may be Digest::NONE,
* in which case the KeyMint implementation cannot build a proper PKCS#1 v1.5 signature
@@ -639,37 +640,37 @@
*
* o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
*
- * o PaddingMode::RSA_PSS padding requires a digest, which may not be Digest::NONE. If
- * Digest::NONE is specified, the begin() must return ErrorCode::INCOMPATIBLE_DIGEST. In
- * addition, the size of the RSA key must be at least 2 + D bytes larger than the output size
- * of the digest, where D is the size of the digest, in bytes. Otherwise begin() must
- * return ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D.
+ * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the padding values
+ * in the key authorizations, and which may not be Digest::NONE. begin() must return
+ * ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. In addition, the size of the RSA
+ * key must be at least 2 + D bytes larger than the output size of the digest, where D is the
+ * size of the digest, in bytes. Otherwise begin() must return
+ * ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D.
*
- * o PaddingMode::RSA_OAEP padding requires a digest, which may not be Digest::NONE. If
- * Digest::NONE is specified, begin() must return ErrorCode::INCOMPATIBLE_DIGEST. The OAEP
- * mask generation function must be MGF1 and the MGF1 digest must be SHA1, regardless of the
- * OAEP digest specified.
+ * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the padding values
+ * in the key authorizations, and which may not be Digest::NONE. begin() must return
+ * ErrorCode::INCOMPATIBLE_DIGEST if this is not the case. RSA_OAEP padding also requires an
+ * MGF1 digest, specified with Tag::RSA_OAEP_MGF_DIGEST, which must match one of the MGF1
+ * padding values in the key authorizations and which may not be Digest::NONE. begin() must
+ * return ErrorCode::INCOMPATIBLE_MGF_DIGEST if this is not the case. The OAEP mask generation
+ * function must be MGF1.
*
* -- EC Keys --
*
- * EC key operations must specify exactly one padding mode in inParams. If unspecified or
- * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
- *
* Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
* means that the key authorizations must contain the specified values. If not, begin() must
- * return ErrorCode::INCOMPATIBLE_DIGEST. Public key operations (KeyPurpose::VERIFY) are
- * permitted with unauthorized digest or padding.
+ * return ErrorCode::INCOMPATIBLE_DIGEST.
*
* -- AES Keys --
*
* AES key operations must specify exactly one block mode (Tag::BLOCK_MODE) and one padding mode
- * (Tag::PADDING) in inParams. If either value is unspecified or specified more than once,
+ * (Tag::PADDING) in params. If either value is unspecified or specified more than once,
* begin() must return ErrorCode::UNSUPPORTED_BLOCK_MODE or
* ErrorCode::UNSUPPORTED_PADDING_MODE. The specified modes must be authorized by the key,
* otherwise begin() must return ErrorCode::INCOMPATIBLE_BLOCK_MODE or
* ErrorCode::INCOMPATIBLE_PADDING_MODE.
*
- * If the block mode is BlockMode::GCM, inParams must specify Tag::MAC_LENGTH, and the specified
+ * If the block mode is BlockMode::GCM, params must specify Tag::MAC_LENGTH, and the specified
* value must be a multiple of 8 that is not greater than 128 or less than the value of
* Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than 128 or
* non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For values less
@@ -682,48 +683,66 @@
*
* If the block mode is BlockMode::CBC, BlockMode::CTR, or BlockMode::GCM, an initialization
* vector or nonce is required. In most cases, callers shouldn't provide an IV or nonce and the
- * IKeyMintDevice implementation must generate a random IV or nonce and return it via
- * Tag::NONCE in outParams. CBC and CTR IVs are 16 bytes. GCM nonces are 12 bytes. If the key
+ * IKeyMintDevice implementation must generate a random IV or nonce and return it via Tag::NONCE
+ * in outParams. CBC and CTR IVs are 16 bytes. GCM nonces are 12 bytes. If the key
* authorizations contain Tag::CALLER_NONCE, then the caller may provide an IV/nonce with
- * Tag::NONCE in inParams. If a nonce is provided when Tag::CALLER_NONCE is not authorized,
+ * Tag::NONCE in params, which must be of the correct size (if not, return
+ * ErrorCode::INVALID_NONCE). If a nonce is provided when Tag::CALLER_NONCE is not authorized,
* begin() must return ErrorCode::CALLER_NONCE_PROHIBITED. If a nonce is not provided when
- * Tag::CALLER_NONCE is authorized, IKeyMintDevice msut generate a random IV/nonce.
+ * Tag::CALLER_NONCE is authorized, IKeyMintDevice must generate a random IV/nonce.
+ *
+ * -- 3DES Keys --
+ *
+ * 3DES key operations must specify exactly one block mode (Tag::BLOCK_MODE) and one padding
+ * mode (Tag::PADDING) in params. If either value is unspecified or specified more than once,
+ * begin() must return ErrorCode::UNSUPPORTED_BLOCK_MODE or
+ * ErrorCode::UNSUPPORTED_PADDING_MODE. The specified modes must be authorized by the key,
+ * otherwise begin() must return ErrorCode::INCOMPATIBLE_BLOCK_MODE or
+ * ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * If the block mode is BlockMode::CBC, an initialization vector or nonce is required. In most
+ * cases, callers shouldn't provide an IV or nonce and the IKeyMintDevice implementation must
+ * generate a random IV or nonce and return it via Tag::NONCE in outParams. CBC IVs are 8
+ * bytes. If the key authorizations contain Tag::CALLER_NONCE, then the caller may provide an
+ * IV/nonce with Tag::NONCE in params, which must be of the correct size (if not, return
+ * ErrorCode::INVALID_NONCE). If a nonce is provided when Tag::CALLER_NONCE is not authorized,
+ * begin() must return ErrorCode::CALLER_NONCE_PROHIBITED. If a nonce is not provided when
+ * Tag::CALLER_NONCE is authorized, IKeyMintDevice must generate a random IV/nonce.
+ *
*
* -- HMAC keys --
*
- * HMAC key operations must specify Tag::MAC_LENGTH in inParams. The specified value must be a
+ * HMAC key operations must specify Tag::MAC_LENGTH in params. The specified value must be a
* multiple of 8 that is not greater than the digest length or less than the value of
* Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than the digest
* length or non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For
* values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH.
*
- * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT,
- * KeyPurpose::DECRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY, or KeyPurpose::AGREE_KEY.
- * Note that for AEAD modes, encryption and decryption imply signing and verification,
- * respectively, but must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+ * @param purpose The purpose of the operation, one of KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT,
+ * KeyPurpose::SIGN, KeyPurpose::VERIFY, or KeyPurpose::AGREE_KEY. Note that for AEAD
+ * modes, encryption and decryption imply signing and verification, respectively, but
+ * must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
*
- * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey(). The key
+ * @param keyBlob The opaque key descriptor returned by generateKey() or importKey(). The key
* must have a purpose compatible with purpose and all of its usage requirements must be
* satisfied, or begin() must return an appropriate error code (see above).
*
- * @param inParams Additional parameters for the operation. If Tag::APPLICATION_ID or
+ * @param params Additional parameters for the operation. If Tag::APPLICATION_ID or
* Tag::APPLICATION_DATA were provided during generation, they must be provided here, or
* the operation must fail with ErrorCode::INVALID_KEY_BLOB. For operations that require
- * a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may
+ * a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, params may
* contain a tag Tag::NONCE. If Tag::NONCE is provided for a key without
* Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
*
- * @param inAuthToken Authentication token. Callers that provide no token must set all numeric
- * fields to zero and the MAC must be an empty vector. TODO: make this field nullable.
- * b/173483024.
+ * @param authToken Authentication token.
*
* @return BeginResult as output, which contains the challenge, KeyParameters which haves
* additional data from the operation initialization, notably to return the IV or nonce
* from operations that generate an IV or nonce, and IKeyMintOperation object pointer
- * which is used to perform update(), finish() or abort() operations.
+ * which is used to perform updateAad(), update(), finish() or abort() operations.
*/
BeginResult begin(in KeyPurpose purpose, in byte[] keyBlob, in KeyParameter[] params,
- in HardwareAuthToken authToken);
+ in @nullable HardwareAuthToken authToken);
/**
* Called by client to notify the IKeyMintDevice that the device is now locked, and keys with
@@ -737,7 +756,7 @@
* Note that the IKeyMintDevice UNLOCKED_DEVICE_REQUIRED semantics are slightly different from
* the UNLOCKED_DEVICE_REQUIRED semantics enforced by keystore. Keystore handles device locking
* on a per-user basis. Because auth tokens do not contain an Android user ID, it's not
- * possible to replicate the keystore enformcement logic in IKeyMintDevice. So from the
+ * possible to replicate the keystore enforcement logic in IKeyMintDevice. So from the
* IKeyMintDevice perspective, any user unlock unlocks all UNLOCKED_DEVICE_REQUIRED keys.
* Keystore will continue enforcing the per-user device locking.
*
@@ -783,18 +802,4 @@
* place of the input storageKeyBlob
*/
byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
-
- /**
- * Called by the client to perform a KeyMint operation.
- *
- * This method is added primarily as a placeholder. Details will be fleshed before the KeyMint
- * V1 interface is frozen. Until then, implementations must return ErrorCode::UNIMPLEMENTED.
- *
- * @param request is an encrypted buffer containing a description of the operation the client
- * wishes to perform. Structure, content and encryption are TBD.
- *
- * @return an encrypted buffer containing the result of the operation. Structure, content and
- * encryption are TBD.
- */
- byte[] performOperation(in byte[] request);
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index d2a993f..aa7b492 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -31,12 +31,12 @@
* update() is called. If updateAad() is called after update(), it must return
* ErrorCode::INVALID_TAG.
*
- * If operation is in an invalid state (was aborted or had an error) update() must return
+ * If the operation is in an invalid state (was aborted or had an error) update() must return
* ErrorCode::INVALID_OPERATION_HANDLE.
*
* If this method returns an error code other than ErrorCode::OK, the operation is aborted and
- * the operation handle must be invalidated. Any future use of the handle, with this method,
- * finish, or abort, must return ErrorCode::INVALID_OPERATION_HANDLE.
+ * the operation handle must be invalidated. Any future use of this object must return
+ * ErrorCode::INVALID_OPERATION_HANDLE.
*
* == Authorization Enforcement ==
*
@@ -58,9 +58,10 @@
*
* o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
*
- * o The challenge field in the auth token must contain the operationHandle
+ * o The challenge field in the auth token must contain the value returned from
+ * IKeyMintDevice::begin(), given by the challenge field of the BeginResult structure.
*
- * If any of these conditions are not met, update() must return
+ * If any of these conditions are not met, updateAad() must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
*
* The caller must provide the auth token on every call to updateAad(), update() and finish().
@@ -74,7 +75,7 @@
*
* @param input Additional Authentication Data to be processed.
*
- * @param authToken Authentication token. Can be nullable if not provided.
+ * @param authToken Authentication token, if provided.
*
* @param timeStampToken timestamp token, certifies the freshness of an auth token in case
* the security domain of this KeyMint instance has a different clock than the
@@ -93,18 +94,9 @@
* If operation is in an invalid state (was aborted or had an error) update() must return
* ErrorCode::INVALID_OPERATION_HANDLE.
*
- * To provide more flexibility for buffer handling, implementations of this method have the
- * option of consuming less data than was provided. The caller is responsible for looping to
- * feed the rest of the data in subsequent calls. The amount of input consumed must be returned
- * in the inputConsumed parameter. Implementations must always consume at least one byte,
- * unless the operation cannot accept any more; if more than zero bytes are provided and zero
- * bytes are consumed, callers must consider this an error and abort the operation.
- * TODO(seleneh) update the code to always consume alll the input data. b/168665179.
- *
- * Implementations may also choose how much data to return, as a result of the update. This is
- * only relevant for encryption and decryption operations, because signing and verification
- * return no data until finish. It is recommended to return data as early as possible, rather
- * than buffer it.
+ * Implementations may choose how much data to return as a result of the update. This is
+ * only relevant for encryption and decryption operations, because signing returns no data
+ * until finish. It is recommended to return data as early as possible, rather than buffer it.
*
* If this method returns an error code other than ErrorCode::OK, the operation is aborted and
* the operation handle must be invalidated. Any future use of the handle, with this method,
@@ -112,8 +104,8 @@
*
* == Authorization Enforcement ==
*
- * Key authorization enforcement is performed primarily in begin(). The one exception is the
- * case where the key has:
+ * Key authorization enforcement is performed primarily in IKeyMintDevice::begin(). The one
+ * exception is the case where the key has:
*
* o One or more Tag::USER_SECURE_IDs, and
*
@@ -130,7 +122,8 @@
*
* o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
*
- * o The challenge field in the auth token must contain the operationHandle
+ * o The challenge field in the auth token must contain the challenge value contained in the
+ * BeginResult returned from IKeyMintDevice::begin().
*
* If any of these conditions are not met, update() must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
@@ -139,22 +132,20 @@
*
* -- RSA keys --
*
- * For signing and verification operations with Digest::NONE, this method must accept the entire
- * block to be signed or verified in a single update. It may not consume only a portion of the
- * block in these cases. However, the caller may choose to provide the data in multiple
- * updates, and update() must accept the data this way as well. If the caller provides more
- * data to sign than can be used (length of data exceeds RSA key size), update() must return
- * ErrorCode::INVALID_INPUT_LENGTH.
+ * For signing operations with Digest::NONE, this method must accept the entire block to be
+ * signed in a single update. It may not consume only a portion of the block in these cases.
+ * However, the caller may choose to provide the data in multiple updates, and update() must
+ * accept the data this way as well. If the caller provides more data to sign than can be used
+ * (length of data exceeds RSA key size), update() must return ErrorCode::INVALID_INPUT_LENGTH.
*
* -- ECDSA keys --
*
- * For signing and verification operations with Digest::NONE, this method must accept the entire
- * block to be signed or verified in a single update. This method may not consume only a
- * portion of the block. However, the caller may choose to provide the data in multiple updates
- * and update() must accept the data this way as well. If the caller provides more data to sign
- * than can be used, the data is silently truncated. (This differs from the handling of excess
- * data provided in similar RSA operations. The reason for this is compatibility with legacy
- * clients.)
+ * For signing operations with Digest::NONE, this method must accept the entire block to be
+ * signed in a single update. This method may not consume only a portion of the block.
+ * However, the caller may choose to provide the data in multiple updates and update() must
+ * accept the data this way as well. If the caller provides more data to sign than can be used,
+ * the data is silently truncated. (This differs from the handling of excess data provided in
+ * similar RSA operations. The reason for this is compatibility with legacy clients.)
*
* -- AES keys --
*
@@ -182,7 +173,7 @@
in @nullable TimeStampToken timeStampToken);
/**
- * Finalizes a cryptographic operation begun with begin() and invalidates operation.
+ * Finalizes a cryptographic operation begun with begin() and invalidates the operation.
*
* This method is the last one called in an operation, so all processed data must be returned.
*
@@ -190,8 +181,7 @@
* Any future use of the operation, with finish(), update(), or abort(), must return
* ErrorCode::INVALID_OPERATION_HANDLE.
*
- * Signing operations return the signature as the output. Verification operations accept the
- * signature in the signature parameter, and return no output.
+ * Signing operations return the signature as the output.
*
* == Authorization enforcement ==
*
@@ -230,44 +220,35 @@
* Some additional requirements, depending on the padding mode:
*
* o PaddingMode::NONE. For unpadded signing and encryption operations, if the provided data is
- * shorter than the key, the data must be zero-padded on the left before
- * signing/encryption. If the data is the same length as the key, but numerically larger,
- * finish() must return ErrorCode::INVALID_ARGUMENT. For verification and decryption
- * operations, the data must be exactly as long as the key. Otherwise, return
- * ErrorCode::INVALID_INPUT_LENGTH.
+ * shorter than the key, the data must be zero-padded on the left before signing/encryption.
+ * If the data is the same length as the key, but numerically larger, finish() must return
+ * ErrorCode::INVALID_ARGUMENT. For decryption operations, the data must be exactly as long
+ * as the key. Otherwise, return ErrorCode::INVALID_INPUT_LENGTH.
*
* o PaddingMode::RSA_PSS. For PSS-padded signature operations, the PSS salt length must match
- * the size of the PSS digest selected. The digest specified with Tag::DIGEST in inputParams
+ * the size of the PSS digest selected. The digest specified with Tag::DIGEST in params
* on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask
* generation function and SHA1 must be used as the MGF1 digest algorithm.
*
- * o PaddingMode::RSA_OAEP. The digest specified with Tag::DIGEST in inputParams on begin is
- * used as the OAEP digest algorithm, MGF1 must be used as the mask generation function and
- * and SHA1 must be used as the MGF1 digest algorithm.
- *
* -- ECDSA keys --
*
- * If the data provided for unpadded signing or verification is too long, truncate it.
+ * If the data provided for undigested signing is too long, truncate it.
*
* -- AES keys --
*
* Some additional conditions, depending on block mode:
*
* o BlockMode::ECB or BlockMode::CBC. If padding is PaddingMode::NONE and the data length is
- * not a multiple of the AES block size, finish() must return
- * ErrorCode::INVALID_INPUT_LENGTH. If padding is PaddingMode::PKCS7, pad the data per the
- * PKCS#7 specification, including adding an additional padding block if the data is a multiple
- * of the block length.
+ * not a multiple of the AES block size, finish() must return
+ * ErrorCode::INVALID_INPUT_LENGTH. If padding is PaddingMode::PKCS7, pad the data per the
+ * PKCS#7 specification, including adding an additional padding block if the data is a
+ * multiple of the block length.
*
* o BlockMode::GCM. During encryption, after processing all plaintext, compute the tag
* (Tag::MAC_LENGTH bytes) and append it to the returned ciphertext. During decryption,
* process the last Tag::MAC_LENGTH bytes as the tag. If tag verification fails, finish()
* must return ErrorCode::VERIFICATION_FAILED.
*
- * TODO: update() will need to be refactored into 2 function. b/168665179.
- *
- * @param inParams Additional parameters for the operation.
- *
* @param input Data to be processed, per the parameters established in the call to begin().
* finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH.
*
@@ -281,11 +262,9 @@
* token.
*
* @param confirmationToken is the confirmation token required by keys with
- * Tag::TRUSTED_CONFIRMATION_REQUIRED.
+ * Tag::TRUSTED_CONFIRMATION_REQUIRED.
*
* @return The output data, if any.
- *
- * @return outParams Any output parameters generated by finish().
*/
byte[] finish(in @nullable byte[] input, in @nullable byte[] signature,
in @nullable HardwareAuthToken authToken,
@@ -293,13 +272,10 @@
in @nullable byte[] confirmationToken);
/**
- * Aborts a cryptographic operation begun with begin(), freeing all internal resources. If an
- * operation was finalized, calling update, finish, or abort yields
- * ErrorCode::INVALID_OPERATION_HANDLE. An operation is finalized if finish or abort was
- * called on it, or if update returned an ErrorCode.
- *
- * @param operationHandle The operation handle returned by begin(). This handle must be
- * invalid when abort() returns.
+ * Aborts a cryptographic operation begun with IKeyMintDevice::begin(), freeing all internal
+ * resources. If an operation was finalized, calling updateAad, update, finish, or abort yields
+ * ErrorCode::INVALID_OPERATION_HANDLE. An operation is finalized if finish or abort was called
+ * on it, or if updateAad or update returned an ErrorCode.
*
* @return error See the ErrorCode enum in ErrorCode.aidl.
*/
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 1ae6762..04d91d0 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -19,6 +19,7 @@
import android.hardware.security.keymint.DeviceInfo;
import android.hardware.security.keymint.MacedPublicKey;
import android.hardware.security.keymint.ProtectedData;
+import android.hardware.security.keymint.RpcHardwareInfo;
/**
* An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
@@ -77,7 +78,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 appopriate solution for devices which haven't implemented
+ * hardware-bound key pair. This is an appropriate 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.
*
@@ -121,6 +122,12 @@
const int STATUS_INVALID_EEK = 5;
/**
+ * @return info which contains information about the underlying IRemotelyProvisionedComponent
+ * hardware, such as version number, component name, author name, and supported curve.
+ */
+ RpcHardwareInfo getHardwareInfo();
+
+ /**
* generateKeyPair generates a new ECDSA P-256 key pair that can be certified. Note that this
* method only generates ECDSA P-256 key pairs, but the interface can be extended to add methods
* for generating keys for other algorithms, if necessary.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index f3c5477..f93dbba 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -58,31 +58,143 @@
* There are a few variations in what is contained in `certificateChain`, depending on whether
* the caller requested attestation, whether they provided an attestation key (via the
* `attestationKey` parameter of `generateKey()`, `importKey()` or `importWrappedKey()`), and in
- * the non-attestaion case, whether the key can self-sign.
+ * the non-attestation case, whether the key can self-sign.
*
- * 1. Attestation with factory key. If Tag::ATTESTATION_CHALLENGE is provided and the
- * `attestationKey` parameter on the generate/import call is null, the returned certificate
- * chain must contain an attestation certificate signed with a factory-provisioned
- * attestation key, and the full certificate chain for that factory-provisioned attestation
- * key.
+ * 1. Asymmetric key attestation with factory key. If Tag::ATTESTATION_CHALLENGE is provided
+ * and the `attestationKey` parameter on the generate/import call is null, the returned
+ * certificate chain must contain an attestation certificate signed with a factory-
+ * provisioned attestation key, and the full certificate chain for that factory-provisioned
+ * attestation key. Tag::ATTESTATION_APPLICATION_ID must also be provided when the
+ * ATTESTATION_CHALLENGE is provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be
+ * returned. KeyMint implementations are not required to support factory-provisioned
+ * attestation keys.
*
- * 2. Attestation with caller-provided key. If Tag::ATTESTATION_CHALLENGE is provided and the
- * `attestationKey` parameter on the generat/import call is non-null and contains the key
- * blob of a key with KeyPurpose::ATTEST_KEY, the returned certificate chain must contain
- * only an attestation certificate signed with the specified key. The caller must know the
- * certificate chain for the provided key.
+ * 2. Asymmetric key attestation with caller-provided key. If Tag::ATTESTATION_CHALLENGE is
+ * provided and the `attestationKey` parameter on the generate/import call is non-null and
+ * contains the key blob of a key with KeyPurpose::ATTEST_KEY, the returned certificate
+ * chain must contain only an attestation certificate signed with the specified key. The
+ * caller must know the certificate chain for the provided key. Tag::
+ * ATTESTATION_APPLICATION_ID must also be provided when the ATTESTATION_CHALLENGE is
+ * provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be returned.
*
- * 3. Non-attestation with signing key. If Tag::ATTESTATION_CHALLENGE is not provided and the
- * generated/imported key has KeyPurpose::SIGN, then the returned certificate chain must
- * contain only a single self-signed certificate with no attestation extension.
+ * 3. Asymmetric key non-attestation with signing key. If Tag::ATTESTATION_CHALLENGE is not
+ * provided and the generated/imported key has KeyPurpose::SIGN, then the returned
+ * certificate chain must contain only a single self-signed certificate with no attestation
+ * extension. Tag::ATTESTATION_APPLICATION_ID will be ignored if provided.
*
- * 4. Non-attestation with non-signing key. If TAG::ATTESTATION_CHALLENGE is not provided and
- * the generated/imported key does not have KeyPurpose::SIGN, then the returned certificate
- * chain must contain only a single certificate with an empty signature and no attestation
- * extension.
+ * 4. Asymmetric key non-attestation with non-signing key. If TAG::ATTESTATION_CHALLENGE is
+ * not provided and the generated/imported key does not have KeyPurpose::SIGN, then the
+ * returned certificate chain must contain only a single certificate with an empty signature
+ * and no attestation extension. Tag::ATTESTATION_APPLICATION_ID will be ignored if
+ * provided.
*
- * 5. Symmetric key. If the generated/imported key is symmetric, the certificate chain must be
- * empty.
+ * 5. Symmetric key. If the generated/imported key is symmetric, the certificate chain must
+ * return empty, any Tag::ATTESTATION_CHALLENGE or Tag::ATTESTATION_APPLICATION_ID inputs,
+ * if provided, are ignored.
+ *
+ * In all cases except the symmetric key, the contents of certificate chain must be DER-encoded
+ * X.509 certificates ordered such that each certificate is signed by the subsequent one, up to
+ * the root which must be self-signed (or contain a fake signature in the case of case 4 above).
+ * The first certificate in the chain signs the public key info of the newly-generated or
+ * newly-imported key pair. In the attestation cases (1 and 2 above), the first certificate
+ * must also satisfy some other requirements:
+ *
+ * o It must have the serial number provided in Tag::CERTIFICATE_SERIAL, or default to 1 if the
+ * tag is not provided.
+ *
+ * o It must have the subject provided in Tag::CERTIFICATE_SUBJECT, or default to CN="Android
+ * Keystore Key", if the tag is not provided.
+ *
+ * o It must contain the notBefore and notAfter date-times specified in
+ * Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER, respectively.
+ *
+ * o It must contain a Key Usage extension with:
+ *
+ * - the digitalSignature bit set iff the attested key has KeyPurpose::SIGN,
+ * - the dataEncipherment bit set iff the attested key has KeyPurpose::DECRYPT,
+ * - the keyEncipherment bit set iff the attested key has KeyPurpose::WRAP_KEY,
+ * - the keyAgreement bit set iff the attested key has KeyPurpose::AGREE_KEY, and
+ * - the keyCertSignBit set iff the attested key has KeyPurpose::ATTEST_KEY.
+ *
+ * o it must contain a KeyDescription attestation extension with OID 1.3.6.1.4.1.11129.2.1.17.
+ *
+ * The KeyDescription content is defined by the following ASN.1 schema, which is mostly a
+ * straightforward translation of the KeyMint tag/value parameter lists to ASN.1.
+ *
+ * KeyDescription ::= SEQUENCE {
+ * attestationVersion INTEGER, # Value 100
+ * attestationSecurityLevel SecurityLevel, # See below
+ * keyMintVersion INTEGER, # Value 100
+ * keymintSecurityLevel SecurityLevel, # See below
+ * attestationChallenge OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams
+ * uniqueId OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID
+ * softwareEnforced AuthorizationList, # See below
+ * hardwareEnforced AuthorizationList, # See below
+ * }
+ *
+ * SecurityLevel ::= ENUMERATED {
+ * Software (0),
+ * TrustedEnvironment (1),
+ * StrongBox (2),
+ * }
+ *
+ * RootOfTrust ::= SEQUENCE {
+ * verifiedBootKey OCTET_STRING,
+ * deviceLocked BOOLEAN,
+ * verifiedBootState VerifiedBootState,
+ * # verifiedBootHash must contain 32-byte value that represents the state of all binaries
+ * # or other components validated by verified boot. Updating any verified binary or
+ * # component must cause this value to change.
+ * verifiedBootHash OCTET_STRING,
+ * }
+ *
+ * VerifiedBootState ::= ENUMERATED {
+ * Verified (0),
+ * SelfSigned (1),
+ * Unverified (2),
+ * Failed (3),
+ * }
+ *
+ * AuthorizationList ::= SEQUENCE {
+ * 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,
+ * rollbackResistance [303] EXPLICIT NULL OPTIONAL,
+ * activeDateTime [400] EXPLICIT INTEGER OPTIONAL,
+ * originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL,
+ * usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL,
+ * userSecureId [502] EXPLICIT INTEGER OPTIONAL,
+ * noAuthRequired [503] EXPLICIT NULL OPTIONAL,
+ * userAuthType [504] EXPLICIT INTEGER OPTIONAL,
+ * authTimeout [505] EXPLICIT INTEGER OPTIONAL,
+ * allowWhileOnBody [506] EXPLICIT NULL OPTIONAL,
+ * trustedUserPresenceReq [507] EXPLICIT NULL OPTIONAL,
+ * trustedConfirmationReq [508] EXPLICIT NULL OPTIONAL,
+ * unlockedDeviceReq [509] EXPLICIT NULL OPTIONAL,
+ * creationDateTime [701] EXPLICIT INTEGER OPTIONAL,
+ * origin [702] EXPLICIT INTEGER OPTIONAL,
+ * rootOfTrust [704] EXPLICIT RootOfTrust OPTIONAL,
+ * osVersion [705] EXPLICIT INTEGER OPTIONAL,
+ * osPatchLevel [706] EXPLICIT INTEGER OPTIONAL,
+ * attestationApplicationId [709] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdBrand [710] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdDevice [711] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdProduct [712] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdSerial [713] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdImei [714] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdMeid [715] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdManufacturer [716] EXPLICIT OCTET_STRING OPTIONAL,
+ * attestationIdModel [717] EXPLICIT OCTET_STRING OPTIONAL,
+ * vendorPatchLevel [718] EXPLICIT INTEGER OPTIONAL,
+ * bootPatchLevel [719] EXPLICIT INTEGER OPTIONAL,
+ * }
*/
Certificate[] certificateChain;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl
index f896125..5840c6b 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyOrigin.aidl
@@ -20,7 +20,7 @@
* The origin of a key (or pair), i.e. where it was generated. Note that ORIGIN can be found in
* either the hardware-enforced or software-enforced list for a key, indicating whether the key is
* hardware or software-based. Specifically, a key with GENERATED in the hardware-enforced list
- * must be guaranteed never to have existed outide the secure hardware.
+ * must be guaranteed never to have existed outside the secure hardware.
* @hide
*/
@VintfStability
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index c874fc3..e141e55 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -23,10 +23,10 @@
@VintfStability
@Backing(type="int")
enum KeyPurpose {
- /* Usable with RSA, EC and AES keys. */
+ /* Usable with RSA, 3DES and AES keys. */
ENCRYPT = 0,
- /* Usable with RSA, EC and AES keys. */
+ /* Usable with RSA, 3DES and AES keys. */
DECRYPT = 1,
/* Usable with RSA, EC and HMAC keys. */
@@ -36,6 +36,7 @@
VERIFY = 3,
/* 4 is reserved */
+
/* Usable with wrapping keys. */
WRAP_KEY = 5,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..d297f87
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
+ * getHardwareInfo()
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RpcHardwareInfo {
+ const int CURVE_NONE = 0;
+ const int CURVE_P256 = 1;
+ const int CURVE_25519 = 2;
+
+ /**
+ * Implementation version of the remotely provisioned component 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.
+ */
+ int versionNumber;
+
+ /**
+ * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
+ * (organization name, not individual). This name is implementation defined, so it can be used
+ * to distinguish between different implementations from the same author.
+ */
+ @utf8InCpp String rpcAuthorName;
+
+ /**
+ * supportedEekCurve returns an int representing which curve is supported for validating
+ * signatures over the Endpoint Encryption Key certificate chain and for using the corresponding
+ * signed encryption key in ECDH. Only one curve should be supported, with preference for 25519
+ * if it's available. These values are defined as constants above.
+ *
+ * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
+ * to provide the correct information here, as the VTS tests will check to make certain that
+ * a passing implementation does not provide CURVE_NONE.
+ */
+ int supportedEekCurve = CURVE_NONE;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index cde1fc0..1e101ab 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -19,7 +19,7 @@
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 definations 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.
/**
@@ -59,7 +59,7 @@
ALGORITHM = (1 << 28) /* TagType:ENUM */ | 2,
/**
- * Tag::KEY_SIZE pecifies the size, in bits, of the key, measuring in the normal way for the
+ * Tag::KEY_SIZE specifies the size, in bits, of the key, measuring in the normal way for the
* key's algorithm. For example, for RSA keys, Tag::KEY_SIZE specifies the size of the public
* modulus. For AES keys it specifies the length of the secret key material. For 3DES keys it
* specifies the length of the key material, not counting parity bits (though parity bits must
@@ -75,9 +75,9 @@
* is only relevant to AES and 3DES keys. Possible values are defined by the BlockMode enum.
*
* This tag is repeatable for key generation/import. For AES and 3DES operations the caller
- * must specify a Tag::BLOCK_MODE in the additionalParams argument of begin(). If the mode is
- * missing or the specified mode is not in the modes specified for the key during
- * generation/import, the operation must fail with ErrorCode::INCOMPATIBLE_BLOCK_MODE.
+ * must specify a Tag::BLOCK_MODE in the params argument of begin(). If the mode is missing or
+ * the specified mode is not in the modes specified for the key during generation/import, the
+ * operation must fail with ErrorCode::INCOMPATIBLE_BLOCK_MODE.
*
* Must be hardware-enforced.
*/
@@ -89,9 +89,9 @@
* values are defined by the Digest enum.
*
* This tag is repeatable for key generation/import. For signing and verification operations,
- * the caller must specify a digest in the additionalParams argument of begin(). If the digest
- * is missing or the specified digest is not in the digests associated with the key, the
- * operation must fail with ErrorCode::INCOMPATIBLE_DIGEST.
+ * the caller must specify a digest in the params argument of begin(). If the digest is missing
+ * or the specified digest is not in the digests associated with the key, the operation must
+ * fail with ErrorCode::INCOMPATIBLE_DIGEST.
*
* Must be hardware-enforced.
*/
@@ -145,7 +145,7 @@
* This value is the minimum MAC length, in bits. It must be a multiple of 8 bits. For HMAC
* keys, the value must be least 64 and no more than 512. For GCM keys, the value must be at
* least 96 and no more than 128. If the provided value violates these requirements,
- * generateKey() or importKey() must return ErrorCode::UNSUPPORTED_KEY_SIZE.
+ * generateKey() or importKey() must return ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH.
*
* Must be hardware-enforced.
*/
@@ -154,9 +154,8 @@
// Tag 9 reserved
/**
- * Tag::EC_CURVE specifies the elliptic curve. EC key generation requests may have
- * Tag:EC_CURVE, Tag::KEY_SIZE, or both. If both are provided and the size and curve do not
- * match, IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ * Tag::EC_CURVE specifies the elliptic curve. Possible values are defined in the EcCurve
+ * enumeration.
*
* Must be hardware-enforced.
*/
@@ -188,37 +187,19 @@
INCLUDE_UNIQUE_ID = (7 << 28) /* TagType:BOOL */ | 202,
/**
- * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with
- * RSA encryption/decryption with OAEP padding. If the key characteristics supports OAEP
- * and this tag is absent then SHA1 digest is selected by default for MGF1.
+ * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
+ * encryption/decryption with OAEP padding. Possible values are defined by the Digest enum.
*
- * This tag is repeatable for key generation/import. If this tag is present in the key
- * characteristics with one or more values from @4.0::Digest, then for RSA cipher
- * operations with OAEP Padding, the caller must specify a digest in the additionalParams
- * argument of begin operation. If this tag is missing or the specified digest is not in
- * the digests associated with the key then begin operation must fail with
- * ErrorCode::INCOMPATIBLE_MGF_DIGEST.
+ * This tag is repeatable for key generation/import. RSA cipher operations with OAEP padding
+ * must specify an MGF1 digest in the params argument of begin(). If this tag is missing or the
+ * specified digest is not in the MGF1 digests associated with the key then begin operation must
+ * fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST.
*
* Must be hardware-enforced.
*/
RSA_OAEP_MGF_DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 203,
- /**
- * TODO(seleneh) this tag needs to be deleted from all codes.
- *
- * Tag::BLOB_USAGE_REQUIREMENTS specifies the necessary system environment conditions for the
- * generated key to be used. Possible values are defined by the KeyBlobUsageRequirements enum.
- *
- * This tag is specified by the caller during key generation or import to require that the key
- * is usable in the specified condition. If the caller specifies Tag::BLOB_USAGE_REQUIREMENTS
- * with value KeyBlobUsageRequirements::STANDALONE the IKeyMintDevice must return a key blob
- * that can be used without file system support. This is critical for devices with encrypted
- * disks, where the file system may not be available until after a KeyMint key is used to
- * decrypt the disk.
- *
- * Must be hardware-enforced.
- */
- BLOB_USAGE_REQUIREMENTS = (1 << 28) /* TagType:ENUM */ | 301,
+ // Tag 301 reserved
/**
* Tag::BOOTLOADER_ONLY specifies only the bootloader can use the key.
@@ -241,7 +222,7 @@
* ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE. IKeyMintDevice implementations are not
* required to support rollback resistance.
*
- * Must be hardwared-enforced.
+ * Must be hardware-enforced.
*/
ROLLBACK_RESISTANCE = (7 << 28) /* TagType:BOOL */ | 303,
@@ -251,7 +232,7 @@
/**
* Keys tagged with EARLY_BOOT_ONLY may only be used during early boot, until
* IKeyMintDevice::earlyBootEnded() is called. Early boot keys may be created after
- * early boot. Early boot keys may not be imprted at all, if Tag::EARLY_BOOT_ONLY is
+ * early boot. Early boot keys may not be imported at all, if Tag::EARLY_BOOT_ONLY is
* provided to IKeyMintDevice::importKey, the import must fail with
* ErrorCode::INVALID_ARGUMENT.
*/
@@ -307,7 +288,7 @@
* with ErrorCode::KEY_RATE_LIMIT_EXCEEDED. This implies that the IKeyMintDevice must keep a
* table of use counters for keys with this tag. Because memory is often limited, this table
* may have a fixed maximum size and KeyMint may fail operations that attempt to use keys with
- * this tag when the table is full. The table must acommodate at least 8 in-use keys and
+ * this tag when the table is full. The table must accommodate at least 8 in-use keys and
* aggressively reuse table slots when key minimum-usage intervals expire. If an operation
* fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
*
@@ -327,7 +308,7 @@
* device is restarted. This implies that the IKeyMintDevice must keep a table of use
* counters for keys with this tag. Because KeyMint memory is often limited, this table can
* have a fixed maximum size and KeyMint can fail operations that attempt to use keys with
- * this tag when the table is full. The table needs to acommodate at least 8 keys. If an
+ * this tag when the table is full. The table needs to accommodate at least 8 keys. If an
* operation fails because the table is full, IKeyMintDevice must
* ErrorCode::TOO_MANY_OPERATIONS.
*
@@ -386,14 +367,14 @@
* key, and may only be used if the difference between the current time when begin() is called
* and the timestamp in the HardwareAuthToken is less than the value in Tag::AUTH_TIMEOUT * 1000
* (the multiplier is because Tag::AUTH_TIMEOUT is in seconds, but the HardwareAuthToken
- * timestamp is in milliseconds). Otherwise the IKeyMintDevice must returrn
+ * timestamp is in milliseconds). Otherwise the IKeyMintDevice must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
*
* If Tag::AUTH_TIMEOUT is not present, then the key is an "auth-per-operation" key. In this
* case, begin() must not require a HardwareAuthToken with appropriate contents. Instead,
* update() and finish() must receive a HardwareAuthToken with Tag::USER_SECURE_ID value in
* userId or authenticatorId fields, and the current operation's operation handle in the
- * challenge field. Otherwise the IKeyMintDevice must returrn
+ * challenge field. Otherwise the IKeyMintDevice must return
* ErrorCode::KEY_USER_NOT_AUTHENTICATED.
*
* This tag is repeatable. If repeated, and any one of the values matches the HardwareAuthToken
@@ -434,7 +415,7 @@
/**
* Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
* after user authentication. If
- * Tag::USER_SECURE_ID is present and this tag is not, then the key requies authentication for
+ * Tag::USER_SECURE_ID is present and this tag is not, then the key requires authentication for
* every usage (see begin() for the details of the authentication-per-operation flow).
*
* The value is a 32-bit integer specifying the time in seconds after a successful
@@ -504,7 +485,7 @@
* 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 ConfirmatinUI HAL.
+ * CONFIRMATION_TOKEN, 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
@@ -524,10 +505,10 @@
/**
* Tag::APPLICATION_ID. When provided to generateKey or importKey, this tag specifies data
- * that is necessary during all uses of the key. In particular, calls to exportKey() and
- * getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to
- * begin must provide this tag and the same associated data as part of the inParams set. If
- * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+ * that is necessary during all uses of the key. In particular, calls to exportKey() must
+ * provide the same value to the clientId parameter, and calls to begin() must provide this
+ * tag and the same associated data as part of the inParams set. If the correct data is not
+ * provided, the method must return ErrorCode::INVALID_KEY_BLOB.
*
* The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
@@ -550,7 +531,7 @@
* provide this tag and the same associated data as part of the inParams set. If the correct
* data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
*
- * The content of this tag msut be bound to the key cryptographically, meaning it must not be
+ * The content of this tag must be bound to the key cryptographically, meaning it must not be
* possible for an adversary who has access to all of the secure world secrets but does not have
* access to the tag content to decrypt the key without brute-forcing the tag content, which
* applications can prevent by specifying sufficiently high-entropy content.
@@ -561,10 +542,9 @@
/**
* Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
- * January 1, 1970. This tag is optional and informational only.
+ * January 1, 1970. This tag is optional and informational only, and not enforced by anything.
*
- * Tag::CREATED is informational only, and not enforced by anything. Must be in the
- * software-enforced list, if provided.
+ * Must be in the software-enforced list, if provided.
*/
CREATION_DATETIME = (6 << 28) /* TagType:DATE */ | 701,
@@ -593,8 +573,8 @@
* Tag::OS_VERSION specifies the system OS version with which the key may be used. This tag is
* never sent to the IKeyMintDevice, but is added to the hardware-enforced authorization list
* by the TA. Any attempt to use a key with a Tag::OS_VERSION value different from the
- * currently-running OS version must cause begin(), getKeyCharacteristics() or exportKey() to
- * return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
+ * currently-running OS version must cause begin() or exportKey() to return
+ * ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
*
* The value of the tag is an integer of the form MMmmss, where MM is the major version number,
* mm is the minor version number, and ss is the sub-minor version number. For example, for a
@@ -616,9 +596,8 @@
* Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
* This tag is never sent to the keyMint TA, but is added to the hardware-enforced
* authorization list by the TA. Any attempt to use a key with a Tag::OS_PATCHLEVEL value
- * different from the currently-running system patchlevel must cause begin(),
- * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See
- * upgradeKey() for details.
+ * different from the currently-running system patchlevel must cause begin() or
+ * exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
*
* The value of the tag is an integer of the form YYYYMM, where YYYY is the four-digit year of
* the last update and MM is the two-digit month of the last update. For example, for a key
@@ -650,10 +629,11 @@
* Tag::CREATION_DATETIME by 2592000000, dropping any remainder. T changes every 30 days
* (2592000000 = 30 * 24 * 60 * 60 * 1000).
*
- * C is the value of Tag::ATTESTATION_APPLICATION_ID that is provided to attestKey().
+ * C is the value of Tag::ATTESTATION_APPLICATION_ID that is provided to attested key
+ * generation/import operations.
*
- * R is 1 if Tag::RESET_SINCE_ID_ROTATION was provided to attestKey or 0 if the tag was not
- * provided.
+ * R is 1 if Tag::RESET_SINCE_ID_ROTATION was provided to attested key generation/import or 0
+ * if the tag was not provided.
*
* HBK is a unique hardware-bound secret known to the secure environment and never revealed
* by it. The secret must contain at least 128 bits of entropy and be unique to the
@@ -668,9 +648,9 @@
UNIQUE_ID = (9 << 28) /* TagType:BYTES */ | 707,
/**
- * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attestKey() method,
- * which must place the value in the KeyDescription SEQUENCE of the attestation extension. See
- * attestKey().
+ * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attested key
+ * generation/import methods, which must place the value in the KeyDescription SEQUENCE of the
+ * attestation extension.
*
* Must never appear in KeyCharacteristics.
*/
@@ -678,7 +658,7 @@
/**
* Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
- * only with attestKey().
+ * only with attested key generation/import operations.
*
* The content of Tag::ATTESTATION_APPLICATION_ID is a DER-encoded ASN.1 structure, with the
* following schema:
@@ -704,8 +684,8 @@
/**
* Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
- * Android, to attestKey(). This field must be set only when requesting attestation of the
- * device's identifiers.
+ * Android, to attested key generation/import operations. This field must be set only when
+ * requesting attestation of the device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -717,8 +697,8 @@
/**
* Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
- * Android, to attestKey(). This field must be set only when requesting attestation of the
- * device's identifiers.
+ * Android, to attested key generation/import operations. This field must be set only when
+ * requesting attestation of the device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -730,8 +710,8 @@
/**
* Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
- * in Android, to attestKey(). This field must be set only when requesting attestation of the
- * device's identifiers.
+ * in Android, to attested key generation/import operations. This field must be set only when
+ * requesting attestation of the device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -754,8 +734,9 @@
ATTESTATION_ID_SERIAL = (9 << 28) /* TagType:BYTES */ | 713,
/**
- * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attestKey().
- * This field must be set only when requesting attestation of the device's identifiers.
+ * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
+ * generation/import operations. This field must be set only when requesting attestation of the
+ * device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -766,8 +747,9 @@
ATTESTATION_ID_IMEI = (9 << 28) /* TagType:BYTES */ | 714,
/**
- * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attestKey().
- * This field must be set only when requesting attestation of the device's identifiers.
+ * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attested key
+ * generation/import operations. This field must be set only when requesting attestation of the
+ * device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -779,8 +761,8 @@
/**
* Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
- * Build.MANUFACTURER in Android, to attstKey(). This field must be set only when requesting
- * attestation of the device's identifiers.
+ * Build.MANUFACTURER in Android, to attested key generation/import operations. This field must
+ * be set only when requesting attestation of the device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -792,8 +774,8 @@
/**
* Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
- * Android, to attestKey(). This field must be set only when requesting attestation of the
- * device's identifiers.
+ * Android, to attested key generation/import operations. This field must be set only when
+ * requesting attestation of the device's identifiers.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -807,9 +789,8 @@
* Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
* be used. This tag is never sent to the keyMint TA, but is added to the hardware-enforced
* authorization list by the TA. Any attempt to use a key with a Tag::VENDOR_PATCHLEVEL value
- * different from the currently-running system patchlevel must cause begin(),
- * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See
- * upgradeKey() for details.
+ * different from the currently-running system patchlevel must cause begin() or
+ * exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
*
* The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
* the last update, MM is the two-digit month and DD is the two-digit day of the last
@@ -830,8 +811,8 @@
* key may be used. This tag is never sent to the keyMint TA, but is added to the
* hardware-enforced authorization list by the TA. Any attempt to use a key with a
* Tag::BOOT_PATCHLEVEL value different from the currently-running system patchlevel must
- * cause begin(), getKeyCharacteristics() or exportKey() to return
- * ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details.
+ * cause begin() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for
+ * details.
*
* The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
* the last update, MM is the two-digit month and DD is the two-digit day of the last
@@ -839,20 +820,20 @@
* the value would be 20180605. If the day is not known, 00 may be substituted.
*
* During each boot, the bootloader must provide the patch level of the boot image to the secure
- * envirionment (mechanism is implementation-defined).
+ * environment (mechanism is implementation-defined).
*
* Must be hardware-enforced.
*/
BOOT_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 719,
/**
- * DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attestKey(). 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.
+ * 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.
* SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and
* return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
*
@@ -935,33 +916,34 @@
CONFIRMATION_TOKEN = (9 << 28) /* TagType:BYTES */ | 1005,
/**
- * Tag::CERTIFICATE_SERIAL specifies the serial number to be assigned to the
- * attestation certificate to be generated for the given key. This parameter should only
- * be passed to keyMint in the attestation parameters during generateKey() and importKey().
+ * Tag::CERTIFICATE_SERIAL specifies the serial number to be assigned to the attestation
+ * certificate to be generated for the given key. This parameter should only be passed to
+ * 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,
/**
- * Tag::CERTIFICATE_SUBJECT the certificate subject. The value is a DER encoded X509 NAME.
- * This value is used when generating a self signed certificates. This tag may be specified
+ * Tag::CERTIFICATE_SUBJECT the certificate subject. The value is a DER encoded X509 NAME.
+ * This value is used when generating a self signed certificates. This tag may be specified
* during generateKey and importKey. If not provided the subject name shall default to
- * <TODO default subject here>.
+ * CN="Android Keystore Key".
*/
CERTIFICATE_SUBJECT = (9 << 28) /* TagType:BYTES */ | 1007,
/**
* Tag::CERTIFICATE_NOT_BEFORE the beginning of the validity of the certificate in UNIX epoch
- * time in seconds. This value is used when generating attestation or self signed certificates.
- * ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if this tag is
- * not provided to generateKey or importKey.
+ * time in seconds. This value is used when generating attestation or self signed 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,
/**
- * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch
- * time in seconds. This value is used when generating attestation or self signed certificates.
- * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey
- * or importKey.
+ * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
+ * seconds. This value is used when generating attestation or self signed certificates.
+ * 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,
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index ebdc9b7..230534c 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -33,7 +33,6 @@
"libkeymint",
"liblog",
"libpuresoftkeymasterdevice",
- "libremote_provisioner",
"libutils",
],
srcs: [
@@ -51,28 +50,3 @@
vendor: true,
src: "android.hardware.hardware_keystore.xml",
}
-
-cc_library {
- name: "libremote_provisioner",
- vendor_available: true,
- static_libs: [
- "libkeymint_remote_prov_support",
- ],
- shared_libs: [
- "android.hardware.security.keymint-V1-ndk_platform",
- "libbinder_ndk",
- "libcppbor_external",
- "libcppcose",
- "libcrypto",
- "libkeymaster_portable",
- "libkeymint",
- "liblog",
- "libpuresoftkeymasterdevice",
- ],
- export_include_dirs: [
- ".",
- ],
- srcs: [
- "RemotelyProvisionedComponent.cpp",
- ],
-}
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
deleted file mode 100644
index 5b02729..0000000
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RemotelyProvisionedComponent.h"
-
-#include <assert.h>
-#include <variant>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <KeyMintUtils.h>
-#include <cppcose/cppcose.h>
-#include <keymaster/keymaster_configuration.h>
-#include <remote_prov/remote_prov_utils.h>
-
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-
-namespace aidl::android::hardware::security::keymint {
-
-using ::std::string;
-using ::std::tuple;
-using ::std::unique_ptr;
-using ::std::variant;
-using ::std::vector;
-using bytevec = ::std::vector<uint8_t>;
-
-using namespace cppcose;
-using namespace keymaster;
-
-namespace {
-
-// Hard-coded set of acceptable public keys that can act as roots of EEK chains.
-inline const vector<bytevec> kAuthorizedEekRoots = {
- // TODO(drysdale): replace this random value with real root pubkey(s).
- {0x5c, 0xea, 0x4b, 0xd2, 0x31, 0x27, 0x15, 0x5e, 0x62, 0x94, 0x70,
- 0x53, 0x94, 0x43, 0x0f, 0x9a, 0x89, 0xd5, 0xc5, 0x0f, 0x82, 0x9b,
- 0xcd, 0x10, 0xe0, 0x79, 0xef, 0xf3, 0xfa, 0x40, 0xeb, 0x0a},
-};
-
-constexpr auto STATUS_FAILED = RemotelyProvisionedComponent::STATUS_FAILED;
-constexpr auto STATUS_INVALID_EEK = RemotelyProvisionedComponent::STATUS_INVALID_EEK;
-constexpr auto STATUS_INVALID_MAC = RemotelyProvisionedComponent::STATUS_INVALID_MAC;
-constexpr uint32_t kAffinePointLength = 32;
-struct AStatusDeleter {
- void operator()(AStatus* p) { AStatus_delete(p); }
-};
-
-// TODO(swillden): Remove the dependency on AStatus stuff. The COSE lib should use something like
-// StatusOr, but it shouldn't depend on AStatus.
-class Status {
- public:
- Status() {}
- Status(int32_t errCode, const std::string& errMsg)
- : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
- explicit Status(const std::string& errMsg)
- : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
- Status(AStatus* status) : status_(status) {}
- Status(Status&&) = default;
- Status(const Status&) = delete;
-
- operator ::ndk::ScopedAStatus() && { return ndk::ScopedAStatus(status_.release()); }
-
- bool isOk() { return !status_; }
-
- // Don't call getMessage() unless isOk() returns false;
- const char* getMessage() const { return AStatus_getMessage(status_.get()); }
-
- private:
- std::unique_ptr<AStatus, AStatusDeleter> status_;
-};
-
-template <typename T>
-class StatusOr {
- public:
- StatusOr(AStatus* status) : status_(status) {}
- StatusOr(Status status) : status_(std::move(status)) {}
- StatusOr(T val) : value_(std::move(val)) {}
-
- bool isOk() { return status_.isOk(); }
-
- T* operator->() & {
- assert(isOk());
- return &value_.value();
- }
- T& operator*() & {
- assert(isOk());
- return value_.value();
- }
- T&& operator*() && {
- assert(isOk());
- return std::move(value_).value();
- }
-
- const char* getMessage() const {
- assert(!isOk());
- return status_.getMessage();
- }
-
- Status moveError() {
- assert(!isOk());
- return std::move(status_);
- }
-
- T moveValue() { return std::move(value_).value(); }
-
- private:
- Status status_;
- std::optional<T> value_;
-};
-
-StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtractEekPubAndId(
- bool testMode, const bytevec& endpointEncryptionCertChain) {
- auto [item, newPos, errMsg] = cppbor::parse(endpointEncryptionCertChain);
-
- if (!item || !item->asArray()) {
- return Status("Error parsing EEK chain" + errMsg);
- }
-
- const cppbor::Array* certArr = item->asArray();
- bytevec lastPubKey;
- for (int i = 0; i < certArr->size(); ++i) {
- auto cosePubKey = verifyAndParseCoseSign1(testMode, certArr->get(i)->asArray(),
- std::move(lastPubKey), bytevec{} /* AAD */);
- if (!cosePubKey) {
- return Status(STATUS_INVALID_EEK,
- "Failed to validate EEK chain: " + cosePubKey.moveMessage());
- }
- lastPubKey = *std::move(cosePubKey);
-
- // In prod mode the first pubkey should match a well-known Google public key.
- if (!testMode && i == 0 &&
- std::find(kAuthorizedEekRoots.begin(), kAuthorizedEekRoots.end(), lastPubKey) ==
- kAuthorizedEekRoots.end()) {
- return Status(STATUS_INVALID_EEK, "Unrecognized root of EEK chain");
- }
- }
-
- auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
- if (!eek) return Status(STATUS_INVALID_EEK, "Failed to get EEK: " + eek.moveMessage());
-
- return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
- eek->getBstrValue(CoseKey::KEY_ID).value());
-}
-
-StatusOr<bytevec /* pubkeys */> validateAndExtractPubkeys(bool testMode,
- const vector<MacedPublicKey>& keysToSign,
- const bytevec& macKey) {
- auto pubKeysToMac = cppbor::Array();
- for (auto& keyToSign : keysToSign) {
- auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(keyToSign.macedKey);
- if (!macedKeyItem || !macedKeyItem->asArray() ||
- macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
- return Status("Invalid COSE_Mac0 structure");
- }
-
- auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
- auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
- auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
- auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
- if (!protectedParms || !unprotectedParms || !payload || !tag) {
- return Status("Invalid COSE_Mac0 contents");
- }
-
- auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
- if (!protectedMap || !protectedMap->asMap()) {
- return Status("Invalid Mac0 protected: " + errMsg);
- }
- auto& algo = protectedMap->asMap()->get(ALGORITHM);
- if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
- return Status("Unsupported Mac0 algorithm");
- }
-
- auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
- if (!pubKey) return Status(pubKey.moveMessage());
-
- bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
- if (testMode && !testKey) {
- return Status(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST,
- "Production key in test request");
- } else if (!testMode && testKey) {
- return Status(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST,
- "Test key in production request");
- }
-
- auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
- if (!macTag) return Status(STATUS_INVALID_MAC, macTag.moveMessage());
- if (macTag->size() != tag->value().size() ||
- CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
- return Status(STATUS_INVALID_MAC, "MAC tag mismatch");
- }
-
- pubKeysToMac.add(pubKey->moveMap());
- }
-
- return pubKeysToMac.encode();
-}
-
-StatusOr<std::pair<bytevec, bytevec>> buildCosePublicKeyFromKmCert(
- const keymaster_blob_t* km_cert) {
- if (km_cert == nullptr) {
- return Status(STATUS_FAILED, "km_cert is a nullptr");
- }
- const uint8_t* temp = km_cert->data;
- X509* cert = d2i_X509(NULL, &temp, km_cert->data_length);
- if (cert == nullptr) {
- return Status(STATUS_FAILED, "d2i_X509 returned null when attempting to get the cert.");
- }
- EVP_PKEY* pubKey = X509_get_pubkey(cert);
- if (pubKey == nullptr) {
- return Status(STATUS_FAILED, "Boringssl failed to get the public key from the cert");
- }
- EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey);
- if (ecKey == nullptr) {
- return Status(STATUS_FAILED,
- "The key in the certificate returned from GenerateKey is not "
- "an EC key.");
- }
- const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey);
- BIGNUM x;
- BIGNUM y;
- BN_CTX* ctx = BN_CTX_new();
- if (ctx == nullptr) {
- return Status(STATUS_FAILED, "Memory allocation failure for BN_CTX");
- }
- if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, &x, &y,
- ctx)) {
- return Status(STATUS_FAILED, "Failed to get affine coordinates");
- }
- bytevec x_bytestring(kAffinePointLength);
- bytevec y_bytestring(kAffinePointLength);
- if (BN_bn2binpad(&x, x_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
- return Status(STATUS_FAILED, "Wrote incorrect number of bytes for x coordinate");
- }
- if (BN_bn2binpad(&y, y_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
- return Status(STATUS_FAILED, "Wrote incorrect number of bytes for y coordinate");
- }
- BN_CTX_free(ctx);
- return std::make_pair(x_bytestring, y_bytestring);
-}
-
-cppbor::Array buildCertReqRecipients(const bytevec& pubkey, const bytevec& kid) {
- return cppbor::Array() // Array of recipients
- .add(cppbor::Array() // Recipient
- .add(cppbor::Map() // Protected
- .add(ALGORITHM, ECDH_ES_HKDF_256)
- .canonicalize()
- .encode())
- .add(cppbor::Map() // Unprotected
- .add(COSE_KEY, cppbor::Map()
- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
- .add(CoseKey::CURVE, cppcose::X25519)
- .add(CoseKey::PUBKEY_X, pubkey)
- .canonicalize())
- .add(KEY_ID, kid)
- .canonicalize())
- .add(cppbor::Null())); // No ciphertext
-}
-
-static keymaster_key_param_t kKeyMintEcdsaP256Params[] = {
- Authorization(TAG_PURPOSE, KM_PURPOSE_ATTEST_KEY),
- Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC), Authorization(TAG_KEY_SIZE, 256),
- Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256),
- Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256), Authorization(TAG_NO_AUTH_REQUIRED),
- // The certificate generated by KM will be discarded, these values don't matter.
- Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)};
-
-} // namespace
-
-RemotelyProvisionedComponent::RemotelyProvisionedComponent(
- std::shared_ptr<keymint::AndroidKeyMintDevice> keymint) {
- std::tie(devicePrivKey_, bcc_) = generateBcc();
- impl_ = keymint->getKeymasterImpl();
-}
-
-RemotelyProvisionedComponent::~RemotelyProvisionedComponent() {}
-
-ScopedAStatus RemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool testMode,
- MacedPublicKey* macedPublicKey,
- bytevec* privateKeyHandle) {
- // TODO(jbires): The following should move from ->GenerateKey to ->GenerateRKPKey and everything
- // after the GenerateKey call should basically be moved into that new function call
- // as well once the issue with libcppbor in system/keymaster is sorted out
- GenerateKeyRequest request(impl_->message_version());
- request.key_description.Reinitialize(kKeyMintEcdsaP256Params,
- array_length(kKeyMintEcdsaP256Params));
- GenerateKeyResponse response(impl_->message_version());
- impl_->GenerateKey(request, &response);
- if (response.error != KM_ERROR_OK) {
- return km_utils::kmError2ScopedAStatus(response.error);
- }
-
- if (response.certificate_chain.entry_count != 1) {
- // Error: Need the single non-signed certificate with the public key in it.
- return Status(STATUS_FAILED,
- "Expected to receive a single certificate from GenerateKey. Instead got: " +
- std::to_string(response.certificate_chain.entry_count));
- }
- auto affineCoords = buildCosePublicKeyFromKmCert(response.certificate_chain.begin());
- if (!affineCoords.isOk()) return affineCoords.moveError();
- cppbor::Map cosePublicKeyMap = cppbor::Map()
- .add(CoseKey::KEY_TYPE, EC2)
- .add(CoseKey::ALGORITHM, ES256)
- .add(CoseKey::CURVE, cppcose::P256)
- .add(CoseKey::PUBKEY_X, affineCoords->first)
- .add(CoseKey::PUBKEY_Y, affineCoords->second);
- if (testMode) {
- cosePublicKeyMap.add(CoseKey::TEST_KEY, cppbor::Null());
- }
-
- bytevec cosePublicKey = cosePublicKeyMap.canonicalize().encode();
-
- auto macedKey = constructCoseMac0(testMode ? remote_prov::kTestMacKey : macKey_,
- {} /* externalAad */, cosePublicKey);
- if (!macedKey) return Status(macedKey.moveMessage());
-
- macedPublicKey->macedKey = macedKey->encode();
- *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest(
- bool testMode, const vector<MacedPublicKey>& keysToSign,
- const bytevec& endpointEncCertChain, const bytevec& challenge, DeviceInfo* deviceInfo,
- ProtectedData* protectedData, bytevec* keysToSignMac) {
- auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign,
- testMode ? remote_prov::kTestMacKey : macKey_);
- if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError();
-
- bytevec ephemeralMacKey = remote_prov::randomBytes(SHA256_DIGEST_LENGTH);
-
- auto pubKeysToSignMac = generateCoseMac0Mac(ephemeralMacKey, bytevec{}, *pubKeysToSign);
- if (!pubKeysToSignMac) return Status(pubKeysToSignMac.moveMessage());
- *keysToSignMac = *std::move(pubKeysToSignMac);
-
- bytevec devicePrivKey;
- cppbor::Array bcc;
- if (testMode) {
- std::tie(devicePrivKey, bcc) = generateBcc();
- } else {
- devicePrivKey = devicePrivKey_;
- bcc = bcc_.clone();
- }
-
- std::unique_ptr<cppbor::Map> deviceInfoMap = createDeviceInfo();
- deviceInfo->deviceInfo = deviceInfoMap->encode();
- auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */, //
- ephemeralMacKey /* Payload */,
- cppbor::Array() /* AAD */
- .add(challenge)
- .add(std::move(deviceInfoMap))
- .encode());
- if (!signedMac) return Status(signedMac.moveMessage());
-
- bytevec ephemeralPrivKey(X25519_PRIVATE_KEY_LEN);
- bytevec ephemeralPubKey(X25519_PUBLIC_VALUE_LEN);
- X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data());
-
- auto eek = validateAndExtractEekPubAndId(testMode, endpointEncCertChain);
- if (!eek.isOk()) return eek.moveError();
-
- auto sessionKey = x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first,
- true /* senderIsA */);
- if (!sessionKey) return Status(sessionKey.moveMessage());
-
- auto coseEncrypted =
- constructCoseEncrypt(*sessionKey, remote_prov::randomBytes(kAesGcmNonceLength),
- cppbor::Array() // payload
- .add(signedMac.moveValue())
- .add(std::move(bcc))
- .encode(),
- {}, // aad
- buildCertReqRecipients(ephemeralPubKey, eek->second));
-
- if (!coseEncrypted) return Status(coseEncrypted.moveMessage());
- protectedData->protectedData = coseEncrypted->encode();
-
- return ScopedAStatus::ok();
-}
-
-bytevec RemotelyProvisionedComponent::deriveBytesFromHbk(const string& context,
- size_t numBytes) const {
- bytevec fakeHbk(32, 0);
- bytevec result(numBytes);
-
- // TODO(swillden): Figure out if HKDF can fail. It doesn't seem like it should be able to,
- // but the function does return an error code.
- HKDF(result.data(), numBytes, //
- EVP_sha256(), //
- fakeHbk.data(), fakeHbk.size(), //
- nullptr /* salt */, 0 /* salt len */, //
- reinterpret_cast<const uint8_t*>(context.data()), context.size());
-
- return result;
-}
-
-std::unique_ptr<cppbor::Map> RemotelyProvisionedComponent::createDeviceInfo() const {
- auto result = std::make_unique<cppbor::Map>(cppbor::Map());
-
- // The following placeholders show how the DeviceInfo map would be populated.
- // result->add(cppbor::Tstr("brand"), cppbor::Tstr("Google"));
- // result->add(cppbor::Tstr("manufacturer"), cppbor::Tstr("Google"));
- // result->add(cppbor::Tstr("product"), cppbor::Tstr("Fake"));
- // result->add(cppbor::Tstr("model"), cppbor::Tstr("Imaginary"));
- // result->add(cppbor::Tstr("board"), cppbor::Tstr("Chess"));
- // result->add(cppbor::Tstr("vb_state"), cppbor::Tstr("orange"));
- // result->add(cppbor::Tstr("bootloader_state"), cppbor::Tstr("unlocked"));
- // result->add(cppbor::Tstr("os_version"), cppbor::Tstr("SC"));
- // result->add(cppbor::Tstr("system_patch_level"), cppbor::Uint(20210331));
- // result->add(cppbor::Tstr("boot_patch_level"), cppbor::Uint(20210331));
- // result->add(cppbor::Tstr("vendor_patch_level"), cppbor::Uint(20210331));
-
- result->canonicalize();
- return result;
-}
-
-std::pair<bytevec /* privKey */, cppbor::Array /* BCC */>
-RemotelyProvisionedComponent::generateBcc() {
- bytevec privKey(ED25519_PRIVATE_KEY_LEN);
- bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
-
- ED25519_keypair(pubKey.data(), privKey.data());
-
- auto coseKey = cppbor::Map()
- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
- .add(CoseKey::ALGORITHM, EDDSA)
- .add(CoseKey::CURVE, ED25519)
- .add(CoseKey::KEY_OPS, VERIFY)
- .add(CoseKey::PUBKEY_X, pubKey)
- .canonicalize()
- .encode();
- auto sign1Payload = cppbor::Map()
- .add(1 /* Issuer */, "Issuer")
- .add(2 /* Subject */, "Subject")
- .add(-4670552 /* Subject Pub Key */, coseKey)
- .add(-4670553 /* Key Usage (little-endian order) */,
- std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */)
- .canonicalize()
- .encode();
- auto coseSign1 = constructCoseSign1(privKey, /* signing key */
- cppbor::Map(), /* extra protected */
- sign1Payload, {} /* AAD */);
- assert(coseSign1);
-
- return {privKey, cppbor::Array().add(coseKey).add(coseSign1.moveValue())};
-}
-
-} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
deleted file mode 100644
index 8185e26..0000000
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <AndroidKeyMintDevice.h>
-#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
-#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
-#include <cppbor.h>
-#include <keymaster/UniquePtr.h>
-#include <keymaster/android_keymaster.h>
-
-namespace aidl::android::hardware::security::keymint {
-
-using ::ndk::ScopedAStatus;
-
-class RemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
- public:
- explicit RemotelyProvisionedComponent(std::shared_ptr<keymint::AndroidKeyMintDevice> keymint);
- virtual ~RemotelyProvisionedComponent();
-
- ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
- std::vector<uint8_t>* privateKeyHandle) override;
-
- ScopedAStatus generateCertificateRequest(bool testMode,
- const std::vector<MacedPublicKey>& keysToSign,
- const std::vector<uint8_t>& endpointEncCertChain,
- const std::vector<uint8_t>& challenge,
- DeviceInfo* deviceInfo, ProtectedData* protectedData,
- std::vector<uint8_t>* keysToSignMac) override;
-
- private:
- // TODO(swillden): Move these into an appropriate Context class.
- std::vector<uint8_t> deriveBytesFromHbk(const std::string& context, size_t numBytes) const;
- std::unique_ptr<cppbor::Map> createDeviceInfo() const;
- std::pair<std::vector<uint8_t>, cppbor::Array> generateBcc();
-
- std::vector<uint8_t> macKey_ = deriveBytesFromHbk("Key to MAC public keys", 32);
- std::vector<uint8_t> devicePrivKey_;
- cppbor::Array bcc_;
- std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
-};
-
-} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
index bcebbaf..8092e34 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -21,14 +21,13 @@
#include <android/binder_process.h>
#include <AndroidKeyMintDevice.h>
+#include <AndroidRemotelyProvisionedComponentDevice.h>
#include <AndroidSecureClock.h>
#include <AndroidSharedSecret.h>
#include <keymaster/soft_keymaster_logger.h>
-#include "RemotelyProvisionedComponent.h"
-
using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
-using aidl::android::hardware::security::keymint::RemotelyProvisionedComponent;
+using aidl::android::hardware::security::keymint::AndroidRemotelyProvisionedComponentDevice;
using aidl::android::hardware::security::keymint::SecurityLevel;
using aidl::android::hardware::security::secureclock::AndroidSecureClock;
using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;
@@ -56,7 +55,7 @@
// Add Shared Secret Service
addService<AndroidSharedSecret>(keyMint);
// Add Remotely Provisioned Component Service
- addService<RemotelyProvisionedComponent>(keyMint);
+ addService<AndroidRemotelyProvisionedComponentDevice>(keyMint);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index c1affa6..d5c45e2 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -31,6 +31,7 @@
],
srcs: [
"AttestKeyTest.cpp",
+ "DeviceUniqueAttestationTest.cpp",
"KeyMintTest.cpp",
],
shared_libs: [
@@ -43,6 +44,8 @@
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
+ "libcppcose_rkp",
+ "libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
],
test_suites: [
@@ -73,6 +76,9 @@
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
+ "libcppcose_rkp",
+ "libgmock_ndk",
+ "libkeymint_remote_prov_support",
],
}
@@ -87,21 +93,20 @@
],
shared_libs: [
"libbinder_ndk",
- "libcppbor_external",
"libcrypto",
- "libkeymaster_portable",
- "libpuresoftkeymasterdevice",
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
- "libcppcose",
+ "libcppbor_external",
+ "libcppcose_rkp",
"libgmock_ndk",
+ "libkeymaster_portable",
"libkeymint",
"libkeymint_support",
"libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
- "libremote_provisioner",
+ "libpuresoftkeymasterdevice",
],
test_suites: [
"general-tests",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index daa3e18..4e951d6 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -35,6 +35,12 @@
using AttestKeyTest = KeyMintAidlTestBase;
+/*
+ * AttestKeyTest.AllRsaSizes
+ *
+ * This test creates self signed RSA attestation keys of various sizes, and verify they can be
+ * used to sign other RSA and EC keys.
+ */
TEST_P(AttestKeyTest, AllRsaSizes) {
for (auto size : ValidKeySizes(Algorithm::RSA)) {
/*
@@ -54,7 +60,7 @@
EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
/*
- * Use attestation key to sign RSA key
+ * Use attestation key to sign RSA signing key
*/
attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
vector<uint8_t> attested_key_blob;
@@ -81,14 +87,47 @@
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
- if (attest_key_cert_chain.size() > 0) {
- attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
- }
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+ EXPECT_EQ(attested_key_cert_chain.size(), 2);
+
+ /*
+ * Use attestation key to sign RSA decryption key
+ */
+ attested_key_characteristics.resize(0);
+ attested_key_cert_chain.resize(0);
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo2")
+ .AttestationApplicationId("bar2")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo2", "bar2", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+ EXPECT_EQ(attested_key_cert_chain.size(), 2);
/*
* Use attestation key to sign EC key
*/
+ attested_key_characteristics.resize(0);
+ attested_key_cert_chain.resize(0);
EXPECT_EQ(ErrorCode::OK,
GenerateKey(AuthorizationSetBuilder()
.EcdsaSigningKey(EcCurve::P_256)
@@ -111,9 +150,7 @@
EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
// Appending the attest_key chain to the attested_key_chain should yield a valid chain.
- if (attest_key_cert_chain.size() > 0) {
- attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
- }
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
// Bail early if anything failed.
@@ -121,6 +158,327 @@
}
}
+/*
+ * AttestKeyTest.RsaAttestedAttestKeys
+ *
+ * This test creates an RSA attestation key signed by factory keys, and varifies it can be
+ * used to sign other RSA and EC keys.
+ */
+TEST_P(AttestKeyTest, RsaAttestedAttestKeys) {
+ 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 = 66;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ /*
+ * Create attestation key.
+ */
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+
+ EXPECT_GT(attest_key_cert_chain.size(), 1);
+ verify_subject_and_serial(attest_key_cert_chain[0], serial_int, subject, false);
+ EXPECT_TRUE(ChainSignaturesAreValid(attest_key_cert_chain));
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attest_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attest_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, //
+ sw_enforced, hw_enforced, SecLevel(),
+ attest_key_cert_chain[0].encodedCertificate));
+
+ /*
+ * Use attestation key to sign RSA key
+ */
+ attest_key.issuerSubjectName = subject_der;
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+
+ auto subject2 = "cert subject";
+ vector<uint8_t> subject_der2(make_name_from_str(subject2));
+
+ uint64_t serial_int2 = 987;
+ vector<uint8_t> serial_blob2(build_serial_blob(serial_int2));
+
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob2)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der2)
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+ CheckedDeleteKey(&attest_key.keyBlob);
+
+ AuthorizationSet hw_enforced2 = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced2 = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced2, hw_enforced2, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ attested_key_cert_chain.insert(attested_key_cert_chain.end(), attest_key_cert_chain.begin(),
+ attest_key_cert_chain.end());
+
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+ EXPECT_GT(attested_key_cert_chain.size(), 2);
+ verify_subject_and_serial(attested_key_cert_chain[0], serial_int2, subject2, false);
+}
+
+/*
+ * AttestKeyTest.RsaAttestKeyChaining
+ *
+ * This test creates a chain of multiple RSA attest keys, each used to sign the next attest key,
+ * with the last attest key signed by the factory chain.
+ */
+TEST_P(AttestKeyTest, RsaAttestKeyChaining) {
+ const int chain_size = 6;
+ vector<vector<uint8_t>> key_blob_list(chain_size);
+ vector<vector<Certificate>> cert_chain_list(chain_size);
+
+ for (int i = 0; i < chain_size; i++) {
+ string sub = "attest key chaining ";
+ char index = '1' + i;
+ string subject = sub + index;
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 7000 + i;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<KeyCharacteristics> attested_key_characteristics;
+ AttestationKey attest_key;
+ optional<AttestationKey> attest_key_opt;
+
+ if (i > 0) {
+ attest_key.issuerSubjectName = make_name_from_str(sub + (char)(index - 1));
+ attest_key.keyBlob = key_blob_list[i - 1];
+ attest_key_opt = attest_key;
+ }
+
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+ &cert_chain_list[i]));
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_list[i][0].encodedCertificate));
+
+ if (i > 0) {
+ /*
+ * The first key is attestated with factory chain, but all the rest of the keys are
+ * not supposed to be returned in attestation certificate chains.
+ */
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_list[i]));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ cert_chain_list[i].insert(cert_chain_list[i].end(), //
+ cert_chain_list[i - 1].begin(), //
+ cert_chain_list[i - 1].end());
+ }
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
+ EXPECT_GT(cert_chain_list[i].size(), i + 1);
+ verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
+ }
+
+ for (int i = 0; i < chain_size; i++) {
+ CheckedDeleteKey(&key_blob_list[i]);
+ }
+}
+
+/*
+ * AttestKeyTest.EcAttestKeyChaining
+ *
+ * This test creates a chain of multiple Ec attest keys, each used to sign the next attest key,
+ * with the last attest key signed by the factory chain.
+ */
+TEST_P(AttestKeyTest, EcAttestKeyChaining) {
+ const int chain_size = 6;
+ vector<vector<uint8_t>> key_blob_list(chain_size);
+ vector<vector<Certificate>> cert_chain_list(chain_size);
+
+ for (int i = 0; i < chain_size; i++) {
+ string sub = "Ec attest key chaining ";
+ char index = '1' + i;
+ string subject = sub + index;
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 800000 + i;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<KeyCharacteristics> attested_key_characteristics;
+ AttestationKey attest_key;
+ optional<AttestationKey> attest_key_opt;
+
+ if (i > 0) {
+ attest_key.issuerSubjectName = make_name_from_str(sub + (char)(index - 1));
+ attest_key.keyBlob = key_blob_list[i - 1];
+ attest_key_opt = attest_key;
+ }
+
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+ &cert_chain_list[i]));
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_list[i][0].encodedCertificate));
+
+ if (i > 0) {
+ /*
+ * The first key is attestated with factory chain, but all the rest of the keys are
+ * not supposed to be returned in attestation certificate chains.
+ */
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_list[i]));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ cert_chain_list[i].insert(cert_chain_list[i].end(), //
+ cert_chain_list[i - 1].begin(), //
+ cert_chain_list[i - 1].end());
+ }
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
+ EXPECT_GT(cert_chain_list[i].size(), i + 1);
+ verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
+ }
+
+ for (int i = 0; i < chain_size; i++) {
+ CheckedDeleteKey(&key_blob_list[i]);
+ }
+}
+
+/*
+ * AttestKeyTest.AlternateAttestKeyChaining
+ *
+ * This test creates a chain of multiple attest keys, in the order Ec - RSA - Ec - RSA ....
+ * Each attest key is used to sign the next attest key, with the last attest key signed by
+ * the factory chain. This is to verify different algorithms of attest keys can
+ * cross sign each other and be chained together.
+ */
+TEST_P(AttestKeyTest, AlternateAttestKeyChaining) {
+ const int chain_size = 6;
+ vector<vector<uint8_t>> key_blob_list(chain_size);
+ vector<vector<Certificate>> cert_chain_list(chain_size);
+
+ for (int i = 0; i < chain_size; i++) {
+ string sub = "Alt attest key chaining ";
+ char index = '1' + i;
+ string subject = sub + index;
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 90000000 + i;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<KeyCharacteristics> attested_key_characteristics;
+ AttestationKey attest_key;
+ optional<AttestationKey> attest_key_opt;
+
+ if (i > 0) {
+ attest_key.issuerSubjectName = make_name_from_str(sub + (char)(index - 1));
+ attest_key.keyBlob = key_blob_list[i - 1];
+ attest_key_opt = attest_key;
+ }
+
+ if ((i & 0x1) == 1) {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+ &cert_chain_list[i]));
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .AttestKey()
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+ &cert_chain_list[i]));
+ }
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_list[i][0].encodedCertificate));
+
+ if (i > 0) {
+ /*
+ * The first key is attestated with factory chain, but all the rest of the keys are
+ * not supposed to be returned in attestation certificate chains.
+ */
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_list[i]));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ cert_chain_list[i].insert(cert_chain_list[i].end(), //
+ cert_chain_list[i - 1].begin(), //
+ cert_chain_list[i - 1].end());
+ }
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
+ EXPECT_GT(cert_chain_list[i].size(), i + 1);
+ verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
+ }
+
+ for (int i = 0; i < chain_size; i++) {
+ CheckedDeleteKey(&key_blob_list[i]);
+ }
+}
+
TEST_P(AttestKeyTest, AllEcCurves) {
for (auto curve : ValidCurves()) {
/*
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
new file mode 100644
index 0000000..7009c6e
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymint_1_attest_key_test"
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+class DeviceUniqueAttestationTest : public KeyMintAidlTestBase {
+ protected:
+ void CheckUniqueAttestationResults(const vector<uint8_t>& key_blob,
+ const vector<KeyCharacteristics>& key_characteristics,
+ const AuthorizationSet& hw_enforced, int key_size) {
+ ASSERT_GT(cert_chain_.size(), 0);
+
+ if (KeyMintAidlTestBase::dump_Attestations) {
+ std::cout << bin2hex(cert_chain_[0].encodedCertificate) << std::endl;
+ }
+
+ ASSERT_GT(key_blob.size(), 0U);
+
+ 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);
+
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
+ SecLevel(), cert_chain_[0].encodedCertificate));
+ }
+};
+
+/*
+ * DeviceUniqueAttestationTest.RsaNonStrongBoxUnimplemented
+ *
+ * Verifies that non strongbox implementations do not implement Rsa device unique
+ * attestation.
+ */
+TEST_P(DeviceUniqueAttestationTest, RsaNonStrongBoxUnimplemented) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ // Check RSA implementation
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
+ &key_blob, &key_characteristics);
+
+ ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_TAG);
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaNonStrongBoxUnimplemented
+ *
+ * Verifies that non strongbox implementations do not implement Ecdsa device unique
+ * attestation.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaNonStrongBoxUnimplemented) {
+ if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ // Check Ecdsa implementation
+ auto result = GenerateKey(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),
+ &key_blob, &key_characteristics);
+
+ ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_TAG);
+}
+
+/*
+ * DeviceUniqueAttestationTest.RsaDeviceUniqueAttestation
+ *
+ * Verifies that strongbox implementations of Rsa implements device unique
+ * attestation correctly, if implemented.
+ */
+TEST_P(DeviceUniqueAttestationTest, RsaDeviceUniqueAttestation) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ int key_size = 2048;
+
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
+ &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);
+
+ 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());
+
+ CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestation
+ *
+ * Verifies that strongbox implementations of Rsa implements device unique
+ * attestation correctly, if implemented.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestation) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ int key_size = 256;
+
+ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .AttestationChallenge("challenge")
+ .AttestationApplicationId("foo")
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
+ &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);
+
+ 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());
+
+ CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(DeviceUniqueAttestationTest);
+
+} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index ce6f67a..61f2f77 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,9 +22,13 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <cppbor_parse.h>
#include <cutils/properties.h>
+#include <gmock/gmock.h>
#include <openssl/mem.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <keymaster/cppcose/cppcose.h>
#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
@@ -32,6 +36,7 @@
namespace aidl::android::hardware::security::keymint {
+using namespace cppcose;
using namespace std::literals::chrono_literals;
using std::endl;
using std::optional;
@@ -39,6 +44,7 @@
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
+using ::testing::MatchesRegex;
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
if (set.size() == 0)
@@ -113,7 +119,6 @@
// Attestations don't contain everything in key authorization lists, so we need to filter the key
// lists to produce the lists that we expect to match the attestations.
auto kTagsToFilter = {
- Tag::BLOB_USAGE_REQUIREMENTS, //
Tag::CREATION_DATETIME, //
Tag::EC_CURVE,
Tag::HARDWARE_TYPE,
@@ -342,7 +347,7 @@
SCOPED_TRACE("Begin");
Status result;
BeginResult out;
- result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+ result = keymint_->begin(purpose, key_blob, in_params.vector_data(), std::nullopt, &out);
if (result.isOk()) {
*out_params = out.params;
@@ -360,7 +365,7 @@
Status result;
BeginResult out;
- result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+ result = keymint_->begin(purpose, key_blob, in_params.vector_data(), std::nullopt, &out);
if (result.isOk()) {
*out_params = out.params;
@@ -839,6 +844,66 @@
return result;
}
+void verify_serial(X509* cert, const uint64_t expected_serial) {
+ BIGNUM_Ptr ser(BN_new());
+ EXPECT_TRUE(ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), ser.get()));
+
+ uint64_t serial;
+ EXPECT_TRUE(BN_get_u64(ser.get(), &serial));
+ EXPECT_EQ(serial, expected_serial);
+}
+
+// Please set self_signed to true for fake certificates or self signed
+// certificates
+void verify_subject(const X509* cert, //
+ const string& subject, //
+ bool self_signed) {
+ char* cert_issuer = //
+ X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
+
+ char* cert_subj = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
+
+ string expected_subject("/CN=");
+ if (subject.empty()) {
+ expected_subject.append("Android Keystore Key");
+ } else {
+ expected_subject.append(subject);
+ }
+
+ EXPECT_STREQ(expected_subject.c_str(), cert_subj) << "Cert has wrong subject." << cert_subj;
+
+ if (self_signed) {
+ EXPECT_STREQ(cert_issuer, cert_subj)
+ << "Cert issuer and subject mismatch for self signed certificate.";
+ }
+
+ OPENSSL_free(cert_subj);
+ OPENSSL_free(cert_issuer);
+}
+
+vector<uint8_t> build_serial_blob(const uint64_t serial_int) {
+ BIGNUM_Ptr serial(BN_new());
+ EXPECT_TRUE(BN_set_u64(serial.get(), serial_int));
+
+ int len = BN_num_bytes(serial.get());
+ vector<uint8_t> serial_blob(len);
+ if (BN_bn2bin(serial.get(), serial_blob.data()) != len) {
+ return {};
+ }
+
+ return serial_blob;
+}
+
+void verify_subject_and_serial(const Certificate& certificate, //
+ const uint64_t expected_serial, //
+ const string& subject, bool self_signed) {
+ X509_Ptr cert(parse_cert_blob(certificate.encodedCertificate));
+ ASSERT_TRUE(!!cert.get());
+
+ verify_serial(cert.get(), expected_serial);
+ verify_subject(cert.get(), subject, self_signed);
+}
+
bool verify_attestation_record(const string& challenge, //
const string& app_id, //
AuthorizationSet expected_sw_enforced, //
@@ -876,17 +941,21 @@
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
- EXPECT_GE(att_attestation_version, 3U);
+ EXPECT_EQ(att_attestation_version, 100U);
+ vector<uint8_t> appId(app_id.begin(), app_id.end());
- expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
- vector<uint8_t>(app_id.begin(), app_id.end()));
+ // check challenge and app id only if we expects a non-fake certificate
+ if (challenge.length() > 0) {
+ EXPECT_EQ(challenge.length(), att_challenge.size());
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
- EXPECT_GE(att_keymaster_version, 4U);
+ 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(security_level, att_attestation_security_level);
- EXPECT_EQ(challenge.length(), att_challenge.size());
- EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
char property_value[PROPERTY_VALUE_MAX] = {};
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
@@ -897,7 +966,7 @@
if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
std::string date =
- std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
+ std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::integer>());
// strptime seems to require delimiters, but the tag value will
// be YYYYMMDD
date.insert(6, "-");
@@ -1072,17 +1141,10 @@
string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
if (cert_issuer != signer_subj) {
- return AssertionFailure() << "Cert " << i << " has wrong issuer.\n" << cert_data.str();
- }
-
- if (i == 0) {
- string cert_sub = x509NameToStr(X509_get_subject_name(key_cert.get()));
- if ("/CN=Android Keystore Key" != cert_sub) {
- return AssertionFailure()
- << "Leaf cert has wrong subject, should be CN=Android Keystore Key, was "
- << cert_sub << '\n'
- << cert_data.str();
- }
+ return AssertionFailure() << "Cert " << i << " has wrong issuer.\n"
+ << " Signer subject is " << signer_subj
+ << " Issuer subject is " << cert_issuer << endl
+ << cert_data.str();
}
}
@@ -1118,6 +1180,121 @@
return retval;
}
+namespace {
+
+void check_cose_key(const vector<uint8_t>& data, bool testMode) {
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+
+ // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
+ if (testMode) {
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
+ " -70000 : null,\n" // test marker
+ "}"));
+ } else {
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
+ "}"));
+ }
+}
+
+} // namespace
+
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+ vector<uint8_t>* payload_value) {
+ auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+ ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+ ASSERT_NE(coseMac0->asArray(), nullptr);
+ ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+ auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+ ASSERT_NE(protParms, nullptr);
+
+ // Header label:value of 'alg': HMAC-256
+ ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
+
+ auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+ ASSERT_NE(unprotParms, nullptr);
+ ASSERT_EQ(unprotParms->size(), 0);
+
+ // The payload is a bstr holding an encoded COSE_Key
+ auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+ ASSERT_NE(payload, nullptr);
+ check_cose_key(payload->value(), testMode);
+
+ auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+ ASSERT_TRUE(coseMac0Tag);
+ auto extractedTag = coseMac0Tag->value();
+ EXPECT_EQ(extractedTag.size(), 32U);
+
+ // Compare with tag generated with kTestMacKey. Should only match in test mode
+ auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+ payload->value());
+ ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+
+ if (testMode) {
+ EXPECT_EQ(*testTag, extractedTag);
+ } else {
+ EXPECT_NE(*testTag, extractedTag);
+ }
+ if (payload_value != nullptr) {
+ *payload_value = payload->value();
+ }
+}
+
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
+ // Extract x and y affine coordinates from the encoded Cose_Key.
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+ auto coseKey = parsedPayload->asMap();
+ const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
+ ASSERT_NE(xItem->asBstr(), nullptr);
+ vector<uint8_t> x = xItem->asBstr()->value();
+ const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
+ ASSERT_NE(yItem->asBstr(), nullptr);
+ vector<uint8_t> y = yItem->asBstr()->value();
+
+ // Concatenate: 0x04 (uncompressed form marker) | x | y
+ vector<uint8_t> pubKeyData{0x04};
+ pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
+ pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
+
+ EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
+ ASSERT_NE(ecKey, nullptr);
+ EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ ASSERT_NE(group, nullptr);
+ ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
+ EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ ASSERT_NE(point, nullptr);
+ ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
+ nullptr),
+ 1);
+ ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
+
+ EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
+ ASSERT_NE(pubKey, nullptr);
+ EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
+ *signingKey = std::move(pubKey);
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 4d97ea9..75a4418 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -25,6 +25,7 @@
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>
@@ -268,15 +269,27 @@
long challenge_;
};
+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);
+void verify_subject_and_serial(const Certificate& certificate, //
+ const uint64_t expected_serial, //
+ const string& subject, bool self_signed);
+
bool verify_attestation_record(const string& challenge, //
const string& app_id, //
AuthorizationSet expected_sw_enforced, //
AuthorizationSet expected_hw_enforced, //
SecurityLevel security_level,
const vector<uint8_t>& attestation_cert);
+
string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
vector<uint8_t> make_name_from_str(const string& name);
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+ vector<uint8_t>* payload_value);
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
+
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7ecfa37..a89cc5b 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -27,6 +27,9 @@
#include <cutils/properties.h>
+#include <android/binder_manager.h>
+
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/KeyFormat.h>
#include <keymint_support/key_param_output.h>
@@ -134,6 +137,54 @@
"d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
"3492d6");
+/*
+ * DER-encoded PKCS#8 format RSA key. Generated using:
+ *
+ * openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1 "%02X" "\n"'
+ */
+string rsa_2048_key =
+ hex2str("308204BD020100300D06092A864886F70D0101010500048204A7308204A3"
+ "0201000282010100BEBC342B56D443B1299F9A6A7056E80A897E318476A5"
+ "A18029E63B2ED739A61791D339F58DC763D9D14911F2EDEC383DEE11F631"
+ "9B44510E7A3ECD9B79B97382E49500ACF8117DC89CAF0E621F77756554A2"
+ "FD4664BFE7AB8B59AB48340DBFA27B93B5A81F6ECDEB02D0759307128DF3"
+ "E3BAD4055C8B840216DFAA5700670E6C5126F0962FCB70FF308F25049164"
+ "CCF76CC2DA66A7DD9A81A714C2809D69186133D29D84568E892B6FFBF319"
+ "9BDB14383EE224407F190358F111A949552ABA6714227D1BD7F6B20DD0CB"
+ "88F9467B719339F33BFF35B3870B3F62204E4286B0948EA348B524544B5F"
+ "9838F29EE643B079EEF8A713B220D7806924CDF7295070C5020301000102"
+ "82010069F377F35F2F584EF075353CCD1CA99738DB3DBC7C7FF35F9366CE"
+ "176DFD1B135AB10030344ABF5FBECF1D4659FDEF1C0FC430834BE1BE3911"
+ "951377BB3D563A2EA9CA8F4AD9C48A8CE6FD516A735C662686C7B4B3C09A"
+ "7B8354133E6F93F790D59EAEB92E84C9A4339302CCE28FDF04CCCAFA7DE3"
+ "F3A827D4F6F7D38E68B0EC6AB706645BF074A4E4090D06FB163124365FD5"
+ "EE7A20D350E9958CC30D91326E1B292E9EF5DB408EC42DAF737D20149704"
+ "D0A678A0FB5B5446863B099228A352D604BA8091A164D01D5AB05397C71E"
+ "AD20BE2A08FC528FE442817809C787FEE4AB97F97B9130D022153EDC6EB6"
+ "CBE7B0F8E3473F2E901209B5DB10F93604DB0102818100E83C0998214941"
+ "EA4F9293F1B77E2E99E6CF305FAF358238E126124FEAF2EB9724B2EA7B78"
+ "E6032343821A80E55D1D88FB12D220C3F41A56142FEC85796D1917F1E8C7"
+ "74F142B67D3D6E7B7E6B4383E94DB5929089DBB346D5BDAB40CC2D96EE04"
+ "09475E175C63BF78CFD744136740838127EA723FF3FE7FA368C1311B4A4E"
+ "0502818100D240FCC0F5D7715CDE21CB2DC86EA146132EA3B06F61FF2AF5"
+ "4BF38473F59DADCCE32B5F4CC32DD0BA6F509347B4B5B1B58C39F95E4798"
+ "CCBB43E83D0119ACF532F359CA743C85199F0286610E200997D731291717"
+ "9AC9B67558773212EC961E8BCE7A3CC809BC5486A96E4B0E6AF394D94E06"
+ "6A0900B7B70E82A44FB30053C102818100AD15DA1CBD6A492B66851BA8C3"
+ "16D38AB700E2CFDDD926A658003513C54BAA152B30021D667D20078F500F"
+ "8AD3E7F3945D74A891ED1A28EAD0FEEAEC8C14A8E834CF46A13D1378C99D"
+ "18940823CFDD27EC5810D59339E0C34198AC638E09C87CBB1B634A9864AE"
+ "9F4D5EB2D53514F67B4CAEC048C8AB849A02E397618F3271350281801FA2"
+ "C1A5331880A92D8F3E281C617108BF38244F16E352E69ED417C7153F9EC3"
+ "18F211839C643DCF8B4DD67CE2AC312E95178D5D952F06B1BF779F491692"
+ "4B70F582A23F11304E02A5E7565AE22A35E74FECC8B6FDC93F92A1A37703"
+ "E4CF0E63783BD02EB716A7ECBBFA606B10B74D01579522E7EF84D91FC522"
+ "292108D902C1028180796FE3825F9DCC85DF22D58690065D93898ACD65C0"
+ "87BEA8DA3A63BF4549B795E2CD0E3BE08CDEBD9FCF1720D9CDC5070D74F4"
+ "0DED8E1102C52152A31B6165F83A6722AECFCC35A493D7634664B888A08D"
+ "3EB034F12EA28BFEE346E205D334827F778B16ED40872BD29FCB36536B6E"
+ "93FFB06778696B4A9D81BB0A9423E63DE5");
+
string ec_256_key =
hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
"6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
@@ -209,6 +260,32 @@
string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
};
+string device_suffix(const string& name) {
+ size_t pos = name.find('/');
+ if (pos == string::npos) {
+ return name;
+ }
+ return name.substr(pos + 1);
+}
+
+bool matching_rp_instance(const string& km_name,
+ std::shared_ptr<IRemotelyProvisionedComponent>* rp) {
+ string km_suffix = device_suffix(km_name);
+
+ vector<string> rp_names =
+ ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+ for (const string& rp_name : rp_names) {
+ // If the suffix of the RemotelyProvisionedComponent instance equals the suffix of the
+ // KeyMint instance, assume they match.
+ if (device_suffix(rp_name) == km_suffix && AServiceManager_isDeclared(rp_name.c_str())) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(rp_name.c_str()));
+ *rp = IRemotelyProvisionedComponent::fromBinder(binder);
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
class NewKeyGenerationTest : public KeyMintAidlTestBase {
@@ -282,21 +359,30 @@
* have correct characteristics.
*/
TEST_P(NewKeyGenerationTest, RsaWithAttestation) {
- for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
- auto challenge = "hello";
- auto app_id = "foo";
+ 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 = 66;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(key_size, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
- .AttestationChallenge(challenge)
- .AttestationApplicationId(app_id)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .SetDefaultValidity(),
- &key_blob, &key_characteristics));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
@@ -308,6 +394,7 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
@@ -322,6 +409,264 @@
}
/*
+ * NewKeyGenerationTest.RsaWithRpkAttestation
+ *
+ * Verifies that keymint can generate all required RSA key sizes, using an attestation key
+ * that has been generated using an associate IRemotelyProvisionedComponent.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithRpkAttestation) {
+ // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
+ // instance.
+ std::shared_ptr<IRemotelyProvisionedComponent> rp;
+ ASSERT_TRUE(matching_rp_instance(GetParam(), &rp))
+ << "No IRemotelyProvisionedComponent found that matches KeyMint device " << GetParam();
+
+ // Generate a P-256 keypair to use as an attestation key.
+ MacedPublicKey macedPubKey;
+ std::vector<uint8_t> privateKeyBlob;
+ auto status =
+ rp->generateEcdsaP256KeyPair(/* testMode= */ false, &macedPubKey, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk());
+ vector<uint8_t> coseKeyData;
+ check_maced_pubkey(macedPubKey, /* testMode= */ false, &coseKeyData);
+
+ AttestationKey attestation_key;
+ attestation_key.keyBlob = std::move(privateKeyBlob);
+ attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
+
+ // The signature over the attested key should correspond to the P256 public key.
+ X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_TRUE(key_cert.get());
+ EVP_PKEY_Ptr signing_pubkey;
+ p256_pub_key(coseKeyData, &signing_pubkey);
+ ASSERT_TRUE(signing_pubkey.get());
+
+ ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+ << "Verification of attested certificate failed "
+ << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.RsaEncryptionWithAttestation
+ *
+ * Verifies that keymint attestation for RSA encryption keys with challenge and
+ * app id is also successful.
+ */
+TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) {
+ auto key_size = 2048;
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ auto subject = "subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 111166;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ AuthorizationSet auths;
+ for (auto& entry : key_characteristics) {
+ auths.push_back(AuthorizationSet(entry.authorizations));
+ }
+
+ EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+ EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+
+ // Verify that App data and ROT are NOT included.
+ EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+ EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+ // Check that some unexpected tags/values are NOT present.
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+
+ EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));
+
+ auto os_ver = auths.GetTagValue(TAG_OS_VERSION);
+ ASSERT_TRUE(os_ver);
+ EXPECT_EQ(*os_ver, os_version());
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, //
+ sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_[0].encodedCertificate));
+
+ CheckedDeleteKey(&key_blob);
+}
+
+/*
+ * NewKeyGenerationTest.RsaWithSelfSign
+ *
+ * Verifies that attesting to RSA key generation is successful, and returns
+ * self signed certificate if no challenge is provided. And signing etc
+ * works as expected.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithSelfSign) {
+ auto subject = "cert subj subj subj subj subj subj 22222222222222222222";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 0;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_EQ(cert_chain_.size(), 1);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.RsaWithAttestationMissAppId
+ *
+ * Verifies that attesting to RSA checks for missing app ID.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithAttestationMissAppId) {
+ auto challenge = "hello";
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+}
+
+/*
+ * NewKeyGenerationTest.RsaWithAttestationAppIdIgnored
+ *
+ * Verifies that attesting to RSA ignores app id if challenge is missing.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithAttestationAppIdIgnored) {
+ auto key_size = 2048;
+ auto app_id = "foo";
+
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 1;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_EQ(cert_chain_.size(), 1);
+
+ CheckedDeleteKey(&key_blob);
+}
+
+/*
* NewKeyGenerationTest.LimitedUsageRsa
*
* Verifies that KeyMint can generate all required RSA key sizes with limited usage, and that the
@@ -368,22 +713,31 @@
* resulting keys have correct characteristics and attestation.
*/
TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) {
- for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
- auto challenge = "hello";
- auto app_id = "foo";
+ 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 = 66;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(key_size, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
- .AttestationChallenge(challenge)
- .AttestationApplicationId(app_id)
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
- .SetDefaultValidity(),
- &key_blob, &key_characteristics));
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
ASSERT_GT(key_blob.size(), 0U);
CheckBaseParams(key_characteristics);
@@ -406,6 +760,7 @@
// Check the usage count limit tag also appears in the attestation.
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -480,6 +835,208 @@
}
/*
+ * NewKeyGenerationTest.EcdsaAttestation
+ *
+ * Verifies that for all Ecdsa key sizes, if challenge and app id is provided,
+ * an attestation will be generated.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestation) {
+ 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 = 0xFFFFFFFFFFFFFFFF;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(key_size)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(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(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, //
+ sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_[0].encodedCertificate));
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaSelfSignAttestation
+ *
+ * Verifies that if no challenge is provided to an Ecdsa key generation, then
+ * the key will generate a self signed attestation.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaSelfSignAttestation) {
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+
+ uint64_t serial_int = 0x123456FFF1234;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+
+ for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(key_size)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(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(ChainSignaturesAreValid(cert_chain_));
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
+ ASSERT_EQ(cert_chain_.size(), 1);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAttestationRequireAppId
+ *
+ * Verifies that if attestation challenge is provided to Ecdsa key generation, then
+ * app id must also be provided or else it will fail.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationRequireAppId) {
+ auto challenge = "hello";
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+
+ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaIgnoreAppId
+ *
+ * Verifies that if no challenge is provided to the Ecdsa key generation, then
+ * any appid will be ignored, and keymint will generate a self sign certificate.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaIgnoreAppId) {
+ auto app_id = "foo";
+
+ for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(key_size)
+ .Digest(Digest::NONE)
+ .AttestationApplicationId(app_id)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(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(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_EQ(cert_chain_.size(), 1);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.AttestationApplicationIDLengthProperlyEncoded
+ *
+ * Verifies that the Attestation Application ID software enforced tag has a proper length encoding.
+ * Some implementations break strict encoding rules by encoding a length between 127 and 256 in one
+ * byte. Proper DER encoding specifies that for lengths greater than 127, one byte should be used
+ * to specify how many following bytes will be used to encode the length.
+ */
+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) {
+ const string app_id(length, 'a');
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(key_size)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics));
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(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(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+ EXPECT_TRUE(verify_attestation_record(challenge, app_id, //
+ sw_enforced, hw_enforced, SecLevel(),
+ cert_chain_[0].encodedCertificate));
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
* NewKeyGenerationTest.LimitedUsageEcdsa
*
* Verifies that KeyMint can generate all required EC key sizes with limited usage, and that the
@@ -641,6 +1198,41 @@
}
/*
+ * NewKeyGenerationTest.HmacNoAttestation
+ *
+ * Verifies that for Hmac key generation, no attestation will be generated even if challenge
+ * and app id are provided.
+ */
+TEST_P(NewKeyGenerationTest, HmacNoAttestation) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ constexpr size_t key_size = 128;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(key_size)
+ .Digest(digest)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ ASSERT_EQ(cert_chain_.size(), 0);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
* NewKeyGenerationTest.LimitedUsageHmac
*
* Verifies that KeyMint supports all required digests with limited usage Hmac, and that the
@@ -774,6 +1366,47 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)));
}
+/*
+ * NewKeyGenerationTest.AesNoAttestation
+ *
+ * Verifies that attestation parameters to AES keys are ignored and generateKey
+ * will succeed.
+ */
+TEST_P(NewKeyGenerationTest, AesNoAttestation) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Padding(PaddingMode::PKCS7)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)));
+
+ ASSERT_EQ(cert_chain_.size(), 0);
+}
+
+/*
+ * NewKeyGenerationTest.TripleDesNoAttestation
+ *
+ * Verifies that attesting parameters to 3DES keys are ignored and generate key
+ * will be successful. No attestation should be generated.
+ */
+TEST_P(NewKeyGenerationTest, TripleDesNoAttestation) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .TripleDesEncryptionKey(168)
+ .BlockMode(BlockMode::ECB)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)));
+ ASSERT_EQ(cert_chain_.size(), 0);
+}
+
INSTANTIATE_KEYMINT_AIDL_TEST(NewKeyGenerationTest);
typedef KeyMintAidlTestBase SigningOperationsTest;
@@ -1711,16 +2344,27 @@
* Verifies that importing and using an RSA key pair works correctly.
*/
TEST_P(ImportKeyTest, RsaSuccess) {
+ uint32_t key_size;
+ string key;
+
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ key_size = 2048;
+ key = rsa_2048_key;
+ } else {
+ key_size = 1024;
+ key = rsa_key;
+ }
+
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaSigningKey(1024, 65537)
+ .RsaSigningKey(key_size, 65537)
.Digest(Digest::SHA_2_256)
.Padding(PaddingMode::RSA_PSS)
.SetDefaultValidity(),
- KeyFormat::PKCS8, rsa_key));
+ KeyFormat::PKCS8, key));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
- CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+ CheckCryptoParam(TAG_KEY_SIZE, key_size);
CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
@@ -4728,16 +5372,6 @@
INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
-using PerformOperationTest = KeyMintAidlTestBase;
-
-TEST_P(PerformOperationTest, RequireUnimplemented) {
- vector<uint8_t> response;
- auto result = keymint_->performOperation({} /* request */, &response);
- ASSERT_EQ(GetReturnErrorCode(result), ErrorCode::UNIMPLEMENTED);
-}
-
-INSTANTIATE_KEYMINT_AIDL_TEST(PerformOperationTest);
-
} // namespace aidl::android::hardware::security::keymint::test
int main(int argc, char** argv) {
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 57bc27a..a2071c2 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -16,13 +16,13 @@
#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
-#include <RemotelyProvisionedComponent.h>
+#include <AndroidRemotelyProvisionedComponentDevice.h>
#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
#include <android/binder_manager.h>
#include <cppbor_parse.h>
-#include <cppcose/cppcose.h>
#include <gmock/gmock.h>
+#include <keymaster/cppcose/cppcose.h>
#include <keymaster/keymaster_configuration.h>
#include <keymint_support/authorization_set.h>
#include <openssl/ec.h>
@@ -55,117 +55,6 @@
return bytevec(p, p + strlen(s));
}
-void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
- // Extract x and y affine coordinates from the encoded Cose_Key.
- auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
- ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
- auto coseKey = parsedPayload->asMap();
- const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
- ASSERT_NE(xItem->asBstr(), nullptr);
- vector<uint8_t> x = xItem->asBstr()->value();
- const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
- ASSERT_NE(yItem->asBstr(), nullptr);
- vector<uint8_t> y = yItem->asBstr()->value();
-
- // Concatenate: 0x04 (uncompressed form marker) | x | y
- vector<uint8_t> pubKeyData{0x04};
- pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
- pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
-
- EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
- ASSERT_NE(ecKey, nullptr);
- EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- ASSERT_NE(group, nullptr);
- ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
- EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
- ASSERT_NE(point, nullptr);
- ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
- nullptr),
- 1);
- ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
-
- EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
- ASSERT_NE(pubKey, nullptr);
- EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
- *signingKey = std::move(pubKey);
-}
-
-void check_cose_key(const vector<uint8_t>& data, bool testMode) {
- auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
- ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
-
- // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
- if (testMode) {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- " -70000 : null,\n" // test marker
- "}"));
- } else {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- "}"));
- }
-}
-
-void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
- vector<uint8_t>* payload_value) {
- auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
- ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
-
- ASSERT_NE(coseMac0->asArray(), nullptr);
- ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
-
- auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
- ASSERT_NE(protParms, nullptr);
-
- // Header label:value of 'alg': HMAC-256
- ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
-
- auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
- ASSERT_NE(unprotParms, nullptr);
- ASSERT_EQ(unprotParms->size(), 0);
-
- // The payload is a bstr holding an encoded COSE_Key
- auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
- ASSERT_NE(payload, nullptr);
- check_cose_key(payload->value(), testMode);
-
- auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
- ASSERT_TRUE(coseMac0Tag);
- auto extractedTag = coseMac0Tag->value();
- EXPECT_EQ(extractedTag.size(), 32U);
-
- // Compare with tag generated with kTestMacKey. Should only match in test mode
- auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
- payload->value());
- ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
-
- if (testMode) {
- EXPECT_EQ(*testTag, extractedTag);
- } else {
- EXPECT_NE(*testTag, extractedTag);
- }
- if (payload_value != nullptr) {
- *payload_value = payload->value();
- }
-}
-
ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 6c795f5..54b6fdc 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -228,8 +228,7 @@
AuthorizationSet* out_params) {
Status result;
BeginResult out;
- result = keymint_->begin(purpose, key_blob_, in_params.vector_data(), HardwareAuthToken(),
- &out);
+ result = keymint_->begin(purpose, key_blob_, in_params.vector_data(), std::nullopt, &out);
if (result.isOk()) {
*out_params = out.params;
op_ = out.operation;
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 4c4258b..718133a 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -57,25 +57,8 @@
"include",
],
shared_libs: [
- "libcppcose",
"libcppbor_external",
+ "libcppcose_rkp",
"libcrypto",
],
}
-
-cc_library {
- name: "libcppcose",
- vendor_available: true,
- host_supported: true,
- srcs: [
- "cppcose.cpp",
- ],
- export_include_dirs: [
- "include",
- ],
- shared_libs: [
- "libcppbor_external",
- "libcrypto",
- "liblog",
- ],
-}
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
deleted file mode 100644
index bafb2b6..0000000
--- a/security/keymint/support/cppcose.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cppcose/cppcose.h>
-
-#include <stdio.h>
-#include <iostream>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <openssl/err.h>
-
-namespace cppcose {
-
-namespace {
-
-ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
- const bytevec& nonce,
- const bytevec& aad,
- bool encrypt) {
- if (key.size() != kAesGcmKeySize) return "Invalid key size";
-
- bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
- if (!ctx) return "Failed to allocate cipher context";
-
- if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
- nonce.data(), encrypt ? 1 : 0)) {
- return "Failed to initialize cipher";
- }
-
- int outlen;
- if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
- aad.data(), aad.size())) {
- return "Failed to process AAD";
- }
-
- return std::move(ctx);
-}
-
-} // namespace
-
-ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
- const bytevec& payload) {
- auto macStructure = cppbor::Array()
- .add("MAC0")
- .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
- .add(externalAad)
- .add(payload)
- .encode();
-
- bytevec macTag(SHA256_DIGEST_LENGTH);
- uint8_t* out = macTag.data();
- unsigned int outLen;
- out = HMAC(EVP_sha256(), //
- macKey.data(), macKey.size(), //
- macStructure.data(), macStructure.size(), //
- out, &outLen);
-
- assert(out != nullptr && outLen == macTag.size());
- if (out == nullptr || outLen != macTag.size()) {
- return "Error computing public key MAC";
- }
-
- return macTag;
-}
-
-ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
- const bytevec& payload) {
- auto tag = generateCoseMac0Mac(macKey, externalAad, payload);
- if (!tag) return tag.moveMessage();
-
- return cppbor::Array()
- .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
- .add(cppbor::Map() /* unprotected */)
- .add(payload)
- .add(tag.moveValue());
-}
-
-ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) {
- auto mac = macItem ? macItem->asArray() : nullptr;
- if (!mac || mac->size() != kCoseMac0EntryCount) {
- return "Invalid COSE_Mac0";
- }
-
- auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
- auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
- auto payload = mac->get(kCoseMac0Payload)->asBstr();
- auto tag = mac->get(kCoseMac0Tag)->asBstr();
- if (!protectedParms || !unprotectedParms || !payload || !tag) {
- return "Invalid COSE_Mac0 contents";
- }
-
- return payload->value();
-}
-
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
- const bytevec& macKey) {
- auto mac = macItem ? macItem->asArray() : nullptr;
- if (!mac || mac->size() != kCoseMac0EntryCount) {
- return "Invalid COSE_Mac0";
- }
-
- auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
- auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
- auto payload = mac->get(kCoseMac0Payload)->asBstr();
- auto tag = mac->get(kCoseMac0Tag)->asBstr();
- if (!protectedParms || !unprotectedParms || !payload || !tag) {
- return "Invalid COSE_Mac0 contents";
- }
-
- auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
- if (!protectedMap || !protectedMap->asMap()) {
- return "Invalid Mac0 protected: " + errMsg;
- }
- auto& algo = protectedMap->asMap()->get(ALGORITHM);
- if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
- return "Unsupported Mac0 algorithm";
- }
-
- auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
- if (!macTag) return macTag.moveMessage();
-
- if (macTag->size() != tag->value().size() ||
- CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
- return "MAC tag mismatch";
- }
-
- return payload->value();
-}
-
-ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
- const bytevec& payload, const bytevec& aad) {
- bytevec signatureInput = cppbor::Array()
- .add("Signature1") //
- .add(protectedParams)
- .add(aad)
- .add(payload)
- .encode();
-
- if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
- bytevec signature(ED25519_SIGNATURE_LEN);
- if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
- return "Signing failed";
- }
-
- return signature;
-}
-
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
- const bytevec& payload, const bytevec& aad) {
- bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
- auto signature = createCoseSign1Signature(key, protParms, payload, aad);
- if (!signature) return signature.moveMessage();
-
- return cppbor::Array()
- .add(protParms)
- .add(cppbor::Map() /* unprotected parameters */)
- .add(payload)
- .add(*signature);
-}
-
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
- const bytevec& aad) {
- return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
-}
-
-ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1,
- const bytevec& signingCoseKey, const bytevec& aad) {
- if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
- return "Invalid COSE_Sign1";
- }
-
- const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
- const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
- const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
- const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
-
- if (!protectedParams || !unprotectedParams || !payload || !signature) {
- return "Invalid COSE_Sign1";
- }
-
- auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
- if (!parsedProtParams) {
- return errMsg + " when parsing protected params.";
- }
- if (!parsedProtParams->asMap()) {
- return "Protected params must be a map";
- }
-
- auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
- return "Unsupported signature algorithm";
- }
-
- if (!ignoreSignature) {
- bool selfSigned = signingCoseKey.empty();
- auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
- if (!key) return "Bad signing key: " + key.moveMessage();
-
- bytevec signatureInput = cppbor::Array()
- .add("Signature1")
- .add(*protectedParams)
- .add(aad)
- .add(*payload)
- .encode();
-
- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
- key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
- return "Signature verification failed";
- }
- }
-
- return payload->value();
-}
-
-ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
- const bytevec& protectedParams,
- const bytevec& plaintextPayload, const bytevec& aad) {
- auto ciphertext = aesGcmEncrypt(key, nonce,
- cppbor::Array() // Enc strucure as AAD
- .add("Encrypt") // Context
- .add(protectedParams) // Protected
- .add(aad) // External AAD
- .encode(),
- plaintextPayload);
-
- if (!ciphertext) return ciphertext.moveMessage();
- return ciphertext.moveValue();
-}
-
-ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
- const bytevec& plaintextPayload, const bytevec& aad,
- cppbor::Array recipients) {
- auto encryptProtectedHeader = cppbor::Map() //
- .add(ALGORITHM, AES_GCM_256)
- .canonicalize()
- .encode();
-
- auto ciphertext =
- createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
- if (!ciphertext) return ciphertext.moveMessage();
-
- return cppbor::Array()
- .add(encryptProtectedHeader) // Protected
- .add(cppbor::Map().add(IV, nonce).canonicalize()) // Unprotected
- .add(*ciphertext) // Payload
- .add(std::move(recipients));
-}
-
-ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
- const cppbor::Item* coseEncrypt) {
- if (!coseEncrypt || !coseEncrypt->asArray() ||
- coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
- return "Invalid COSE_Encrypt";
- }
-
- auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
- if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
- return "Invalid recipients list";
- }
-
- auto& recipient = recipients->asArray()->get(0);
- if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
- return "Invalid COSE_recipient";
- }
-
- auto& ciphertext = recipient->asArray()->get(2);
- if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
- return "Unexpected value in recipients ciphertext field " +
- cppbor::prettyPrint(ciphertext.get());
- }
-
- auto& protParms = recipient->asArray()->get(0);
- if (!protParms || !protParms->asBstr()) return "Invalid protected params";
- auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
- if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
- if (!parsedProtParms->asMap()) return "Invalid protected params";
-
- auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
- return "Invalid algorithm";
- }
-
- auto& unprotParms = recipient->asArray()->get(1);
- if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
-
- auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
- if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
-
- auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
- if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
- return "Invalid key type";
- }
-
- auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
- if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
- return "Unsupported curve";
- }
-
- auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
- if (!pubkey || !pubkey->asBstr() ||
- pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
- return "Invalid X25519 public key";
- }
-
- auto& key_id = unprotParms->asMap()->get(KEY_ID);
- if (key_id && key_id->asBstr()) {
- return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
- }
-
- // If no key ID, just return an empty vector.
- return std::make_pair(pubkey->asBstr()->value(), bytevec{});
-}
-
-ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
- const bytevec& external_aad) {
- if (!coseEncrypt || !coseEncrypt->asArray() ||
- coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
- return "Invalid COSE_Encrypt";
- }
-
- auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
- auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
- auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
- auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
-
- if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
- return "Invalid COSE_Encrypt";
- }
-
- auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
- if (!parsedProtParams) {
- return errMsg + " when parsing protected params.";
- }
- if (!parsedProtParams->asMap()) {
- return "Protected params must be a map";
- }
-
- auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
- return "Unsupported encryption algorithm";
- }
-
- if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
- return "Invalid unprotected params";
- }
-
- auto& nonce = unprotParms->asMap()->get(IV);
- if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
- return "Invalid nonce";
- }
-
- if (!ciphertext->asBstr()) return "Invalid ciphertext";
-
- auto aad = cppbor::Array() // Enc strucure as AAD
- .add("Encrypt") // Context
- .add(protParms->asBstr()->value()) // Protected
- .add(external_aad) // External AAD
- .encode();
-
- return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
-}
-
-ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
- const bytevec& pubKeyB, bool senderIsA) {
- bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
- if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
- return "ECDH operation failed";
- }
-
- bytevec kdfContext = cppbor::Array()
- .add(AES_GCM_256)
- .add(cppbor::Array() // Sender Info
- .add(cppbor::Bstr("client"))
- .add(bytevec{} /* nonce */)
- .add(senderIsA ? pubKeyA : pubKeyB))
- .add(cppbor::Array() // Recipient Info
- .add(cppbor::Bstr("server"))
- .add(bytevec{} /* nonce */)
- .add(senderIsA ? pubKeyB : pubKeyA))
- .add(cppbor::Array() // SuppPubInfo
- .add(128) // output key length
- .add(bytevec{})) // protected
- .encode();
-
- bytevec retval(SHA256_DIGEST_LENGTH);
- bytevec salt{};
- if (!HKDF(retval.data(), retval.size(), //
- EVP_sha256(), //
- rawSharedKey.data(), rawSharedKey.size(), //
- salt.data(), salt.size(), //
- kdfContext.data(), kdfContext.size())) {
- return "ECDH HKDF failed";
- }
-
- return retval;
-}
-
-ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
- const bytevec& plaintext) {
- auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
- if (!ctx) return ctx.moveMessage();
-
- bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
- int outlen;
- if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
- plaintext.size())) {
- return "Failed to encrypt plaintext";
- }
- assert(plaintext.size() == outlen);
-
- if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
- return "Failed to finalize encryption";
- }
- assert(outlen == 0);
-
- if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
- ciphertext.data() + plaintext.size())) {
- return "Failed to retrieve tag";
- }
-
- return ciphertext;
-}
-
-ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
- const bytevec& ciphertextWithTag) {
- auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
- if (!ctx) return ctx.moveMessage();
-
- if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
-
- bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
- int outlen;
- if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
- ciphertextWithTag.size() - kAesGcmTagSize)) {
- return "Failed to decrypt plaintext";
- }
- assert(plaintext.size() == outlen);
-
- bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
- if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
- return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
- }
-
- if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
- return "Failed to finalize encryption";
- }
- assert(outlen == 0);
-
- return plaintext;
-}
-
-} // namespace cppcose
diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h
deleted file mode 100644
index a936bfd..0000000
--- a/security/keymint/support/include/cppcose/cppcose.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <openssl/cipher.h>
-#include <openssl/curve25519.h>
-#include <openssl/digest.h>
-#include <openssl/hkdf.h>
-#include <openssl/hmac.h>
-#include <openssl/mem.h>
-#include <openssl/sha.h>
-
-namespace cppcose {
-
-using bytevec = std::vector<uint8_t>;
-
-constexpr int kCoseSign1EntryCount = 4;
-constexpr int kCoseSign1ProtectedParams = 0;
-constexpr int kCoseSign1UnprotectedParams = 1;
-constexpr int kCoseSign1Payload = 2;
-constexpr int kCoseSign1Signature = 3;
-
-constexpr int kCoseMac0EntryCount = 4;
-constexpr int kCoseMac0ProtectedParams = 0;
-constexpr int kCoseMac0UnprotectedParams = 1;
-constexpr int kCoseMac0Payload = 2;
-constexpr int kCoseMac0Tag = 3;
-
-constexpr int kCoseEncryptEntryCount = 4;
-constexpr int kCoseEncryptProtectedParams = 0;
-constexpr int kCoseEncryptUnprotectedParams = 1;
-constexpr int kCoseEncryptPayload = 2;
-constexpr int kCoseEncryptRecipients = 3;
-
-enum Label : int {
- ALGORITHM = 1,
- KEY_ID = 4,
- IV = 5,
- COSE_KEY = -1,
-};
-
-enum CoseKeyAlgorithm : int {
- AES_GCM_256 = 3,
- HMAC_256 = 5,
- ES256 = -7, // ECDSA with SHA-256
- EDDSA = -8,
- ECDH_ES_HKDF_256 = -25,
-};
-
-enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
-enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
-enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
-
-constexpr int kAesGcmNonceLength = 12;
-constexpr int kAesGcmTagSize = 16;
-constexpr int kAesGcmKeySize = 32;
-
-template <typename T>
-class ErrMsgOr {
- public:
- ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {}
- ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {}
- ErrMsgOr(T val) : value_(std::move(val)) {}
-
- operator bool() const { return value_.has_value(); }
-
- T* operator->() & {
- assert(value_);
- return &value_.value();
- }
- T& operator*() & {
- assert(value_);
- return value_.value();
- };
- T&& operator*() && {
- assert(value_);
- return std::move(value_).value();
- };
-
- const std::string& message() { return errMsg_; }
- std::string moveMessage() { return std::move(errMsg_); }
-
- T moveValue() {
- assert(value_);
- return std::move(value_).value();
- }
-
- private:
- std::string errMsg_;
- std::optional<T> value_;
-};
-
-class CoseKey {
- public:
- CoseKey() {}
- CoseKey(const CoseKey&) = delete;
- CoseKey(CoseKey&&) = default;
-
- enum Label : int {
- KEY_TYPE = 1,
- KEY_ID = 2,
- ALGORITHM = 3,
- KEY_OPS = 4,
- CURVE = -1,
- PUBKEY_X = -2,
- PUBKEY_Y = -3,
- PRIVATE_KEY = -4,
- TEST_KEY = -70000 // Application-defined
- };
-
- static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
- auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
- if (!parsedKey) return errMsg + " when parsing key";
- if (!parsedKey->asMap()) return "CoseKey must be a map";
- return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
- }
-
- static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
- CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
- auto key = parse(coseKey);
- if (!key) return key;
-
- if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
- !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
- !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
- return "Unexpected key type:";
- }
-
- return key;
- }
-
- static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
- auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
- if (!key) return key;
-
- auto& pubkey = key->getMap().get(PUBKEY_X);
- if (!pubkey || !pubkey->asBstr() ||
- pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
- return "Invalid Ed25519 public key";
- }
-
- return key;
- }
-
- static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
- auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
- if (!key) return key;
-
- auto& pubkey = key->getMap().get(PUBKEY_X);
- if (!pubkey || !pubkey->asBstr() ||
- pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
- return "Invalid X25519 public key";
- }
-
- auto& kid = key->getMap().get(KEY_ID);
- if (requireKid && (!kid || !kid->asBstr())) {
- return "Missing KID";
- }
-
- return key;
- }
-
- static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
- auto key = parse(coseKey, EC2, ES256, P256);
- if (!key) return key;
-
- auto& pubkey_x = key->getMap().get(PUBKEY_X);
- auto& pubkey_y = key->getMap().get(PUBKEY_Y);
- if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
- pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
- return "Invalid P256 public key";
- }
-
- return key;
- }
-
- std::optional<int> getIntValue(Label label) {
- const auto& value = key_->get(label);
- if (!value || !value->asInt()) return {};
- return value->asInt()->value();
- }
-
- std::optional<bytevec> getBstrValue(Label label) {
- const auto& value = key_->get(label);
- if (!value || !value->asBstr()) return {};
- return value->asBstr()->value();
- }
-
- const cppbor::Map& getMap() const { return *key_; }
- cppbor::Map&& moveMap() { return std::move(*key_); }
-
- bool checkIntValue(Label label, int expectedValue) {
- const auto& value = key_->get(label);
- return value && value->asInt() && value->asInt()->value() == expectedValue;
- }
-
- void add(Label label, int value) { key_->add(label, value); }
- void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
-
- bytevec encode() { return key_->canonicalize().encode(); }
-
- private:
- CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
-
- // This is the full parsed key structure.
- std::unique_ptr<cppbor::Map> key_;
-};
-
-ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
- const bytevec& payload);
-ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
- const bytevec& payload);
-ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem);
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
- const bytevec& macKey);
-
-ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
- const bytevec& payload, const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
- const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
- const bytevec& payload, const bytevec& aad);
-/**
- * Verify and parse a COSE_Sign1 message, returning the payload.
- *
- * @param ignoreSignature indicates whether signature verification should be skipped. If true, no
- * verification of the signature will be done.
- *
- * @param coseSign1 is the COSE_Sign1 to verify and parse.
- *
- * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature. The bytevec may
- * be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
- * use, i.e. that coseSign1 is a self-signed "certificate".
- */
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature,
- const cppbor::Array* coseSign1,
- const bytevec& signingCoseKey,
- const bytevec& aad);
-
-ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
- const bytevec& protectedParams, const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
- const bytevec& plaintextPayload, const bytevec& aad,
- cppbor::Array recipients);
-ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
- const cppbor::Item* encryptItem);
-inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
-getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
- return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
-}
-
-ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key,
- const cppbor::Item* encryptItem,
- const bytevec& aad);
-
-ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
- const bytevec& recipientPubKey, bool senderIsA);
-
-ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
- const bytevec& aad,
- const bytevec& plaintext);
-ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
- const bytevec& aad,
- const bytevec& ciphertextWithTag);
-
-} // namespace cppcose
diff --git a/security/keymint/support/include/keymint_support/keymint_tags.h b/security/keymint/support/include/keymint_support/keymint_tags.h
index ae21125..5b2a6f3 100644
--- a/security/keymint/support/include/keymint_support/keymint_tags.h
+++ b/security/keymint/support/include/keymint_support/keymint_tags.h
@@ -153,7 +153,7 @@
TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t,
TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t,
TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t,
- TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>;
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED_t, TAG_CERTIFICATE_SERIAL_t, TAG_CERTIFICATE_SUBJECT_t>;
template <typename TypedTagType>
struct TypedTag2ValueType;
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 5e205a2..e4261f3 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -18,7 +18,7 @@
#include <vector>
-#include <cppcose/cppcose.h>
+#include <keymaster/cppcose/cppcose.h>
namespace aidl::android::hardware::security::keymint::remote_prov {
diff --git a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
index 71b4278..2fbd29a 100644
--- a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
+++ b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
@@ -43,7 +43,7 @@
*
* where:
*
- * ``ISecureClock.TIME_STAMP_MAC_LABEL'' is a sting constant defined in ISecureClock.aidl.
+ * ``ISecureClock.TIME_STAMP_MAC_LABEL'' is a string constant defined in ISecureClock.aidl.
*
* ``H'' is the shared HMAC key (see computeSharedHmac() in ISharedSecret).
*
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
index 8cb259f..7431804 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
@@ -19,6 +19,6 @@
@VintfStability
parcelable CompositeEffect {
int delayMs;
- android.hardware.vibrator.CompositePrimitive primitive;
+ android.hardware.vibrator.CompositePrimitive primitive = android.hardware.vibrator.CompositePrimitive.NOOP;
float scale;
}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
index 406a899..5a990c0 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -22,7 +22,7 @@
parcelable CompositeEffect {
/* Period of silence preceding primitive. */
int delayMs;
- CompositePrimitive primitive;
+ CompositePrimitive primitive = CompositePrimitive.NOOP;
/*
* 0.0 (inclusive) - 1.0 (inclusive),
* where 0.0 is minimum "feelable" amplitude.
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
index 29bd9a9..61627d9 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
@@ -12,7 +12,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
@@ -37,6 +38,6 @@
android.hardware.weaver.WeaverReadResponse read(in int slotId, in byte[] key);
void write(in int slotId, in byte[] key, in byte[] value);
const int STATUS_FAILED = 1;
- const int INCORRECT_KEY = 2;
- const int THROTTLE = 3;
+ const int STATUS_INCORRECT_KEY = 2;
+ const int STATUS_THROTTLE = 3;
}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
index 239cdac..7491f32 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
@@ -12,7 +12,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
@@ -33,7 +34,7 @@
package android.hardware.weaver;
@VintfStability
parcelable WeaverConfig {
- long slots;
- long keySize;
- long valueSize;
+ int slots;
+ int keySize;
+ int valueSize;
}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 7e5db59..47ee4c8 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -12,7 +12,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *////////////////////////////////////////////////////////////////////////////////
+ */
+///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index ebbfabe..f51034a 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -46,8 +46,8 @@
* Read binder calls may return a ServiceSpecificException with the following error codes.
*/
const int STATUS_FAILED = 1;
- const int INCORRECT_KEY = 2;
- const int THROTTLE = 3;
+ const int STATUS_INCORRECT_KEY = 2;
+ const int STATUS_THROTTLE = 3;
/**
* Attempts to retrieve the value stored in the identified slot.
diff --git a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
index 75d961e..a156a7b 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
@@ -21,14 +21,14 @@
/**
* The number of slots available.
*/
- long slots;
+ int slots;
/**
* The number of bytes used for a key.
*/
- long keySize;
+ int keySize;
/**
* The number of bytes used for a value.
*/
- long valueSize;
+ int valueSize;
}
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
index 7d8daa2..878c762 100644
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
@@ -156,7 +156,7 @@
ASSERT_FALSE(readRet.isOk());
ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
- ASSERT_EQ(IWeaver::INCORRECT_KEY, readRet.getServiceSpecificError());
+ ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
EXPECT_TRUE(readValue.empty());
}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
index e4fe52c..bdca32c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -25,6 +25,7 @@
#include "supplicant_hidl_call_util.h"
#include "supplicant_hidl_test_utils.h"
+#include <cutils/properties.h>
using ::android::sp;
using ::android::hardware::hidl_array;
@@ -61,7 +62,7 @@
constexpr uint32_t kTestRadioWorkFrequency = 2412;
constexpr uint32_t kTestRadioWorkTimeout = 8;
constexpr uint32_t kTestRadioWorkId = 16;
-constexpr int8_t kTestCountryCode[] = {'U', 'S'};
+int8_t kTestCountryCode[] = {'U', 'S'};
constexpr uint8_t kTestWpsDeviceType[] = {[0 ... 7] = 0x01};
constexpr uint16_t kTestWpsConfigMethods = 0xffff;
} // namespace
@@ -454,6 +455,10 @@
* SetCountryCode.
*/
TEST_P(SupplicantStaIfaceHidlTest, SetCountryCode) {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+ property_get("ro.boot.wificountrycode", buffer.data(), "US");
+ kTestCountryCode[0] = buffer.data()[0];
+ kTestCountryCode[1] = buffer.data()[1];
sta_iface_->setCountryCode(
kTestCountryCode, [](const SupplicantStatus& status) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);