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