1 // Copyright 2022, 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 //! Fuzzes unsafe APIs of libkeystore2 module
16
17 #![no_main]
18
19 use binder::get_declared_instances;
20 use keystore2::{legacy_blob::LegacyBlobLoader, utils::ui_opts_2_compat};
21 use keystore2_aaid::get_aaid;
22 use keystore2_apc_compat::ApcHal;
23 use keystore2_crypto::{
24 aes_gcm_decrypt, aes_gcm_encrypt, ec_key_generate_key, ec_key_get0_public_key,
25 ec_key_marshal_private_key, ec_key_parse_private_key, ec_point_oct_to_point,
26 ec_point_point_to_oct, ecdh_compute_key, generate_random_data, hkdf_expand, hkdf_extract,
27 hmac_sha256, parse_subject_from_certificate, Password, ZVec,
28 };
29 use keystore2_selinux::{check_access, getpidcon, setcon, Backend, Context, KeystoreKeyBackend};
30 use keystore2_vintf::get_hidl_instances;
31 use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
32 use std::{ffi::CString, sync::Arc};
33
34 // Avoid allocating too much memory and crashing the fuzzer.
35 const MAX_SIZE_MODIFIER: usize = 1024;
36
37 /// CString does not contain any internal 0 bytes
get_valid_cstring_data(data: &[u8]) -> &[u8]38 fn get_valid_cstring_data(data: &[u8]) -> &[u8] {
39 match data.iter().position(|&b| b == 0) {
40 Some(idx) => &data[0..idx],
41 None => data,
42 }
43 }
44
45 #[derive(Arbitrary, Debug)]
46 enum FuzzCommand<'a> {
47 DecodeAlias {
48 string: String,
49 },
50 TryFrom {
51 vector_data: Vec<u8>,
52 },
53 GenerateRandomData {
54 size: usize,
55 },
56 HmacSha256 {
57 key_hmac: &'a [u8],
58 msg: &'a [u8],
59 },
60 AesGcmDecrypt {
61 data: &'a [u8],
62 iv: &'a [u8],
63 tag: &'a [u8],
64 key_aes_decrypt: &'a [u8],
65 },
66 AesGcmEecrypt {
67 plaintext: &'a [u8],
68 key_aes_encrypt: &'a [u8],
69 },
70 Password {
71 pw: &'a [u8],
72 salt: &'a [u8],
73 key_length: usize,
74 },
75 HkdfExtract {
76 hkdf_secret: &'a [u8],
77 hkdf_salt: &'a [u8],
78 },
79 HkdfExpand {
80 out_len: usize,
81 hkdf_prk: &'a [u8],
82 hkdf_info: &'a [u8],
83 },
84 PublicPrivateKey {
85 ec_priv_buf: &'a [u8],
86 ec_oct_buf: &'a [u8],
87 },
88 ParseSubjectFromCertificate {
89 parse_buf: &'a [u8],
90 },
91 GetHidlInstances {
92 hidl_package: &'a str,
93 major_version: usize,
94 minor_version: usize,
95 hidl_interface_name: &'a str,
96 },
97 GetAidlInstances {
98 aidl_package: &'a str,
99 aidl_interface_name: &'a str,
100 },
101 GetAaid {
102 aaid_uid: u32,
103 },
104 Hal {
105 opt: i32,
106 prompt_text: &'a str,
107 locale: &'a str,
108 extra_data: &'a [u8],
109 },
110 Context {
111 context: &'a str,
112 },
113 Backend {
114 namespace: &'a str,
115 },
116 GetPidCon {
117 pid: i32,
118 },
119 CheckAccess {
120 source: &'a [u8],
121 target: &'a [u8],
122 tclass: &'a str,
123 perm: &'a str,
124 },
125 SetCon {
126 set_target: &'a [u8],
127 },
128 }
129
130 fuzz_target!(|commands: Vec<FuzzCommand>| {
131 for command in commands {
132 match command {
133 FuzzCommand::DecodeAlias { string } => {
134 let _res = LegacyBlobLoader::decode_alias(&string);
135 }
136 FuzzCommand::TryFrom { vector_data } => {
137 let _res = ZVec::try_from(vector_data);
138 }
139 FuzzCommand::GenerateRandomData { size } => {
140 let _res = generate_random_data(size % MAX_SIZE_MODIFIER);
141 }
142 FuzzCommand::HmacSha256 { key_hmac, msg } => {
143 let _res = hmac_sha256(key_hmac, msg);
144 }
145 FuzzCommand::AesGcmDecrypt { data, iv, tag, key_aes_decrypt } => {
146 let _res = aes_gcm_decrypt(data, iv, tag, key_aes_decrypt);
147 }
148 FuzzCommand::AesGcmEecrypt { plaintext, key_aes_encrypt } => {
149 let _res = aes_gcm_encrypt(plaintext, key_aes_encrypt);
150 }
151 FuzzCommand::Password { pw, salt, key_length } => {
152 let _res = Password::from(pw).derive_key(salt, key_length % MAX_SIZE_MODIFIER);
153 }
154 FuzzCommand::HkdfExtract { hkdf_secret, hkdf_salt } => {
155 let _res = hkdf_extract(hkdf_secret, hkdf_salt);
156 }
157 FuzzCommand::HkdfExpand { out_len, hkdf_prk, hkdf_info } => {
158 let _res = hkdf_expand(out_len % MAX_SIZE_MODIFIER, hkdf_prk, hkdf_info);
159 }
160 FuzzCommand::PublicPrivateKey { ec_priv_buf, ec_oct_buf } => {
161 let check_private_key = {
162 let mut check_private_key = ec_key_parse_private_key(ec_priv_buf);
163 if check_private_key.is_err() {
164 check_private_key = ec_key_generate_key();
165 };
166 check_private_key
167 };
168 let check_ecpoint = ec_point_oct_to_point(ec_oct_buf);
169 if check_private_key.is_ok() {
170 let private_key = check_private_key.unwrap();
171 ec_key_get0_public_key(&private_key);
172 let _res = ec_key_marshal_private_key(&private_key);
173
174 if check_ecpoint.is_ok() {
175 let public_key = check_ecpoint.unwrap();
176 let _res = ec_point_point_to_oct(public_key.get_point());
177 let _res = ecdh_compute_key(public_key.get_point(), &private_key);
178 }
179 }
180 }
181 FuzzCommand::ParseSubjectFromCertificate { parse_buf } => {
182 let _res = parse_subject_from_certificate(parse_buf);
183 }
184 FuzzCommand::GetHidlInstances {
185 hidl_package,
186 major_version,
187 minor_version,
188 hidl_interface_name,
189 } => {
190 get_hidl_instances(hidl_package, major_version, minor_version, hidl_interface_name);
191 }
192 FuzzCommand::GetAidlInstances { aidl_package, aidl_interface_name } => {
193 get_declared_instances(
194 format!("{}.{}", aidl_package, aidl_interface_name).as_str(),
195 )
196 .unwrap();
197 }
198 FuzzCommand::GetAaid { aaid_uid } => {
199 let _res = get_aaid(aaid_uid);
200 }
201 FuzzCommand::Hal { opt, prompt_text, locale, extra_data } => {
202 let hal = ApcHal::try_get_service();
203 if hal.is_some() {
204 let hal = Arc::new(hal.unwrap());
205 let apc_compat_options = ui_opts_2_compat(opt);
206 let prompt_text =
207 std::str::from_utf8(get_valid_cstring_data(prompt_text.as_bytes()))
208 .unwrap();
209 let locale =
210 std::str::from_utf8(get_valid_cstring_data(locale.as_bytes())).unwrap();
211 let _res = hal.prompt_user_confirmation(
212 prompt_text,
213 extra_data,
214 locale,
215 apc_compat_options,
216 move |_, _, _| {},
217 );
218 }
219 }
220 FuzzCommand::Context { context } => {
221 let _res = Context::new(context);
222 }
223 FuzzCommand::Backend { namespace } => {
224 let backend = KeystoreKeyBackend::new();
225 if let Ok(backend) = backend {
226 let _res = backend.lookup(namespace);
227 }
228 }
229 FuzzCommand::GetPidCon { pid } => {
230 let _res = getpidcon(pid);
231 }
232 FuzzCommand::CheckAccess { source, target, tclass, perm } => {
233 let source = get_valid_cstring_data(source);
234 let target = get_valid_cstring_data(target);
235 let _res = check_access(
236 &CString::new(source).unwrap(),
237 &CString::new(target).unwrap(),
238 tclass,
239 perm,
240 );
241 }
242 FuzzCommand::SetCon { set_target } => {
243 let _res = setcon(&CString::new(get_valid_cstring_data(set_target)).unwrap());
244 }
245 }
246 }
247 });
248