mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge changes from topic "sk_hal" into main
* changes: VTS test for ISecretkeeper Secretkeeper implementation: in-HAL/nonsecure impl Introduce Secretkeeper HAL interface
This commit is contained in:
@@ -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>
|
||||
|
||||
36
security/secretkeeper/aidl/Android.bp
Normal file
36
security/secretkeeper/aidl/Android.bp
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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"],
|
||||
}
|
||||
|
||||
aidl_interface {
|
||||
name: "android.hardware.security.secretkeeper",
|
||||
vendor_available: true,
|
||||
srcs: ["android/hardware/security/secretkeeper/*.aidl"],
|
||||
stability: "vintf",
|
||||
backend: {
|
||||
ndk: {
|
||||
enabled: true,
|
||||
},
|
||||
rust: {
|
||||
enabled: true,
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.virt",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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.secretkeeper;
|
||||
@VintfStability
|
||||
interface ISecretkeeper {
|
||||
byte[] processSecretManagementRequest(in byte[] request);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 android.hardware.security.secretkeeper;
|
||||
|
||||
@VintfStability
|
||||
/**
|
||||
* Secretkeeper service definition.
|
||||
*
|
||||
* An ISecretkeeper instance provides secure storage of secrets on behalf of other components in
|
||||
* Android, in particular for protected virtual machine instances. From the perspective of security
|
||||
* privilege, Secretkeeper must be implemented in an environment with privilege higher than any of
|
||||
* its clients. Since AVF based protected Virtual Machines are one set of its clients, the
|
||||
* implementation of ISecretkeeper should live in a secure environment, such as:
|
||||
* - A trusted execution environment such as ARM TrustZone.
|
||||
* - A completely separate, purpose-built and certified secure CPU.
|
||||
*
|
||||
* TODO(b/291224769): Extend the HAL interface to include:
|
||||
* 1. Session setup api: This is used to perform cryptographic operations that allow shared keys to
|
||||
* be exchanged between session participants, typically (but not necessarily) a pVM instance and
|
||||
* Secretkeeper. This session setup is based on public key cryptography.
|
||||
* 2. Dice policy operation - These allow sealing of the secrets with a class of Dice chains.
|
||||
* Typical operations are (securely) updating the dice policy sealing the Secrets above. These
|
||||
* operations are core to AntiRollback protected secrets - ie, ensuring secrets of a pVM are only
|
||||
* accessible to same or higher versions of the images.
|
||||
* 3. Maintenance api: This is required for removing the Secretkeeper entries for obsolete pvMs.
|
||||
*/
|
||||
interface ISecretkeeper {
|
||||
/**
|
||||
* processSecretManagementRequest method is used for interacting with the Secret Management API
|
||||
*
|
||||
* Secret Management API: The clients can use this API to store (& get) 32 bytes of data.
|
||||
* The API is a CBOR based protocol, which follows request/response model.
|
||||
* See SecretManagement.cddl for the API spec.
|
||||
*
|
||||
* Further, the requests (from client) & responses (from service) must be encrypted into
|
||||
* ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
|
||||
* the client & service. This cryptographic protection is required because the messages are
|
||||
* ferried via Android, which is allowed to be outside the TCB of clients (for example protected
|
||||
* Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
|
||||
* is critical for establishing the secure channel.
|
||||
*
|
||||
* Secretkeeper database should guarantee the following properties:
|
||||
* 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
|
||||
* be able to get a client's data in clear.
|
||||
*
|
||||
* 2. Integrity: The data is protected against malicious Android OS tampering with database.
|
||||
* ie, if Android (userspace & kernel) tampers with the client's secret, the Secretkeeper
|
||||
* service must be able to detect it & return error when clients requests for their secrets.
|
||||
* Note: the integrity requirements also include Antirollback protection ie, reverting the
|
||||
* database into an old state should be detected.
|
||||
*
|
||||
* 3. The data is persistent across device boot.
|
||||
* Note: Denial of service is not in scope. A malicious Android may be able to delete data,
|
||||
* but for ideal Android, the data should be persistent.
|
||||
*
|
||||
* @param CBOR-encoded ProtectedRequestPacket. See SecretManagement.cddl for its definition.
|
||||
* @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
|
||||
*/
|
||||
byte[] processSecretManagementRequest(in byte[] request);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
; CDDL for the Secret Management API.
|
||||
; Also see processSecretManagementRequest method in ISecretkeeper.aidl
|
||||
|
||||
; ProtectedRequestPacket is used by client for accessing Secret Management API
|
||||
; in Secretkeeper service. The service returns ProtectedResponsePacket of the corresponding type.
|
||||
|
||||
; ProtectedRequestPacket & ProtectedResponsePacket are encrypted wrappers
|
||||
; on RequestPacket & ResponsePacket using symmetric keys agreed between Secretkeeper & clients
|
||||
; (these are referred to as KeySourceToSink & KeySinkToSource)
|
||||
;
|
||||
; The API operation required is encoded using 'Opcode', the arguments using 'Params'
|
||||
; and returned values as 'Result'.
|
||||
|
||||
ProtectedRequestPacket =
|
||||
ProtectedGetVersionRequest / ProtectedStoreSecretRequest / ProtectedGetSecretRequest
|
||||
ProtectedResponsePacket =
|
||||
ProtectedGetVersionResponse / ProtectedStoreSecretResponse / ProtectedGetSecretResponse
|
||||
|
||||
ProtectedGetVersionRequest = ProtectedRequestPacket<GetVersionRequestPacket>
|
||||
ProtectedGetVersionResponse = ProtectedResponsePacket<GetVersionResponsePacket>
|
||||
ProtectedStoreSecretRequest = ProtectedRequestPacket<StoreSecretRequestPacket>
|
||||
ProtectedStoreSecretResponse = ProtectedResponsePacket<StoreSecretResponsePacket>
|
||||
ProtectedGetSecretRequest = ProtectedRequestPacket<GetSecretRequestPacket>
|
||||
ProtectedGetSecretResponse = ProtectedResponsePacket<GetSecretResponsePacket>
|
||||
|
||||
GetVersionRequestPacket = RequestPacket<GetVersionOpcode, GetVersionParams>
|
||||
GetVersionResponsePacket = ResponsePacket<GetVersionResult>
|
||||
StoreSecretRequestPacket = RequestPacket<StoreSecretOpcode, StoreSecretParams>
|
||||
StoreSecretResponsePacket = ResponsePacket<StoreSecretResult>
|
||||
GetSecretRequestPacket = RequestPacket<GetOpcode, GetSecretParams>
|
||||
GetSecretResponsePacket = ResponsePacket<GetSecretResult>
|
||||
|
||||
RequestPacket<Opcode, Params> = [
|
||||
Opcode,
|
||||
Params
|
||||
]
|
||||
ResponsePacket<Result> = ResponsePacketError / ResponsePacketSuccess<Result>
|
||||
|
||||
ResponsePacketSuccess = [
|
||||
0, ; Indicates successful Response
|
||||
result : Result
|
||||
]
|
||||
ResponsePacketError = [
|
||||
error_code: ErrorCode, ; Indicate the error
|
||||
error_message: tstr ; Additional human-readable context
|
||||
]
|
||||
|
||||
Opcode = &(
|
||||
GetVersionOpcode: 1, ; Get version of the SecretManagement API
|
||||
StoreSecretOpcode: 2, ; Store a secret
|
||||
GetSecretOpcode: 3, ; Get the secret
|
||||
)
|
||||
|
||||
GetVersionParams = ()
|
||||
GetVersionResult = (version : uint)
|
||||
|
||||
StoreSecretParams = (
|
||||
id : bstr .size 64 ; Unique identifier of the secret
|
||||
secret : bstr .size 32,
|
||||
sealing_policy : bstr .cbor DicePolicy, ; See DicePolicy.cddl for definition of DicePolicy
|
||||
)
|
||||
StoreSecretResult = ()
|
||||
|
||||
GetSecretParams = (
|
||||
id : bstr .size 64 ; Unique identifier of the secret
|
||||
; Use this to update the sealing policy associated with a secret during GetSecret operation.
|
||||
updated_sealing_policy : bstr .cbor DicePolicy / nil,
|
||||
)
|
||||
GetSecretResult = (secret : bstr .size 32)
|
||||
|
||||
|
||||
ProtectedRequestPacket<Payload, Key> = CryptoPayload<Payload, KeySourceToSink>
|
||||
ProtectedResponsePacket<Payload, Key> = ProtectedResponseError
|
||||
/ ProtectedResponseSuccess<Payload>
|
||||
|
||||
ProtectedResponseSuccess<Payload> = [
|
||||
0, ; Indicates successful crypto operations. Note: Payload
|
||||
; may contain Error from functional layer.
|
||||
message: CryptoPayload<Payload, KeySinkToSource> ; message is the encrypted payload
|
||||
]
|
||||
|
||||
ProtectedResponseError = [
|
||||
error_code: CryptoErrorCode, ; Indicates the error. This is in cleartext & will be
|
||||
; visible to Android. These are errors from crypto
|
||||
; layer & indicates the request could not even be read
|
||||
message: tstr ; Additional human-readable context
|
||||
]
|
||||
|
||||
CryptoPayload<Payload, Key> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
|
||||
protected: bstr .cbor {
|
||||
1 : 3, ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
|
||||
4 : bstr ; key identifier, uniquely identifies the session
|
||||
; TODO(b/291228560): Refer to the Key Exchange spec.
|
||||
},
|
||||
unprotected: {
|
||||
5 : bstr .size 12 ; IV
|
||||
},
|
||||
ciphertext : bstr ; AES-GCM-256(Key, bstr .cbor Payload)
|
||||
; AAD for the encryption is CBOR-serialized
|
||||
; Enc_structure (RFC 9052 s5.3) with empty external_aad.
|
||||
]
|
||||
|
||||
; TODO(b/291224769): Create a more exhaustive set of CryptoErrorCode
|
||||
CryptoErrorCode = &(
|
||||
CryptoErrorCode_SessionExpired: 1,
|
||||
)
|
||||
|
||||
; TODO(b/291224769): Create a more exhaustive set of ErrorCodes
|
||||
ErrorCode = &(
|
||||
; Use this as if no other error code can be used.
|
||||
ErrorCode_UnexpectedServerError: 1,
|
||||
; Indicate the Request was malformed & hence couldnt be served.
|
||||
ErrorCode_RequestMalformed: 2,
|
||||
)
|
||||
|
||||
; INCLUDE DicePolicy.cddl for: DicePolicy
|
||||
35
security/secretkeeper/aidl/vts/Android.bp
Normal file
35
security/secretkeeper/aidl/vts/Android.bp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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_test {
|
||||
name: "VtsSecretkeeperTargetTest",
|
||||
srcs: ["secretkeeper_test_client.rs"],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
rustlibs: [
|
||||
"libsecretkeeper_comm_nostd",
|
||||
"android.hardware.security.secretkeeper-V1-rust",
|
||||
"libbinder_rs",
|
||||
"liblog_rust",
|
||||
],
|
||||
require_root: true,
|
||||
}
|
||||
109
security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
Normal file
109
security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
use binder::StatusCode;
|
||||
use log::warn;
|
||||
use secretkeeper_comm::data_types::error::SecretkeeperError;
|
||||
use secretkeeper_comm::data_types::request::Request;
|
||||
use secretkeeper_comm::data_types::request_response_impl::{
|
||||
GetVersionRequest, GetVersionResponse,
|
||||
};
|
||||
use secretkeeper_comm::data_types::response::Response;
|
||||
use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
|
||||
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
|
||||
|
||||
const SECRETKEEPER_IDENTIFIER: &str =
|
||||
"android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
|
||||
const CURRENT_VERSION: u64 = 1;
|
||||
|
||||
fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
|
||||
match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
|
||||
Ok(sk) => Some(sk),
|
||||
Err(StatusCode::NAME_NOT_FOUND) => None,
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"unexpected error while fetching connection to Secretkeeper {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
|
||||
// with expected bytes.
|
||||
|
||||
#[test]
|
||||
fn secret_management_get_version() {
|
||||
let secretkeeper = match get_connection() {
|
||||
Some(sk) => sk,
|
||||
None => {
|
||||
warn!("Secretkeeper HAL is unavailable, skipping test");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let request = GetVersionRequest {};
|
||||
let request_packet = request.serialize_to_packet();
|
||||
let request_bytes = request_packet.into_bytes().unwrap();
|
||||
|
||||
// TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
|
||||
// with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
|
||||
|
||||
let response_bytes = secretkeeper
|
||||
.processSecretManagementRequest(&request_bytes)
|
||||
.unwrap();
|
||||
|
||||
let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
|
||||
assert_eq!(
|
||||
response_packet.response_type().unwrap(),
|
||||
ResponseType::Success
|
||||
);
|
||||
let get_version_response =
|
||||
*GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
|
||||
assert_eq!(get_version_response.version(), CURRENT_VERSION);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secret_management_malformed_request() {
|
||||
let secretkeeper = match get_connection() {
|
||||
Some(sk) => sk,
|
||||
None => {
|
||||
warn!("Secretkeeper HAL is unavailable, skipping test");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let request = GetVersionRequest {};
|
||||
let request_packet = request.serialize_to_packet();
|
||||
let mut request_bytes = request_packet.into_bytes().unwrap();
|
||||
|
||||
// Deform the request
|
||||
request_bytes[0] = !request_bytes[0];
|
||||
|
||||
// TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
|
||||
// with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
|
||||
|
||||
let response_bytes = secretkeeper
|
||||
.processSecretManagementRequest(&request_bytes)
|
||||
.unwrap();
|
||||
|
||||
let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
|
||||
assert_eq!(
|
||||
response_packet.response_type().unwrap(),
|
||||
ResponseType::Error
|
||||
);
|
||||
let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
|
||||
assert_eq!(err, SecretkeeperError::RequestMalformed);
|
||||
}
|
||||
37
security/secretkeeper/default/Android.bp
Normal file
37
security/secretkeeper/default/Android.bp
Normal file
@@ -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",
|
||||
],
|
||||
}
|
||||
5
security/secretkeeper/default/secretkeeper.rc
Normal file
5
security/secretkeeper/default/secretkeeper.rc
Normal file
@@ -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
|
||||
28
security/secretkeeper/default/secretkeeper.xml
Normal file
28
security/secretkeeper/default/secretkeeper.xml
Normal file
@@ -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>
|
||||
121
security/secretkeeper/default/src/main.rs
Normal file
121
security/secretkeeper/default/src/main.rs
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user