• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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