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