xref: /aosp_15_r20/system/keymint/hal/src/tests.rs (revision 9860b7637a5f185913c70aa0caabe3ecb78441e4)
1*9860b763SAndroid Build Coastguard Worker // Copyright 2022, The Android Open Source Project
2*9860b763SAndroid Build Coastguard Worker //
3*9860b763SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9860b763SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9860b763SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9860b763SAndroid Build Coastguard Worker //
7*9860b763SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*9860b763SAndroid Build Coastguard Worker //
9*9860b763SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9860b763SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9860b763SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9860b763SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9860b763SAndroid Build Coastguard Worker // limitations under the License.
14*9860b763SAndroid Build Coastguard Worker 
15*9860b763SAndroid Build Coastguard Worker use super::*;
16*9860b763SAndroid Build Coastguard Worker use crate::{
17*9860b763SAndroid Build Coastguard Worker     binder,
18*9860b763SAndroid Build Coastguard Worker     hal::keymint::{ErrorCode::ErrorCode, IKeyMintDevice::IKeyMintDevice},
19*9860b763SAndroid Build Coastguard Worker     keymint::MAX_CBOR_OVERHEAD,
20*9860b763SAndroid Build Coastguard Worker };
21*9860b763SAndroid Build Coastguard Worker use kmr_wire::{
22*9860b763SAndroid Build Coastguard Worker     keymint::{
23*9860b763SAndroid Build Coastguard Worker         HardwareAuthToken, HardwareAuthenticatorType, NEXT_MESSAGE_SIGNAL_FALSE,
24*9860b763SAndroid Build Coastguard Worker         NEXT_MESSAGE_SIGNAL_TRUE,
25*9860b763SAndroid Build Coastguard Worker     },
26*9860b763SAndroid Build Coastguard Worker     secureclock::{TimeStampToken, Timestamp},
27*9860b763SAndroid Build Coastguard Worker     FinishRequest, PerformOpReq,
28*9860b763SAndroid Build Coastguard Worker };
29*9860b763SAndroid Build Coastguard Worker use std::sync::{Arc, Mutex};
30*9860b763SAndroid Build Coastguard Worker 
31*9860b763SAndroid Build Coastguard Worker #[derive(Clone, Debug)]
32*9860b763SAndroid Build Coastguard Worker struct TestChannel {
33*9860b763SAndroid Build Coastguard Worker     req: Arc<Mutex<Vec<u8>>>,
34*9860b763SAndroid Build Coastguard Worker     rsp: Vec<u8>,
35*9860b763SAndroid Build Coastguard Worker }
36*9860b763SAndroid Build Coastguard Worker 
37*9860b763SAndroid Build Coastguard Worker impl TestChannel {
38*9860b763SAndroid Build Coastguard Worker     fn new(rsp: &str) -> Self {
39*9860b763SAndroid Build Coastguard Worker         Self { req: Arc::new(Mutex::new(vec![])), rsp: hex::decode(rsp).unwrap() }
40*9860b763SAndroid Build Coastguard Worker     }
41*9860b763SAndroid Build Coastguard Worker     fn req_data(&self) -> Vec<u8> {
42*9860b763SAndroid Build Coastguard Worker         self.req.lock().unwrap().clone()
43*9860b763SAndroid Build Coastguard Worker     }
44*9860b763SAndroid Build Coastguard Worker }
45*9860b763SAndroid Build Coastguard Worker 
46*9860b763SAndroid Build Coastguard Worker impl SerializedChannel for TestChannel {
47*9860b763SAndroid Build Coastguard Worker     const MAX_SIZE: usize = 4096;
48*9860b763SAndroid Build Coastguard Worker     fn execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>> {
49*9860b763SAndroid Build Coastguard Worker         *self.req.lock().unwrap() = serialized_req.to_vec();
50*9860b763SAndroid Build Coastguard Worker         Ok(self.rsp.clone())
51*9860b763SAndroid Build Coastguard Worker     }
52*9860b763SAndroid Build Coastguard Worker }
53*9860b763SAndroid Build Coastguard Worker 
54*9860b763SAndroid Build Coastguard Worker #[test]
55*9860b763SAndroid Build Coastguard Worker fn test_method_roundtrip() {
56*9860b763SAndroid Build Coastguard Worker     let channel = TestChannel::new(concat!(
57*9860b763SAndroid Build Coastguard Worker         "82", // 2-arr (PerformOpResponse)
58*9860b763SAndroid Build Coastguard Worker         "00", // int   (PerformOpResponse.error_code == ErrorCode::Ok)
59*9860b763SAndroid Build Coastguard Worker         "81", // 1-arr (PerformOpResponse.rsp)
60*9860b763SAndroid Build Coastguard Worker         "82", // 2-arr (PerformOpResponse.rsp.0 : PerformOpRsp)
61*9860b763SAndroid Build Coastguard Worker         "13", // 0x13 = KeyMintOperation::DEVICE_GENERATE_KEY
62*9860b763SAndroid Build Coastguard Worker         "81", // 1-arr (GenerateKeyResponse)
63*9860b763SAndroid Build Coastguard Worker         "83", // 3-arr (ret: KeyCreationResult)
64*9860b763SAndroid Build Coastguard Worker         "41", "01", // 1-bstr (KeyCreationResult.keyBlob)
65*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (KeyCreationResult.keyCharacteristics)
66*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (KeyCreationResult.certificateChain)
67*9860b763SAndroid Build Coastguard Worker     ));
68*9860b763SAndroid Build Coastguard Worker     let imp = keymint::Device::new(Arc::new(Mutex::new(channel.clone())));
69*9860b763SAndroid Build Coastguard Worker 
70*9860b763SAndroid Build Coastguard Worker     let result = imp.generateKey(&[], None).unwrap();
71*9860b763SAndroid Build Coastguard Worker 
72*9860b763SAndroid Build Coastguard Worker     let want_req = concat!(
73*9860b763SAndroid Build Coastguard Worker         "82", // 2-arr (PerformOpReq)
74*9860b763SAndroid Build Coastguard Worker         "13", // 0x13 = DEVICE_GENERATE_KEY
75*9860b763SAndroid Build Coastguard Worker         "82", // 1-arr (GenerateKeyRequest)
76*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (* KeyParameter)
77*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (? AttestationKey)
78*9860b763SAndroid Build Coastguard Worker     );
79*9860b763SAndroid Build Coastguard Worker     assert_eq!(channel.req_data(), hex::decode(want_req).unwrap());
80*9860b763SAndroid Build Coastguard Worker 
81*9860b763SAndroid Build Coastguard Worker     assert_eq!(result.keyBlob, vec![0x01]);
82*9860b763SAndroid Build Coastguard Worker     assert!(result.keyCharacteristics.is_empty());
83*9860b763SAndroid Build Coastguard Worker     assert!(result.certificateChain.is_empty());
84*9860b763SAndroid Build Coastguard Worker }
85*9860b763SAndroid Build Coastguard Worker 
86*9860b763SAndroid Build Coastguard Worker #[test]
87*9860b763SAndroid Build Coastguard Worker fn test_method_err_roundtrip() {
88*9860b763SAndroid Build Coastguard Worker     let channel = TestChannel::new(concat!(
89*9860b763SAndroid Build Coastguard Worker         "82", // 2-arr (PerformOpResponse)
90*9860b763SAndroid Build Coastguard Worker         "21", // (PerformOpResponse.error_code = ErrorCode::UNSUPPORTED_PURPOSE)
91*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (PerformOpResponse.rsp)
92*9860b763SAndroid Build Coastguard Worker     ));
93*9860b763SAndroid Build Coastguard Worker     let imp = keymint::Device::new(Arc::new(Mutex::new(channel.clone())));
94*9860b763SAndroid Build Coastguard Worker 
95*9860b763SAndroid Build Coastguard Worker     let result = imp.generateKey(&[], None);
96*9860b763SAndroid Build Coastguard Worker 
97*9860b763SAndroid Build Coastguard Worker     let want_req = concat!(
98*9860b763SAndroid Build Coastguard Worker         "82", // 2-arr (PerformOpReq)
99*9860b763SAndroid Build Coastguard Worker         "13", // 0x13 = DEVICE_GENERATE_KEY
100*9860b763SAndroid Build Coastguard Worker         "82", // 1-arr (GenerateKeyRequest)
101*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (* KeyParameter)
102*9860b763SAndroid Build Coastguard Worker         "80", // 0-arr (? AttestationKey)
103*9860b763SAndroid Build Coastguard Worker     );
104*9860b763SAndroid Build Coastguard Worker     assert_eq!(channel.req_data(), hex::decode(want_req).unwrap());
105*9860b763SAndroid Build Coastguard Worker 
106*9860b763SAndroid Build Coastguard Worker     assert!(result.is_err());
107*9860b763SAndroid Build Coastguard Worker     let status = result.unwrap_err();
108*9860b763SAndroid Build Coastguard Worker     assert_eq!(status.exception_code(), binder::ExceptionCode::SERVICE_SPECIFIC);
109*9860b763SAndroid Build Coastguard Worker     assert_eq!(status.service_specific_error(), ErrorCode::UNSUPPORTED_PURPOSE.0);
110*9860b763SAndroid Build Coastguard Worker }
111*9860b763SAndroid Build Coastguard Worker 
112*9860b763SAndroid Build Coastguard Worker #[test]
113*9860b763SAndroid Build Coastguard Worker fn test_overhead_size() {
114*9860b763SAndroid Build Coastguard Worker     let largest_op_req = PerformOpReq::OperationFinish(FinishRequest {
115*9860b763SAndroid Build Coastguard Worker         op_handle: 0x7fffffff,
116*9860b763SAndroid Build Coastguard Worker         input: Some(Vec::new()),
117*9860b763SAndroid Build Coastguard Worker         signature: Some(vec![0; 132]),
118*9860b763SAndroid Build Coastguard Worker         auth_token: Some(HardwareAuthToken {
119*9860b763SAndroid Build Coastguard Worker             challenge: 0x7fffffff,
120*9860b763SAndroid Build Coastguard Worker             user_id: 0x7fffffff,
121*9860b763SAndroid Build Coastguard Worker             authenticator_id: 0x7fffffff,
122*9860b763SAndroid Build Coastguard Worker             authenticator_type: HardwareAuthenticatorType::Password,
123*9860b763SAndroid Build Coastguard Worker             timestamp: Timestamp { milliseconds: 0x7fffffff },
124*9860b763SAndroid Build Coastguard Worker             mac: vec![0; 32],
125*9860b763SAndroid Build Coastguard Worker         }),
126*9860b763SAndroid Build Coastguard Worker         timestamp_token: Some(TimeStampToken {
127*9860b763SAndroid Build Coastguard Worker             challenge: 0x7fffffff,
128*9860b763SAndroid Build Coastguard Worker             timestamp: Timestamp { milliseconds: 0x7fffffff },
129*9860b763SAndroid Build Coastguard Worker             mac: vec![0; 32],
130*9860b763SAndroid Build Coastguard Worker         }),
131*9860b763SAndroid Build Coastguard Worker         confirmation_token: Some(vec![0; 32]),
132*9860b763SAndroid Build Coastguard Worker     });
133*9860b763SAndroid Build Coastguard Worker     let data = largest_op_req.into_vec().unwrap();
134*9860b763SAndroid Build Coastguard Worker     assert!(
135*9860b763SAndroid Build Coastguard Worker         data.len() < MAX_CBOR_OVERHEAD,
136*9860b763SAndroid Build Coastguard Worker         "expect largest serialized empty message (size {}) to be smaller than {}",
137*9860b763SAndroid Build Coastguard Worker         data.len(),
138*9860b763SAndroid Build Coastguard Worker         MAX_CBOR_OVERHEAD
139*9860b763SAndroid Build Coastguard Worker     );
140*9860b763SAndroid Build Coastguard Worker }
141*9860b763SAndroid Build Coastguard Worker 
142*9860b763SAndroid Build Coastguard Worker #[test]
143*9860b763SAndroid Build Coastguard Worker fn test_extract_rsp_true_marker() {
144*9860b763SAndroid Build Coastguard Worker     let msg_content = vec![0x82, 0x21, 0x80];
145*9860b763SAndroid Build Coastguard Worker     // test true marker and message content
146*9860b763SAndroid Build Coastguard Worker     let mut resp = vec![NEXT_MESSAGE_SIGNAL_TRUE];
147*9860b763SAndroid Build Coastguard Worker     resp.extend_from_slice(&msg_content);
148*9860b763SAndroid Build Coastguard Worker     assert_eq!(Ok((true, msg_content.as_slice())), extract_rsp(&resp));
149*9860b763SAndroid Build Coastguard Worker }
150*9860b763SAndroid Build Coastguard Worker 
151*9860b763SAndroid Build Coastguard Worker #[test]
152*9860b763SAndroid Build Coastguard Worker fn test_extract_rsp_false_marker() {
153*9860b763SAndroid Build Coastguard Worker     let msg_content = vec![0x82, 0x21, 0x80];
154*9860b763SAndroid Build Coastguard Worker     // test false signal and message content
155*9860b763SAndroid Build Coastguard Worker     let mut resp = vec![NEXT_MESSAGE_SIGNAL_FALSE];
156*9860b763SAndroid Build Coastguard Worker     resp.extend_from_slice(&msg_content);
157*9860b763SAndroid Build Coastguard Worker     assert_eq!(Ok((false, msg_content.as_slice())), extract_rsp(&resp));
158*9860b763SAndroid Build Coastguard Worker }
159*9860b763SAndroid Build Coastguard Worker 
160*9860b763SAndroid Build Coastguard Worker #[test]
161*9860b763SAndroid Build Coastguard Worker fn test_extract_rsp_empty_input() {
162*9860b763SAndroid Build Coastguard Worker     // test invalid (empty) input
163*9860b763SAndroid Build Coastguard Worker     let resp3 = vec![];
164*9860b763SAndroid Build Coastguard Worker     let result = extract_rsp(&resp3);
165*9860b763SAndroid Build Coastguard Worker     assert!(result.is_err());
166*9860b763SAndroid Build Coastguard Worker     let status = result.unwrap_err();
167*9860b763SAndroid Build Coastguard Worker     assert_eq!(status.exception_code(), binder::ExceptionCode::ILLEGAL_ARGUMENT);
168*9860b763SAndroid Build Coastguard Worker }
169*9860b763SAndroid Build Coastguard Worker 
170*9860b763SAndroid Build Coastguard Worker #[test]
171*9860b763SAndroid Build Coastguard Worker fn test_extract_rsp_single_byte_input() {
172*9860b763SAndroid Build Coastguard Worker     // test invalid (single byte) input
173*9860b763SAndroid Build Coastguard Worker     let resp4 = vec![NEXT_MESSAGE_SIGNAL_FALSE];
174*9860b763SAndroid Build Coastguard Worker     let result = extract_rsp(&resp4);
175*9860b763SAndroid Build Coastguard Worker     assert!(result.is_err());
176*9860b763SAndroid Build Coastguard Worker     let status = result.unwrap_err();
177*9860b763SAndroid Build Coastguard Worker     assert_eq!(status.exception_code(), binder::ExceptionCode::ILLEGAL_ARGUMENT);
178*9860b763SAndroid Build Coastguard Worker }
179