1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Implementation of the `IHwCryptoOperations` AIDL interface. It can be use to retrieve the
18 //! key generation interface and to process cryptographic operations.
19 
20 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{
21     CryptoOperationErrorAdditionalInfo::CryptoOperationErrorAdditionalInfo,
22     CryptoOperationResult::CryptoOperationResult, CryptoOperationSet::CryptoOperationSet,
23     IHwCryptoOperations::BnHwCryptoOperations, IHwCryptoOperations::IHwCryptoOperations,
24 };
25 use android_hardware_security_see_hwcrypto::binder;
26 use hwcryptohal_common::hwcrypto_err;
27 
28 use crate::cmd_processing::CmdProcessorContext;
29 use crate::crypto_operation_context::{BinderCryptoOperationContext, CryptoOperationContext};
30 
31 /// The `IHwCryptoOperations` implementation.
32 pub struct HwCryptoOperations;
33 
34 impl binder::Interface for HwCryptoOperations {}
35 
36 impl HwCryptoOperations {
new_binder() -> binder::Strong<dyn IHwCryptoOperations>37     pub(crate) fn new_binder() -> binder::Strong<dyn IHwCryptoOperations> {
38         let hwcrypto_operations = HwCryptoOperations;
39         BnHwCryptoOperations::new_binder(hwcrypto_operations, binder::BinderFeatures::default())
40     }
41 }
42 
43 impl IHwCryptoOperations for HwCryptoOperations {
processCommandList( &self, command_lists: &mut std::vec::Vec<CryptoOperationSet>, _additional_error_info: &mut CryptoOperationErrorAdditionalInfo, ) -> binder::Result<Vec<CryptoOperationResult>>44     fn processCommandList(
45         &self,
46         command_lists: &mut std::vec::Vec<CryptoOperationSet>,
47         _additional_error_info: &mut CryptoOperationErrorAdditionalInfo,
48     ) -> binder::Result<Vec<CryptoOperationResult>> {
49         let mut results = Vec::<CryptoOperationResult>::new();
50         for command_list in command_lists {
51             results.try_reserve(1).map_err(|e| {
52                 hwcrypto_err!(ALLOCATION_ERROR, "couldn't grow result vector: {:?}", e)
53             })?;
54             results.push(CryptoOperationResult { context: None });
55             match &command_list.context {
56                 None => {
57                     let mut cmd_processor = CmdProcessorContext::new();
58                     cmd_processor.process_all_steps(&mut command_list.operations)?;
59                     if !cmd_processor.is_destroyed() {
60                         let operation_context = CryptoOperationContext::new_binder(cmd_processor);
61                         (*results
62                             .last_mut()
63                             .expect("shouldn't happen, we pushed an element before match"))
64                         .context = Some(operation_context);
65                     }
66                 }
67                 Some(operation_context) => {
68                     BinderCryptoOperationContext::from(operation_context.clone())
69                         .process_all_steps(&mut command_list.operations)?;
70                 }
71             }
72         }
73         Ok(results)
74     }
75 }
76 
77 #[cfg(test)]
78 mod tests {
79     use super::*;
80     use crate::hwcrypto_ipc_server::RUST_SERVICE_PORT;
81     use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{
82         types::{
83             AesCipherMode::AesCipherMode, CipherModeParameters::CipherModeParameters,
84             HmacOperationParameters::HmacOperationParameters, KeyLifetime::KeyLifetime,
85             KeyType::KeyType, KeyUse::KeyUse, OperationData::OperationData,
86             SymmetricCryptoParameters::SymmetricCryptoParameters,
87             SymmetricOperation::SymmetricOperation,
88             SymmetricOperationParameters::SymmetricOperationParameters,
89         },
90         CryptoOperation::CryptoOperation,
91         IHwCryptoKey::{
92             DerivedKey::DerivedKey, DerivedKeyParameters::DerivedKeyParameters,
93             DerivedKeyPolicy::DerivedKeyPolicy, DeviceKeyId::DeviceKeyId,
94             DiceBoundDerivationKey::DiceBoundDerivationKey,
95             DiceCurrentBoundKeyResult::DiceCurrentBoundKeyResult, IHwCryptoKey, KeySlot::KeySlot,
96         },
97         KeyPolicy::KeyPolicy,
98         OperationParameters::OperationParameters,
99     };
100     use binder::Strong;
101     use rpcbinder::RpcSession;
102     use test::{assert_ok, expect, expect_eq};
103 
104     #[test]
aes_simple_test_from_binder()105     fn aes_simple_test_from_binder() {
106         let hw_device_key: Strong<dyn IHwCryptoKey> =
107             RpcSession::new().setup_trusty_client(RUST_SERVICE_PORT).expect("Failed to connect");
108         let derivation_key = DiceBoundDerivationKey::KeyId(DeviceKeyId::DEVICE_BOUND_KEY);
109         let key_and_policy =
110             assert_ok!(hw_device_key.deriveCurrentDicePolicyBoundKey(&derivation_key));
111         let DiceCurrentBoundKeyResult { diceBoundKey: key, dicePolicyForKeyVersion: policy } =
112             key_and_policy;
113         expect!(key.is_some(), "should have received a key");
114         expect!(policy.len() > 0, "should have received a DICE policy");
115 
116         let hw_crypto = hw_device_key.getHwCryptoOperations().expect("Failed to get crypto ops.");
117         let usage = KeyUse::ENCRYPT_DECRYPT;
118         let key_type = KeyType::AES_256_CBC_PKCS7_PADDING;
119         let policy = KeyPolicy {
120             usage,
121             keyLifetime: KeyLifetime::HARDWARE,
122             keyPermissions: Vec::new(),
123             keyType: key_type,
124             keyManagementKey: false,
125         };
126 
127         let cbor_policy = hwcryptohal_common::policy::cbor_serialize_key_policy(&policy)
128             .expect("couldn't serialize policy");
129         let key_policy = DerivedKeyPolicy::OpaqueKey(cbor_policy);
130         let params = DerivedKeyParameters {
131             derivationKey: key,
132             keyPolicy: key_policy,
133             context: "context".as_bytes().to_vec(),
134         };
135         let derived_key = assert_ok!(hw_device_key.deriveKey(&params));
136         let key = match derived_key {
137             DerivedKey::Opaque(key) => key.expect("key shouldn't be NULL"),
138             DerivedKey::ExplicitKey(_) => panic!("wrong type of key received"),
139         };
140 
141         let nonce = [0u8; 16];
142         let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
143             nonce: nonce.into(),
144         }));
145         let direction = SymmetricOperation::ENCRYPT;
146         let sym_op_params =
147             SymmetricOperationParameters { key: Some(key.clone()), direction, parameters };
148         let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
149         let mut cmd_list = Vec::<CryptoOperation>::new();
150         let data_output = OperationData::DataBuffer(Vec::new());
151         cmd_list.push(CryptoOperation::DataOutput(data_output));
152         cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
153         let input_data = OperationData::DataBuffer("string to be encrypted".as_bytes().to_vec());
154         cmd_list.push(CryptoOperation::DataInput(input_data));
155         let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
156         let mut crypto_sets = Vec::new();
157         crypto_sets.push(crypto_op_set);
158         let mut additional_error_info =
159             CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 };
160         let mut op_result = hw_crypto
161             .processCommandList(&mut crypto_sets, &mut additional_error_info)
162             .expect("couldn't process commands");
163         // Extracting the vector from the command list because of ownership
164         let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
165             crypto_sets.remove(0).operations.remove(0)
166         else {
167             panic!("not reachable, we created this object above on the test");
168         };
169         let context = op_result.remove(0).context;
170         // Separating the finish call on a different command set to test the returned context
171         let mut cmd_list = Vec::<CryptoOperation>::new();
172         let data_output = OperationData::DataBuffer(encrypted_data);
173         cmd_list.push(CryptoOperation::DataOutput(data_output));
174         cmd_list.push(CryptoOperation::Finish(None));
175         let crypto_op_set = CryptoOperationSet { context, operations: cmd_list };
176         let mut crypto_sets = Vec::new();
177         crypto_sets.push(crypto_op_set);
178         hw_crypto
179             .processCommandList(&mut crypto_sets, &mut additional_error_info)
180             .expect("couldn't process commands");
181         let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) =
182             crypto_sets.remove(0).operations.remove(0)
183         else {
184             panic!("not reachable, we created this object above on the test");
185         };
186 
187         //// Decrypting
188         let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters {
189             nonce: nonce.into(),
190         }));
191         let direction = SymmetricOperation::DECRYPT;
192         let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters };
193         let op_params = OperationParameters::SymmetricCrypto(sym_op_params);
194         let mut cmd_list = Vec::<CryptoOperation>::new();
195         let data_output = OperationData::DataBuffer(Vec::new());
196         cmd_list.push(CryptoOperation::DataOutput(data_output));
197         cmd_list.push(CryptoOperation::SetOperationParameters(op_params));
198         cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data)));
199         cmd_list.push(CryptoOperation::Finish(None));
200         let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
201         let mut crypto_sets = Vec::new();
202         crypto_sets.push(crypto_op_set);
203         hw_crypto
204             .processCommandList(&mut crypto_sets, &mut additional_error_info)
205             .expect("couldn't process commands");
206         // Extracting the vector from the command list because of ownership
207         let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) =
208             crypto_sets.remove(0).operations.remove(0)
209         else {
210             panic!("not reachable, we created this object above on the test");
211         };
212         let decrypted_msg =
213             String::from_utf8(decrypted_data).expect("couldn't decode received message");
214         expect_eq!(decrypted_msg, "string to be encrypted", "couldn't retrieve original message");
215     }
216 
217     #[test]
hmac_simple_test_from_binder()218     fn hmac_simple_test_from_binder() {
219         let hw_key: Strong<dyn IHwCryptoKey> =
220             RpcSession::new().setup_trusty_client(RUST_SERVICE_PORT).expect("Failed to connect");
221 
222         let key =
223             hw_key.getKeyslotData(KeySlot::KEYMINT_SHARED_HMAC_KEY).expect("couldn't get key");
224 
225         let hw_crypto = hw_key.getHwCryptoOperations().expect("Failed to get crypto ops.");
226 
227         let hmac_parameters = HmacOperationParameters { key: Some(key.clone()) };
228         let op_parameters = OperationParameters::Hmac(hmac_parameters);
229         let mut cmd_list = Vec::<CryptoOperation>::new();
230         let data_output = OperationData::DataBuffer(Vec::new());
231         cmd_list.push(CryptoOperation::DataOutput(data_output));
232         cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
233         let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
234         cmd_list.push(CryptoOperation::DataInput(input_data));
235         cmd_list.push(CryptoOperation::Finish(None));
236         let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
237         let mut crypto_sets = Vec::new();
238         crypto_sets.push(crypto_op_set);
239         let mut additional_error_info =
240             CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 };
241         hw_crypto
242             .processCommandList(&mut crypto_sets, &mut additional_error_info)
243             .expect("couldn't process commands");
244         // Extracting the vector from the command list because of ownership
245         let CryptoOperation::DataOutput(OperationData::DataBuffer(mac)) =
246             crypto_sets.remove(0).operations.remove(0)
247         else {
248             panic!("not reachable, we created this object above on the test");
249         };
250 
251         //Getting a second mac to compare
252         let hmac_parameters = HmacOperationParameters { key: Some(key) };
253         let op_parameters = OperationParameters::Hmac(hmac_parameters);
254         let mut cmd_list = Vec::<CryptoOperation>::new();
255         let data_output = OperationData::DataBuffer(Vec::new());
256         cmd_list.push(CryptoOperation::DataOutput(data_output));
257         cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters));
258         let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec());
259         cmd_list.push(CryptoOperation::DataInput(input_data));
260         cmd_list.push(CryptoOperation::Finish(None));
261         let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list };
262         let mut crypto_sets = Vec::new();
263         crypto_sets.push(crypto_op_set);
264         let mut additional_error_info =
265             CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 };
266         hw_crypto
267             .processCommandList(&mut crypto_sets, &mut additional_error_info)
268             .expect("couldn't process commands");
269         // Extracting the vector from the command list because of ownership
270         let CryptoOperation::DataOutput(OperationData::DataBuffer(mac2)) =
271             crypto_sets.remove(0).operations.remove(0)
272         else {
273             panic!("not reachable, we created this object above on the test");
274         };
275         expect_eq!(mac, mac2, "got a different mac");
276     }
277 }
278