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, 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 CheckAccess {
112 source: &'a [u8],
113 target: &'a [u8],
114 tclass: &'a str,
115 perm: &'a str,
116 },
117 SetCon {
118 set_target: &'a [u8],
119 },
120 }
121
122 fuzz_target!(|commands: Vec<FuzzCommand>| {
123 for command in commands {
124 match command {
125 FuzzCommand::DecodeAlias { string } => {
126 let _res = LegacyBlobLoader::decode_alias(&string);
127 }
128 FuzzCommand::TryFrom { vector_data } => {
129 let _res = ZVec::try_from(vector_data);
130 }
131 FuzzCommand::GenerateRandomData { size } => {
132 let _res = generate_random_data(size % MAX_SIZE_MODIFIER);
133 }
134 FuzzCommand::HmacSha256 { key_hmac, msg } => {
135 let _res = hmac_sha256(key_hmac, msg);
136 }
137 FuzzCommand::AesGcmDecrypt { data, iv, tag, key_aes_decrypt } => {
138 let _res = aes_gcm_decrypt(data, iv, tag, key_aes_decrypt);
139 }
140 FuzzCommand::AesGcmEecrypt { plaintext, key_aes_encrypt } => {
141 let _res = aes_gcm_encrypt(plaintext, key_aes_encrypt);
142 }
143 FuzzCommand::Password { pw, salt, key_length } => {
144 let _res =
145 Password::from(pw).derive_key_pbkdf2(salt, key_length % MAX_SIZE_MODIFIER);
146 }
147 FuzzCommand::HkdfExtract { hkdf_secret, hkdf_salt } => {
148 let _res = hkdf_extract(hkdf_secret, hkdf_salt);
149 }
150 FuzzCommand::HkdfExpand { out_len, hkdf_prk, hkdf_info } => {
151 let _res = hkdf_expand(out_len % MAX_SIZE_MODIFIER, hkdf_prk, hkdf_info);
152 }
153 FuzzCommand::PublicPrivateKey { ec_priv_buf, ec_oct_buf } => {
154 let check_private_key = {
155 let mut check_private_key = ec_key_parse_private_key(ec_priv_buf);
156 if check_private_key.is_err() {
157 check_private_key = ec_key_generate_key();
158 };
159 check_private_key
160 };
161 let check_ecpoint = ec_point_oct_to_point(ec_oct_buf);
162 if check_private_key.is_ok() {
163 let private_key = check_private_key.unwrap();
164 ec_key_get0_public_key(&private_key);
165 let _res = ec_key_marshal_private_key(&private_key);
166
167 if check_ecpoint.is_ok() {
168 let public_key = check_ecpoint.unwrap();
169 let _res = ec_point_point_to_oct(public_key.get_point());
170 let _res = ecdh_compute_key(public_key.get_point(), &private_key);
171 }
172 }
173 }
174 FuzzCommand::ParseSubjectFromCertificate { parse_buf } => {
175 let _res = parse_subject_from_certificate(parse_buf);
176 }
177 FuzzCommand::GetHidlInstances {
178 hidl_package,
179 major_version,
180 minor_version,
181 hidl_interface_name,
182 } => {
183 get_hidl_instances(hidl_package, major_version, minor_version, hidl_interface_name);
184 }
185 FuzzCommand::GetAaid { aaid_uid } => {
186 let _res = get_aaid(aaid_uid);
187 }
188 FuzzCommand::Hal { opt, prompt_text, locale, extra_data } => {
189 let hal = ApcHal::try_get_service();
190 if hal.is_some() {
191 let hal = Arc::new(hal.unwrap());
192 let apc_compat_options = ui_opts_2_compat(opt);
193 let prompt_text =
194 std::str::from_utf8(get_valid_cstring_data(prompt_text.as_bytes()))
195 .unwrap();
196 let locale =
197 std::str::from_utf8(get_valid_cstring_data(locale.as_bytes())).unwrap();
198 let _res = hal.prompt_user_confirmation(
199 prompt_text,
200 extra_data,
201 locale,
202 apc_compat_options,
203 move |_, _, _| {},
204 );
205 }
206 }
207 FuzzCommand::Context { context } => {
208 let _res = Context::new(context);
209 }
210 FuzzCommand::Backend { namespace } => {
211 let backend = KeystoreKeyBackend::new();
212 if let Ok(backend) = backend {
213 let _res = backend.lookup(namespace);
214 }
215 }
216 FuzzCommand::CheckAccess { source, target, tclass, perm } => {
217 let source = get_valid_cstring_data(source);
218 let target = get_valid_cstring_data(target);
219 let _res = check_access(
220 &CString::new(source).unwrap(),
221 &CString::new(target).unwrap(),
222 tclass,
223 perm,
224 );
225 }
226 FuzzCommand::SetCon { set_target } => {
227 let _res = setcon(&CString::new(get_valid_cstring_data(set_target)).unwrap());
228 }
229 }
230 }
231 });
232