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 use android_hardware_security_authgraph::aidl::android::hardware::security::authgraph::{
26     IAuthGraphKeyExchange::IAuthGraphKeyExchange,
27 };
28 use authgraph_hal::channel::SerializedChannel;
29 use authgraph_hal::service::AuthGraphService;
30 use coset::CborSerializable;
31 use secretkeeper_comm::wire::{PerformOpSuccessRsp, PerformOpResponse, ApiError, PerformOpReq, AidlErrorCode, SecretId};
32 use std::ffi::CString;
33 
34 /// Implementation of the Secretkeeper HAL service, communicating with a TA
35 /// in a secure environment via a communication channel.
36 pub struct SecretkeeperService<T: SerializedChannel + 'static> {
37     authgraph: binder::Strong<dyn IAuthGraphKeyExchange>,
38     channel: T,
39 }
40 
41 impl<T: SerializedChannel + 'static> SecretkeeperService<T> {
42     /// Construct a new instance that uses the provided channels.
new<S: SerializedChannel + 'static>(sk_channel: T, ag_channel: S) -> Self43     pub fn new<S: SerializedChannel + 'static>(sk_channel: T, ag_channel: S) -> Self {
44         Self { authgraph: AuthGraphService::new_as_binder(ag_channel), channel: sk_channel }
45     }
46 
47     /// 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>48     pub fn new_as_binder<S: SerializedChannel + 'static>(
49         sk_channel: T,
50         ag_channel: S,
51     ) -> binder::Strong<dyn ISecretkeeper> {
52         BnSecretkeeper::new_binder(
53             Self::new(sk_channel, ag_channel),
54             binder::BinderFeatures::default(),
55         )
56     }
57 }
58 
59 impl<T: SerializedChannel> binder::Interface for SecretkeeperService<T> {}
60 
61 /// Implement the `ISecretkeeper` interface.
62 impl<T: SerializedChannel> ISecretkeeper for SecretkeeperService<T> {
processSecretManagementRequest(&self, req: &[u8]) -> binder::Result<Vec<u8>>63     fn processSecretManagementRequest(&self, req: &[u8]) -> binder::Result<Vec<u8>> {
64         let wrapper = PerformOpReq::SecretManagement(req.to_vec());
65         let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
66         let rsp_data = self.channel.execute(&wrapper_data)?;
67         let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
68         match rsp {
69             PerformOpResponse::Success(PerformOpSuccessRsp::ProtectedResponse(data)) => Ok(data),
70             PerformOpResponse::Success(_) => Err(unexpected_response_type()),
71             PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
72         }
73     }
74 
getAuthGraphKe(&self) -> binder::Result<binder::Strong<dyn IAuthGraphKeyExchange>>75     fn getAuthGraphKe(&self) -> binder::Result<binder::Strong<dyn IAuthGraphKeyExchange>> {
76         Ok(self.authgraph.clone())
77     }
78 
deleteIds(&self, ids: &[AidlSecretId]) -> binder::Result<()>79     fn deleteIds(&self, ids: &[AidlSecretId]) -> binder::Result<()> {
80         let ids: Vec<SecretId> = ids
81             .iter()
82             .map(|id| SecretId::try_from(id.id.as_slice()))
83             .collect::<Result<Vec<_>, _>>()
84             .map_err(|_e| {
85                 binder::Status::new_exception(
86                     binder::ExceptionCode::ILLEGAL_ARGUMENT,
87                     Some(&std::ffi::CString::new("secret ID of wrong length".to_string()).unwrap()),
88                 )
89             })?;
90         let wrapper = PerformOpReq::DeleteIds(ids);
91         let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
92         let rsp_data = self.channel.execute(&wrapper_data)?;
93         let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
94         match rsp {
95             PerformOpResponse::Success(PerformOpSuccessRsp::Empty) => Ok(()),
96             PerformOpResponse::Success(_) => Err(unexpected_response_type()),
97             PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
98         }
99     }
100 
deleteAll(&self) -> binder::Result<()>101     fn deleteAll(&self) -> binder::Result<()> {
102         let wrapper = PerformOpReq::DeleteAll;
103         let wrapper_data = wrapper.to_vec().map_err(failed_cbor)?;
104         let rsp_data = self.channel.execute(&wrapper_data)?;
105         let rsp = PerformOpResponse::from_slice(&rsp_data).map_err(failed_cbor)?;
106         match rsp {
107             PerformOpResponse::Success(PerformOpSuccessRsp::Empty) => Ok(()),
108             PerformOpResponse::Success(_) => Err(unexpected_response_type()),
109             PerformOpResponse::Failure(err) => Err(service_specific_error(err)),
110         }
111     }
112 }
113 
114 /// Emit a failure for a failed CBOR conversion.
failed_cbor(err: coset::CoseError) -> binder::Status115 fn failed_cbor(err: coset::CoseError) -> binder::Status {
116     binder::Status::new_exception(
117         binder::ExceptionCode::BAD_PARCELABLE,
118         Some(&std::ffi::CString::new(format!("CBOR conversion failed: {err:?}")).unwrap()),
119     )
120 }
121 
122 /// Emit a service specific error.
service_specific_error(err: ApiError) -> binder::Status123 fn service_specific_error(err: ApiError) -> binder::Status {
124     binder::Status::new_service_specific_error(
125         err.err_code as i32,
126         Some(&CString::new(err.msg).unwrap()),
127     )
128 }
129 
130 /// Emit an error indicating an unexpected type of response received from the TA.
unexpected_response_type() -> binder::Status131 fn unexpected_response_type() -> binder::Status {
132     service_specific_error(ApiError {
133         err_code: AidlErrorCode::InternalError,
134         msg: "unexpected response type".to_string(),
135     })
136 }
137