1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 //! Crate that holds common code for a Secretkeeper HAL service.
18
19 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::{
20 ISecretkeeper::{
21 ISecretkeeper, BnSecretkeeper
22 },
23 SecretId::SecretId as AidlSecretId,
24 };
25 #[cfg(feature = "hal_v2")]
26 use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::PublicKey::PublicKey;
27 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
28 IAuthGraphKeyExchange::IAuthGraphKeyExchange,
29 };
30 use authgraph_hal::channel::SerializedChannel;
31 use authgraph_hal::service::AuthGraphService;
32 use coset::CborSerializable;
33 use secretkeeper_comm::wire::{PerformOpSuccessRsp, PerformOpResponse, ApiError, PerformOpReq, AidlErrorCode, SecretId};
34 use std::ffi::CString;
35
36 /// Implementation of the Secretkeeper HAL service, communicating with a TA
37 /// in a secure environment via a communication channel.
38 pub struct SecretkeeperService<T: SerializedChannel + 'static> {
39 authgraph: binder::Strong<dyn IAuthGraphKeyExchange>,
40 channel: T,
41 }
42
43 impl<T: SerializedChannel + 'static> SecretkeeperService<T> {
44 /// Construct a new instance that uses the provided channels.
new<S: SerializedChannel + 'static>(sk_channel: T, ag_channel: S) -> Self45 pub fn new<S: SerializedChannel + 'static>(sk_channel: T, ag_channel: S) -> Self {
46 Self { authgraph: AuthGraphService::new_as_binder(ag_channel), channel: sk_channel }
47 }
48
49 /// Create a new instance wrapped in a proxy object.
new_as_binder<S: SerializedChannel + 'static>( sk_channel: T, ag_channel: S, ) -> binder::Strong<dyn ISecretkeeper>50 pub fn new_as_binder<S: SerializedChannel + 'static>(
51 sk_channel: T,
52 ag_channel: S,
53 ) -> binder::Strong<dyn ISecretkeeper> {
54 BnSecretkeeper::new_binder(
55 Self::new(sk_channel, ag_channel),
56 binder::BinderFeatures::default(),
57 )
58 }
59 }
60
61 impl<T: SerializedChannel> binder::Interface for SecretkeeperService<T> {}
62
63 /// Implement the `ISecretkeeper` interface.
64 impl<T: SerializedChannel> ISecretkeeper for SecretkeeperService<T> {
processSecretManagementRequest(&self, req: &[u8]) -> binder::Result<Vec<u8>>65 fn processSecretManagementRequest(&self, req: &[u8]) -> binder::Result<Vec<u8>> {
66 let wrapper = PerformOpReq::SecretManagement(req.to_vec());
67 let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
68 let rsp_data = self.channel.execute(&wrapper_data)?;
69 let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
70 match rsp {
71 PerformOpResponse::Success(PerformOpSuccessRsp::ProtectedResponse(data)) => Ok(data),
72 PerformOpResponse::Success(_) => Err(unexpected_response_type()),
73 PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
74 }
75 }
76
getAuthGraphKe(&self) -> binder::Result<binder::Strong<dyn IAuthGraphKeyExchange>>77 fn getAuthGraphKe(&self) -> binder::Result<binder::Strong<dyn IAuthGraphKeyExchange>> {
78 Ok(self.authgraph.clone())
79 }
80
deleteIds(&self, ids: &[AidlSecretId]) -> binder::Result<()>81 fn deleteIds(&self, ids: &[AidlSecretId]) -> binder::Result<()> {
82 let ids: Vec<SecretId> = ids
83 .iter()
84 .map(|id| SecretId::try_from(id.id.as_slice()))
85 .collect::<Result<Vec<_>, _>>()
86 .map_err(|_e| {
87 binder::Status::new_exception(
88 binder::ExceptionCode::ILLEGAL_ARGUMENT,
89 Some(&std::ffi::CString::new("secret ID of wrong length".to_string()).unwrap()),
90 )
91 })?;
92 let wrapper = PerformOpReq::DeleteIds(ids);
93 let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
94 let rsp_data = self.channel.execute(&wrapper_data)?;
95 let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
96 match rsp {
97 PerformOpResponse::Success(PerformOpSuccessRsp::Empty) => Ok(()),
98 PerformOpResponse::Success(_) => Err(unexpected_response_type()),
99 PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
100 }
101 }
102
deleteAll(&self) -> binder::Result<()>103 fn deleteAll(&self) -> binder::Result<()> {
104 let wrapper = PerformOpReq::DeleteAll;
105 let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
106 let rsp_data = self.channel.execute(&wrapper_data)?;
107 let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
108 match rsp {
109 PerformOpResponse::Success(PerformOpSuccessRsp::Empty) => Ok(()),
110 PerformOpResponse::Success(_) => Err(unexpected_response_type()),
111 PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
112 }
113 }
114
115 #[cfg(feature = "hal_v2")]
getSecretkeeperIdentity(&self) -> binder::Result<PublicKey>116 fn getSecretkeeperIdentity(&self) -> binder::Result<PublicKey> {
117 let wrapper = PerformOpReq::GetSecretkeeperIdentity;
118 let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
119 let rsp_data = self.channel.execute(&wrapper_data)?;
120 let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
121 match rsp {
122 PerformOpResponse::Success(PerformOpSuccessRsp::ProtectedResponse(data)) => {
123 Ok(PublicKey { keyMaterial: data })
124 }
125 PerformOpResponse::Success(_) => Err(unexpected_response_type()),
126 PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
127 }
128 }
129 }
130
131 /// Emit a failure for a failed CBOR conversion.
failed_cbor(err: coset::CoseError) -> binder::Status132 fn failed_cbor(err: coset::CoseError) -> binder::Status {
133 binder::Status::new_exception(
134 binder::ExceptionCode::BAD_PARCELABLE,
135 Some(&std::ffi::CString::new(format!("CBOR conversion failed: {err:?}")).unwrap()),
136 )
137 }
138
139 /// Emit a service specific error.
service_specific_error(err: ApiError) -> binder::Status140 fn service_specific_error(err: ApiError) -> binder::Status {
141 binder::Status::new_service_specific_error(
142 err.err_code as i32,
143 Some(&CString::new(err.msg).unwrap()),
144 )
145 }
146
147 /// Emit an error indicating an unexpected type of response received from the TA.
unexpected_response_type() -> binder::Status148 fn unexpected_response_type() -> binder::Status {
149 service_specific_error(ApiError {
150 err_code: AidlErrorCode::InternalError,
151 msg: "unexpected response type".to_string(),
152 })
153 }
154