Secretkeeper implementation: in-HAL/nonsecure impl
Create the default/reference implementation of Secretkeeper HAL. Status
quo, this is non-secure implementation. In reality, the HAL should be
backed by a privileged component such a trusted app.
Bug: 291224769
Test: Topic includes VTS
Change-Id: I6a4ad50482d537f5438de6201275f4020cd827df
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 83d2665..9f6b78b 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -302,6 +302,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.security.secretkeeper</name>
+ <version>1</version>
+ <interface>
+ <name>ISecretkeeper</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
<hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.security.keymint</name>
<version>1-3</version>
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..1c39fa6
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+ name: "android.hardware.security.secretkeeper-service.nonsecure",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["secretkeeper.rc"],
+ vintf_fragments: ["secretkeeper.xml"],
+ rustlibs: [
+ "android.hardware.security.secretkeeper-V1-rust",
+ "libandroid_logger",
+ "libbinder_rs",
+ "liblog_rust",
+ "libsecretkeeper_comm_nostd",
+ ],
+ srcs: [
+ "src/main.rs",
+ ],
+}
diff --git a/security/secretkeeper/default/secretkeeper.rc b/security/secretkeeper/default/secretkeeper.rc
new file mode 100644
index 0000000..f39f9b7
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.rc
@@ -0,0 +1,5 @@
+service vendor.secretkeeper /vendor/bin/hw/android.hardware.security.secretkeeper-service.nonsecure
+ interface aidl android.hardware.security.secretkeeper.ISecretkeeper/nonsecure
+ class hal
+ user nobody
+ group nobody
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
new file mode 100644
index 0000000..40aebe0
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -0,0 +1,28 @@
+<manifest version="1.0" type="device">
+<!--
+/*
+** Copyright 2022, 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.
+*/
+-->
+
+ <hal format="aidl">
+ <name>android.hardware.security.secretkeeper</name>
+ <version>1</version>
+ <interface>
+ <name>ISecretkeeper</name>
+ <instance>nonsecure</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..2d367c5
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+use binder::{BinderFeatures, Interface};
+use log::{error, info, Level};
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::packet::{RequestPacket, ResponsePacket};
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+ GetVersionRequest, GetVersionResponse, Opcode,
+};
+use secretkeeper_comm::data_types::response::Response;
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+ BnSecretkeeper, BpSecretkeeper, ISecretkeeper,
+};
+
+const CURRENT_VERSION: u64 = 1;
+
+#[derive(Debug, Default)]
+pub struct NonSecureSecretkeeper;
+
+impl Interface for NonSecureSecretkeeper {}
+
+impl ISecretkeeper for NonSecureSecretkeeper {
+ fn processSecretManagementRequest(&self, request: &[u8]) -> binder::Result<Vec<u8>> {
+ Ok(self.process_opaque_request(request))
+ }
+}
+
+impl NonSecureSecretkeeper {
+ // A set of requests to Secretkeeper are 'opaque' - encrypted bytes with inner structure
+ // described by CDDL. They need to be decrypted, deserialized and processed accordingly.
+ fn process_opaque_request(&self, request: &[u8]) -> Vec<u8> {
+ // TODO(b/291224769) The request will need to be decrypted & response need to be encrypted
+ // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+ self.process_opaque_request_unhandled_error(request)
+ .unwrap_or_else(
+ // SecretkeeperError is also a valid 'Response', serialize to a response packet.
+ |sk_err| {
+ Response::serialize_to_packet(&sk_err)
+ .into_bytes()
+ .expect("Panicking due to serialization failing")
+ },
+ )
+ }
+
+ fn process_opaque_request_unhandled_error(
+ &self,
+ request: &[u8],
+ ) -> Result<Vec<u8>, SecretkeeperError> {
+ let request_packet = RequestPacket::from_bytes(request).map_err(|e| {
+ error!("Failed to get Request packet from bytes: {:?}", e);
+ SecretkeeperError::RequestMalformed
+ })?;
+ let response_packet = match request_packet
+ .opcode()
+ .map_err(|_| SecretkeeperError::RequestMalformed)?
+ {
+ Opcode::GetVersion => Self::process_get_version_request(request_packet)?,
+ _ => todo!("TODO(b/291224769): Unimplemented operations"),
+ };
+
+ response_packet
+ .into_bytes()
+ .map_err(|_| SecretkeeperError::UnexpectedServerError)
+ }
+
+ fn process_get_version_request(
+ request: RequestPacket,
+ ) -> Result<ResponsePacket, SecretkeeperError> {
+ // Deserialization really just verifies the structural integrity of the request such
+ // as args being empty.
+ let _request = GetVersionRequest::deserialize_from_packet(request)
+ .map_err(|_| SecretkeeperError::RequestMalformed)?;
+ let response = GetVersionResponse::new(CURRENT_VERSION);
+ Ok(response.serialize_to_packet())
+ }
+}
+
+fn main() {
+ // Initialize Android logging.
+ android_logger::init_once(
+ android_logger::Config::default()
+ .with_tag("NonSecureSecretkeeper")
+ .with_min_level(Level::Info)
+ .with_log_id(android_logger::LogId::System),
+ );
+ // Redirect panic messages to logcat.
+ std::panic::set_hook(Box::new(|panic_info| {
+ error!("{}", panic_info);
+ }));
+
+ let service = NonSecureSecretkeeper::default();
+ let service_binder = BnSecretkeeper::new_binder(service, BinderFeatures::default());
+ let service_name = format!(
+ "{}/nonsecure",
+ <BpSecretkeeper as ISecretkeeper>::get_descriptor()
+ );
+ binder::add_service(&service_name, service_binder.as_binder()).unwrap_or_else(|e| {
+ panic!(
+ "Failed to register service {} because of {:?}.",
+ service_name, e
+ );
+ });
+ info!("Registered Binder service, joining threadpool.");
+ binder::ProcessState::join_thread_pool();
+}