xref: /aosp_15_r20/system/security/keystore2/src/error/tests.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1 // Copyright 2020, The Android Open Source Project
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 //! Error handling tests.
16 
17 use super::*;
18 use android_system_keystore2::binder::{
19     ExceptionCode, Result as BinderResult, Status as BinderStatus,
20 };
21 use anyhow::{anyhow, Context};
22 
nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()>23 fn nested_nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
24     Err(anyhow!(Error::Rc(rc))).context("nested nested rc")
25 }
26 
nested_rc(rc: ResponseCode) -> anyhow::Result<()>27 fn nested_rc(rc: ResponseCode) -> anyhow::Result<()> {
28     nested_nested_rc(rc).context("nested rc")
29 }
30 
nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()>31 fn nested_nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
32     Err(anyhow!(Error::Km(ec))).context("nested nested ec")
33 }
34 
nested_ec(ec: ErrorCode) -> anyhow::Result<()>35 fn nested_ec(ec: ErrorCode) -> anyhow::Result<()> {
36     nested_nested_ec(ec).context("nested ec")
37 }
38 
nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode>39 fn nested_nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
40     Ok(rc)
41 }
42 
nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode>43 fn nested_ok(rc: ResponseCode) -> anyhow::Result<ResponseCode> {
44     nested_nested_ok(rc).context("nested ok")
45 }
46 
nested_nested_selinux_perm() -> anyhow::Result<()>47 fn nested_nested_selinux_perm() -> anyhow::Result<()> {
48     Err(anyhow!(selinux::Error::perm())).context("nested nexted selinux permission denied")
49 }
50 
nested_selinux_perm() -> anyhow::Result<()>51 fn nested_selinux_perm() -> anyhow::Result<()> {
52     nested_nested_selinux_perm().context("nested selinux permission denied")
53 }
54 
55 #[derive(Debug, thiserror::Error)]
56 enum TestError {
57     #[error("TestError::Fail")]
58     Fail = 0,
59 }
60 
nested_nested_other_error() -> anyhow::Result<()>61 fn nested_nested_other_error() -> anyhow::Result<()> {
62     Err(anyhow!(TestError::Fail)).context("nested nested other error")
63 }
64 
nested_other_error() -> anyhow::Result<()>65 fn nested_other_error() -> anyhow::Result<()> {
66     nested_nested_other_error().context("nested other error")
67 }
68 
binder_sse_error(sse: i32) -> BinderResult<()>69 fn binder_sse_error(sse: i32) -> BinderResult<()> {
70     Err(BinderStatus::new_service_specific_error(sse, None))
71 }
72 
binder_exception(ex: ExceptionCode) -> BinderResult<()>73 fn binder_exception(ex: ExceptionCode) -> BinderResult<()> {
74     Err(BinderStatus::new_exception(ex, None))
75 }
76 
77 #[test]
keystore_error_test() -> anyhow::Result<(), String>78 fn keystore_error_test() -> anyhow::Result<(), String> {
79     android_logger::init_once(
80         android_logger::Config::default()
81             .with_tag("keystore_error_tests")
82             .with_max_level(log::LevelFilter::Debug),
83     );
84     // All Error::Rc(x) get mapped on a service specific error
85     // code of x.
86     for rc in ResponseCode::LOCKED.0..ResponseCode::BACKEND_BUSY.0 {
87         assert_eq!(
88             Result::<(), i32>::Err(rc),
89             nested_rc(ResponseCode(rc))
90                 .map_err(into_logged_binder)
91                 .map_err(|s| s.service_specific_error())
92         );
93     }
94 
95     // All Keystore Error::Km(x) get mapped on a service
96     // specific error of x.
97     for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
98         assert_eq!(
99             Result::<(), i32>::Err(ec),
100             nested_ec(ErrorCode(ec))
101                 .map_err(into_logged_binder)
102                 .map_err(|s| s.service_specific_error())
103         );
104     }
105 
106     // All Keymint errors x received through a Binder Result get mapped on
107     // a service specific error of x.
108     for ec in ErrorCode::UNKNOWN_ERROR.0..ErrorCode::ROOT_OF_TRUST_ALREADY_SET.0 {
109         assert_eq!(
110             Result::<(), i32>::Err(ec),
111             map_km_error(binder_sse_error(ec))
112                 .with_context(|| format!("Km error code: {}.", ec))
113                 .map_err(into_logged_binder)
114                 .map_err(|s| s.service_specific_error())
115         );
116     }
117 
118     // map_km_error creates an Error::Binder variant storing
119     // ExceptionCode::SERVICE_SPECIFIC and the given
120     // service specific error.
121     let sse = map_km_error(binder_sse_error(1));
122     assert_eq!(Err(Error::Binder(ExceptionCode::SERVICE_SPECIFIC, 1)), sse);
123     // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
124     assert_eq!(
125         Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
126         sse.context("Non negative service specific error.")
127             .map_err(into_logged_binder)
128             .map_err(|s| ResponseCode(s.service_specific_error()))
129     );
130 
131     // map_km_error creates a Error::Binder variant storing the given exception code.
132     let binder_exception = map_km_error(binder_exception(ExceptionCode::TRANSACTION_FAILED));
133     assert_eq!(Err(Error::Binder(ExceptionCode::TRANSACTION_FAILED, 0)), binder_exception);
134     // into_binder then maps it on a service specific error of ResponseCode::SYSTEM_ERROR.
135     assert_eq!(
136         Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
137         binder_exception
138             .context("Binder Exception.")
139             .map_err(into_logged_binder)
140             .map_err(|s| ResponseCode(s.service_specific_error()))
141     );
142 
143     // selinux::Error::Perm() needs to be mapped to ResponseCode::PERMISSION_DENIED
144     assert_eq!(
145         Result::<(), ResponseCode>::Err(ResponseCode::PERMISSION_DENIED),
146         nested_selinux_perm()
147             .map_err(into_logged_binder)
148             .map_err(|s| ResponseCode(s.service_specific_error()))
149     );
150 
151     // All other errors get mapped on System Error.
152     assert_eq!(
153         Result::<(), ResponseCode>::Err(ResponseCode::SYSTEM_ERROR),
154         nested_other_error()
155             .map_err(into_logged_binder)
156             .map_err(|s| ResponseCode(s.service_specific_error()))
157     );
158 
159     // Result::Ok variants get passed to the ok handler.
160     assert_eq!(
161         Ok(ResponseCode::LOCKED),
162         nested_ok(ResponseCode::LOCKED).map_err(into_logged_binder)
163     );
164     assert_eq!(
165         Ok(ResponseCode::SYSTEM_ERROR),
166         nested_ok(ResponseCode::SYSTEM_ERROR).map_err(into_logged_binder)
167     );
168 
169     Ok(())
170 }
171 
172 //Helper function to test whether error cases are handled as expected.
check_result_contains_error_string<T>( result: anyhow::Result<T>, expected_error_string: &str, )173 pub fn check_result_contains_error_string<T>(
174     result: anyhow::Result<T>,
175     expected_error_string: &str,
176 ) {
177     let error_str = format!(
178         "{:#?}",
179         result.err().unwrap_or_else(|| panic!("Expected the error: {}", expected_error_string))
180     );
181     assert!(
182         error_str.contains(expected_error_string),
183         "The string \"{}\" should contain \"{}\"",
184         error_str,
185         expected_error_string
186     );
187 }
188 
189 #[test]
rkpd_error_is_in_sync_with_response_code()190 fn rkpd_error_is_in_sync_with_response_code() {
191     let error_mapping = [
192         (RkpdError::RequestCancelled, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
193         (RkpdError::GetRegistrationFailed, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
194         (
195             RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_UNKNOWN),
196             ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR,
197         ),
198         (
199             RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PERMANENT),
200             ResponseCode::OUT_OF_KEYS_PERMANENT_ERROR,
201         ),
202         (
203             RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_PENDING_INTERNET_CONNECTIVITY),
204             ResponseCode::OUT_OF_KEYS_PENDING_INTERNET_CONNECTIVITY,
205         ),
206         (
207             RkpdError::GetKeyFailed(GetKeyErrorCode::ERROR_REQUIRES_SECURITY_PATCH),
208             ResponseCode::OUT_OF_KEYS_REQUIRES_SYSTEM_UPGRADE,
209         ),
210         (RkpdError::StoreUpgradedKeyFailed, ResponseCode::SYSTEM_ERROR),
211         (RkpdError::RetryableTimeout, ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR),
212         (RkpdError::Timeout, ResponseCode::SYSTEM_ERROR),
213     ];
214     for (rkpd_error, expected_response_code) in error_mapping {
215         let e: Error = rkpd_error.into();
216         assert_eq!(e, Error::Rc(expected_response_code));
217     }
218 }
219