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