xref: /aosp_15_r20/system/secretkeeper/hal/src/lib.rs (revision 3f8e9d82f4020c68ad19a99fc5fdc1fc90b79379)
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