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