18e920a95Sopenharmony_ci/* 28e920a95Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 38e920a95Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48e920a95Sopenharmony_ci * you may not use this file except in compliance with the License. 58e920a95Sopenharmony_ci * You may obtain a copy of the License at 68e920a95Sopenharmony_ci * 78e920a95Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88e920a95Sopenharmony_ci * 98e920a95Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108e920a95Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118e920a95Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128e920a95Sopenharmony_ci * See the License for the specific language governing permissions and 138e920a95Sopenharmony_ci * limitations under the License. 148e920a95Sopenharmony_ci */ 158e920a95Sopenharmony_ci 168e920a95Sopenharmony_ciuse lazy_static::lazy_static; 178e920a95Sopenharmony_ciuse super::cert_chain_utils::PemCollection; 188e920a95Sopenharmony_ciuse super::cert_path_utils::{ 198e920a95Sopenharmony_ci add_cert_path_info, remove_cert_path_info, common_format_fabricate_name, 208e920a95Sopenharmony_ci DebugCertPathType, ReleaseCertPathType, TrustCertPath, 218e920a95Sopenharmony_ci}; 228e920a95Sopenharmony_ciuse super::cs_hisysevent::report_parse_profile_err; 238e920a95Sopenharmony_ciuse super::file_utils::{ 248e920a95Sopenharmony_ci create_file_path, delete_file_path, file_exists, fmt_store_path, 258e920a95Sopenharmony_ci load_bytes_from_file, write_bytes_to_file, change_default_mode_file, change_default_mode_directory 268e920a95Sopenharmony_ci}; 278e920a95Sopenharmony_ciuse hilog_rust::{error, info, hilog, HiLogLabel, LogType}; 288e920a95Sopenharmony_ciuse openssl::pkcs7::{Pkcs7, Pkcs7Flags}; 298e920a95Sopenharmony_ciuse openssl::stack::Stack; 308e920a95Sopenharmony_ciuse openssl::x509::store::{X509Store, X509StoreBuilder}; 318e920a95Sopenharmony_ciuse openssl::x509::{X509NameRef, X509}; 328e920a95Sopenharmony_ciuse std::error::Error; 338e920a95Sopenharmony_ciuse std::ffi::{c_char, CStr, CString}; 348e920a95Sopenharmony_ciuse std::fs::read_dir; 358e920a95Sopenharmony_ciuse ylong_json::JsonValue; 368e920a95Sopenharmony_ci 378e920a95Sopenharmony_ciconst ERROR_CODE: i32 = -1; 388e920a95Sopenharmony_ciconst SUCCESS_CODE: i32 = 0; 398e920a95Sopenharmony_ciconst LOG_LABEL: HiLogLabel = HiLogLabel { 408e920a95Sopenharmony_ci log_type: LogType::LogCore, 418e920a95Sopenharmony_ci domain: 0xd005a06, // security domain 428e920a95Sopenharmony_ci tag: "CODE_SIGN", 438e920a95Sopenharmony_ci}; 448e920a95Sopenharmony_ciconst PROFILE_STORE_EL0_PREFIX: &str = "/data/service/el0/profiles/developer"; 458e920a95Sopenharmony_ciconst PROFILE_STORE_EL1_PREFIX: &str = "/data/service/el1/profiles/release"; 468e920a95Sopenharmony_ciconst PROFILE_STORE_EL1_PUBLIC_PREFIX: &str = "/data/service/el1/public/profiles/release"; 478e920a95Sopenharmony_ciconst DEBUG_PROFILE_STORE_EL0_PREFIX: &str = "/data/service/el0/profiles/debug"; 488e920a95Sopenharmony_ciconst DEBUG_PROFILE_STORE_EL1_PREFIX: &str = "/data/service/el1/profiles/debug"; 498e920a95Sopenharmony_ciconst DEBUG_PROFILE_STORE_EL1_PUBLIC_PREFIX: &str = "/data/service/el1/public/profiles/debug"; 508e920a95Sopenharmony_ciconst PROFILE_STORE_TAIL: &str = "profile.p7b"; 518e920a95Sopenharmony_ciconst PROFILE_TYPE_KEY: &str = "type"; 528e920a95Sopenharmony_ciconst PROFILE_DEVICE_ID_TYPE_KEY: &str = "device-id-type"; 538e920a95Sopenharmony_ciconst PROFILE_DEBUG_INFO_KEY: &str = "debug-info"; 548e920a95Sopenharmony_ciconst PROFILE_DEVICE_IDS_KEY: &str = "device-ids"; 558e920a95Sopenharmony_ciconst PROFILE_BUNDLE_INFO_KEY: &str = "bundle-info"; 568e920a95Sopenharmony_ciconst PROFILE_BUNDLE_INFO_RELEASE_KEY: &str = "distribution-certificate"; 578e920a95Sopenharmony_ciconst PROFILE_BUNDLE_INFO_DEBUG_KEY: &str = "development-certificate"; 588e920a95Sopenharmony_ciconst PROFILE_APP_DISTRIBUTION_TYPE_KEY: &str = "app-distribution-type"; 598e920a95Sopenharmony_ciconst APP_DISTRIBUTION_TYPE_INTERNALTESTING: &str = "internaltesting"; 608e920a95Sopenharmony_ciconst APP_DISTRIBUTION_TYPE_ENTERPRISE: &str = "enterprise"; 618e920a95Sopenharmony_ciconst APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL: &str = "enterprise_normal"; 628e920a95Sopenharmony_ciconst APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM: &str = "enterprise_mdm"; 638e920a95Sopenharmony_ciconst DEFAULT_MAX_CERT_PATH_LEN: u32 = 3; 648e920a95Sopenharmony_ciconst PROFILE_RELEASE_TYPE: &str = "release"; 658e920a95Sopenharmony_ciconst PROFILE_DEBUG_TYPE: &str = "debug"; 668e920a95Sopenharmony_ci 678e920a95Sopenharmony_ci/// profile error 688e920a95Sopenharmony_cipub enum ProfileError { 698e920a95Sopenharmony_ci /// add cert path error 708e920a95Sopenharmony_ci AddCertPathError, 718e920a95Sopenharmony_ci} 728e920a95Sopenharmony_ci/// profile error report to hisysevent 738e920a95Sopenharmony_cipub enum HisyseventProfileError { 748e920a95Sopenharmony_ci /// release platform code 758e920a95Sopenharmony_ci VerifySigner = 1, 768e920a95Sopenharmony_ci /// release authed code 778e920a95Sopenharmony_ci ParsePkcs7 = 2, 788e920a95Sopenharmony_ci /// release developer code 798e920a95Sopenharmony_ci AddCertPath = 3, 808e920a95Sopenharmony_ci} 818e920a95Sopenharmony_ci 828e920a95Sopenharmony_ciextern "C" { 838e920a95Sopenharmony_ci /// if developer state on return true 848e920a95Sopenharmony_ci pub fn IsDeveloperModeOn() -> bool; 858e920a95Sopenharmony_ci fn CodeSignGetUdid(udid: *mut u8) -> i32; 868e920a95Sopenharmony_ci fn IsRdDevice() -> bool; 878e920a95Sopenharmony_ci} 888e920a95Sopenharmony_ci 898e920a95Sopenharmony_ci#[no_mangle] 908e920a95Sopenharmony_ci/// the interface to enable key in profile 918e920a95Sopenharmony_cipub extern "C" fn EnableKeyInProfileByRust( 928e920a95Sopenharmony_ci bundle_name: *const c_char, 938e920a95Sopenharmony_ci profile: *const u8, 948e920a95Sopenharmony_ci profile_size: u32, 958e920a95Sopenharmony_ci) -> i32 { 968e920a95Sopenharmony_ci match enable_key_in_profile_internal(bundle_name, profile, profile_size) { 978e920a95Sopenharmony_ci Ok(_) => SUCCESS_CODE, 988e920a95Sopenharmony_ci Err(_) => ERROR_CODE, 998e920a95Sopenharmony_ci } 1008e920a95Sopenharmony_ci} 1018e920a95Sopenharmony_ci 1028e920a95Sopenharmony_ci#[no_mangle] 1038e920a95Sopenharmony_ci/// the interface remove key in profile 1048e920a95Sopenharmony_cipub extern "C" fn RemoveKeyInProfileByRust(bundle_name: *const c_char) -> i32 { 1058e920a95Sopenharmony_ci match remove_key_in_profile_internal(bundle_name) { 1068e920a95Sopenharmony_ci Ok(_) => SUCCESS_CODE, 1078e920a95Sopenharmony_ci Err(_) => ERROR_CODE, 1088e920a95Sopenharmony_ci } 1098e920a95Sopenharmony_ci} 1108e920a95Sopenharmony_ci 1118e920a95Sopenharmony_cifn parse_pkcs7_data( 1128e920a95Sopenharmony_ci pkcs7: &Pkcs7, 1138e920a95Sopenharmony_ci root_store: &X509Store, 1148e920a95Sopenharmony_ci flags: Pkcs7Flags, 1158e920a95Sopenharmony_ci check_udid: bool, 1168e920a95Sopenharmony_ci) -> Result<(String, String, u32), Box<dyn Error>> { 1178e920a95Sopenharmony_ci let profile = verify_pkcs7_signature(pkcs7, root_store, flags)?; 1188e920a95Sopenharmony_ci let profile_json = parse_and_validate_profile(profile, check_udid)?; 1198e920a95Sopenharmony_ci get_cert_details(&profile_json) 1208e920a95Sopenharmony_ci} 1218e920a95Sopenharmony_ci 1228e920a95Sopenharmony_cifn verify_pkcs7_signature( 1238e920a95Sopenharmony_ci pkcs7: &Pkcs7, 1248e920a95Sopenharmony_ci root_store: &X509Store, 1258e920a95Sopenharmony_ci flags: Pkcs7Flags, 1268e920a95Sopenharmony_ci) -> Result<Vec<u8>, Box<dyn Error>> { 1278e920a95Sopenharmony_ci let stack_of_certs = Stack::<X509>::new()?; 1288e920a95Sopenharmony_ci let mut profile = Vec::new(); 1298e920a95Sopenharmony_ci pkcs7.verify(&stack_of_certs, root_store, None, Some(&mut profile), flags)?; 1308e920a95Sopenharmony_ci Ok(profile) 1318e920a95Sopenharmony_ci} 1328e920a95Sopenharmony_ci 1338e920a95Sopenharmony_ci/// validate bundle info and debug info 1348e920a95Sopenharmony_cipub fn validate_bundle_and_distribution_type( 1358e920a95Sopenharmony_ci profile_json: &JsonValue, 1368e920a95Sopenharmony_ci check_udid: bool, 1378e920a95Sopenharmony_ci) -> Result<(), Box<dyn Error>> { 1388e920a95Sopenharmony_ci let bundle_type = profile_json[PROFILE_TYPE_KEY].try_as_string()?.as_str(); 1398e920a95Sopenharmony_ci match bundle_type { 1408e920a95Sopenharmony_ci PROFILE_DEBUG_TYPE => { 1418e920a95Sopenharmony_ci if check_udid && verify_udid(profile_json).is_err() { 1428e920a95Sopenharmony_ci return Err("Invalid UDID.".into()); 1438e920a95Sopenharmony_ci } 1448e920a95Sopenharmony_ci }, 1458e920a95Sopenharmony_ci PROFILE_RELEASE_TYPE => { 1468e920a95Sopenharmony_ci let distribution_type = profile_json[PROFILE_APP_DISTRIBUTION_TYPE_KEY].try_as_string()?.as_str(); 1478e920a95Sopenharmony_ci match distribution_type { 1488e920a95Sopenharmony_ci APP_DISTRIBUTION_TYPE_INTERNALTESTING => { 1498e920a95Sopenharmony_ci if check_udid && verify_udid(profile_json).is_err() { 1508e920a95Sopenharmony_ci return Err("Invalid UDID.".into()); 1518e920a95Sopenharmony_ci } 1528e920a95Sopenharmony_ci }, 1538e920a95Sopenharmony_ci APP_DISTRIBUTION_TYPE_ENTERPRISE | 1548e920a95Sopenharmony_ci APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL | 1558e920a95Sopenharmony_ci APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM => { 1568e920a95Sopenharmony_ci }, 1578e920a95Sopenharmony_ci _ => { 1588e920a95Sopenharmony_ci return Err("Invalid app distribution type.".into()); 1598e920a95Sopenharmony_ci } 1608e920a95Sopenharmony_ci } 1618e920a95Sopenharmony_ci } 1628e920a95Sopenharmony_ci _ => { 1638e920a95Sopenharmony_ci return Err("Invalid bundle type.".into()); 1648e920a95Sopenharmony_ci }, 1658e920a95Sopenharmony_ci } 1668e920a95Sopenharmony_ci Ok(()) 1678e920a95Sopenharmony_ci} 1688e920a95Sopenharmony_ci 1698e920a95Sopenharmony_cifn parse_and_validate_profile( 1708e920a95Sopenharmony_ci profile: Vec<u8>, 1718e920a95Sopenharmony_ci check_udid: bool, 1728e920a95Sopenharmony_ci) -> Result<JsonValue, Box<dyn Error>> { 1738e920a95Sopenharmony_ci let profile_json = JsonValue::from_text(profile)?; 1748e920a95Sopenharmony_ci validate_bundle_and_distribution_type(&profile_json, check_udid)?; 1758e920a95Sopenharmony_ci Ok(profile_json) 1768e920a95Sopenharmony_ci} 1778e920a95Sopenharmony_ci 1788e920a95Sopenharmony_cifn get_cert_details(profile_json: &JsonValue) -> Result<(String, String, u32), Box<dyn Error>> { 1798e920a95Sopenharmony_ci let bundle_type = profile_json[PROFILE_TYPE_KEY].try_as_string()?.as_str(); 1808e920a95Sopenharmony_ci let profile_type = match bundle_type { 1818e920a95Sopenharmony_ci PROFILE_DEBUG_TYPE => DebugCertPathType::Developer as u32, 1828e920a95Sopenharmony_ci PROFILE_RELEASE_TYPE => ReleaseCertPathType::Developer as u32, 1838e920a95Sopenharmony_ci _ => return Err("Invalid bundle type.".into()), 1848e920a95Sopenharmony_ci }; 1858e920a95Sopenharmony_ci let signed_cert = match bundle_type { 1868e920a95Sopenharmony_ci PROFILE_DEBUG_TYPE => profile_json[PROFILE_BUNDLE_INFO_KEY][PROFILE_BUNDLE_INFO_DEBUG_KEY].try_as_string()?, 1878e920a95Sopenharmony_ci PROFILE_RELEASE_TYPE => profile_json[PROFILE_BUNDLE_INFO_KEY][PROFILE_BUNDLE_INFO_RELEASE_KEY].try_as_string()?, 1888e920a95Sopenharmony_ci _ => return Err("Invalid bundle type.".into()), 1898e920a95Sopenharmony_ci }; 1908e920a95Sopenharmony_ci let signed_pem = X509::from_pem(signed_cert.as_bytes())?; 1918e920a95Sopenharmony_ci let subject = format_x509_fabricate_name(signed_pem.subject_name()); 1928e920a95Sopenharmony_ci let issuer = format_x509_fabricate_name(signed_pem.issuer_name()); 1938e920a95Sopenharmony_ci Ok((subject, issuer, profile_type)) 1948e920a95Sopenharmony_ci} 1958e920a95Sopenharmony_ci 1968e920a95Sopenharmony_cilazy_static! { 1978e920a95Sopenharmony_ci /// global udid 1988e920a95Sopenharmony_ci pub static ref UDID: Result<String, String> = init_udid(); 1998e920a95Sopenharmony_ci} 2008e920a95Sopenharmony_ci 2018e920a95Sopenharmony_cifn init_udid() -> Result<String, String> { 2028e920a95Sopenharmony_ci let mut udid: Vec<u8> = vec![0; 128]; 2038e920a95Sopenharmony_ci let result = unsafe { CodeSignGetUdid(udid.as_mut_ptr()) }; 2048e920a95Sopenharmony_ci 2058e920a95Sopenharmony_ci if result != 0 { 2068e920a95Sopenharmony_ci return Err("Failed to get UDID".to_string()); 2078e920a95Sopenharmony_ci } 2088e920a95Sopenharmony_ci 2098e920a95Sopenharmony_ci if let Some(first_zero_index) = udid.iter().position(|&x| x == 0) { 2108e920a95Sopenharmony_ci udid.truncate(first_zero_index); 2118e920a95Sopenharmony_ci } 2128e920a95Sopenharmony_ci 2138e920a95Sopenharmony_ci match String::from_utf8(udid) { 2148e920a95Sopenharmony_ci Ok(s) => Ok(s), 2158e920a95Sopenharmony_ci Err(_) => Err("UDID is not valid UTF-8".to_string()), 2168e920a95Sopenharmony_ci } 2178e920a95Sopenharmony_ci} 2188e920a95Sopenharmony_ci 2198e920a95Sopenharmony_ci/// get device udid 2208e920a95Sopenharmony_cipub fn get_udid() -> Result<String, String> { 2218e920a95Sopenharmony_ci UDID.clone() 2228e920a95Sopenharmony_ci} 2238e920a95Sopenharmony_ci 2248e920a95Sopenharmony_ci 2258e920a95Sopenharmony_cifn verify_signers( 2268e920a95Sopenharmony_ci pkcs7: &Pkcs7, 2278e920a95Sopenharmony_ci profile_signer: &[(&String, &String)], 2288e920a95Sopenharmony_ci) -> Result<(), Box<dyn Error>> { 2298e920a95Sopenharmony_ci let stack_of_certs = Stack::<X509>::new()?; 2308e920a95Sopenharmony_ci let signers_result = pkcs7.signers(&stack_of_certs, Pkcs7Flags::empty())?; 2318e920a95Sopenharmony_ci for signer in signers_result { 2328e920a95Sopenharmony_ci let subject_name = format_x509name_to_string(signer.subject_name()); 2338e920a95Sopenharmony_ci let issuer_name = format_x509name_to_string(signer.issuer_name()); 2348e920a95Sopenharmony_ci if !profile_signer.contains(&(&subject_name, &issuer_name)) { 2358e920a95Sopenharmony_ci return Err("Verification failed.".into()); 2368e920a95Sopenharmony_ci } 2378e920a95Sopenharmony_ci } 2388e920a95Sopenharmony_ci Ok(()) 2398e920a95Sopenharmony_ci} 2408e920a95Sopenharmony_ci 2418e920a95Sopenharmony_cifn format_x509name_to_string(name: &X509NameRef) -> String { 2428e920a95Sopenharmony_ci let mut parts = Vec::new(); 2438e920a95Sopenharmony_ci 2448e920a95Sopenharmony_ci for entry in name.entries() { 2458e920a95Sopenharmony_ci let tag = match entry.object().nid() { 2468e920a95Sopenharmony_ci openssl::nid::Nid::COMMONNAME => "CN", 2478e920a95Sopenharmony_ci openssl::nid::Nid::COUNTRYNAME => "C", 2488e920a95Sopenharmony_ci openssl::nid::Nid::ORGANIZATIONNAME => "O", 2498e920a95Sopenharmony_ci openssl::nid::Nid::ORGANIZATIONALUNITNAME => "OU", 2508e920a95Sopenharmony_ci _ => continue, 2518e920a95Sopenharmony_ci }; 2528e920a95Sopenharmony_ci let value = entry.data().as_utf8().unwrap(); 2538e920a95Sopenharmony_ci parts.push(format!("{}={}", tag, value)); 2548e920a95Sopenharmony_ci } 2558e920a95Sopenharmony_ci parts.join(", ") 2568e920a95Sopenharmony_ci} 2578e920a95Sopenharmony_ci 2588e920a95Sopenharmony_cifn format_x509_fabricate_name(name: &X509NameRef) -> String { 2598e920a95Sopenharmony_ci let mut common_name = String::new(); 2608e920a95Sopenharmony_ci let mut organization = String::new(); 2618e920a95Sopenharmony_ci let mut email = String::new(); 2628e920a95Sopenharmony_ci 2638e920a95Sopenharmony_ci for entry in name.entries() { 2648e920a95Sopenharmony_ci let entry_nid = entry.object().nid(); 2658e920a95Sopenharmony_ci if let Ok(value) = entry.data().as_utf8() { 2668e920a95Sopenharmony_ci match entry_nid { 2678e920a95Sopenharmony_ci openssl::nid::Nid::COMMONNAME => common_name = value.to_string(), 2688e920a95Sopenharmony_ci openssl::nid::Nid::ORGANIZATIONNAME => organization = value.to_string(), 2698e920a95Sopenharmony_ci openssl::nid::Nid::PKCS9_EMAILADDRESS => email = value.to_string(), 2708e920a95Sopenharmony_ci _ => continue, 2718e920a95Sopenharmony_ci }; 2728e920a95Sopenharmony_ci } 2738e920a95Sopenharmony_ci } 2748e920a95Sopenharmony_ci let ret = common_format_fabricate_name(&common_name, &organization, &email); 2758e920a95Sopenharmony_ci ret 2768e920a95Sopenharmony_ci} 2778e920a95Sopenharmony_ci 2788e920a95Sopenharmony_cifn get_profile_paths(is_debug: bool) -> Vec<String> { 2798e920a95Sopenharmony_ci let mut paths = Vec::new(); 2808e920a95Sopenharmony_ci let profile_prefixes = match is_debug { 2818e920a95Sopenharmony_ci false => vec![PROFILE_STORE_EL0_PREFIX, PROFILE_STORE_EL1_PREFIX, PROFILE_STORE_EL1_PUBLIC_PREFIX], 2828e920a95Sopenharmony_ci true => vec![DEBUG_PROFILE_STORE_EL0_PREFIX, DEBUG_PROFILE_STORE_EL1_PREFIX, DEBUG_PROFILE_STORE_EL1_PUBLIC_PREFIX], 2838e920a95Sopenharmony_ci }; 2848e920a95Sopenharmony_ci for profile_prefix in profile_prefixes { 2858e920a95Sopenharmony_ci paths.extend(get_paths_from_prefix(profile_prefix)); 2868e920a95Sopenharmony_ci } 2878e920a95Sopenharmony_ci paths 2888e920a95Sopenharmony_ci} 2898e920a95Sopenharmony_ci 2908e920a95Sopenharmony_cifn get_paths_from_prefix(prefix: &str) -> Vec<String> { 2918e920a95Sopenharmony_ci let mut paths = Vec::new(); 2928e920a95Sopenharmony_ci if let Ok(entries) = read_dir(prefix) { 2938e920a95Sopenharmony_ci for entry in entries.filter_map(Result::ok) { 2948e920a95Sopenharmony_ci let path = entry.path(); 2958e920a95Sopenharmony_ci let filename = fmt_store_path(&path.to_string_lossy(), PROFILE_STORE_TAIL); 2968e920a95Sopenharmony_ci if file_exists(&filename) { 2978e920a95Sopenharmony_ci paths.push(filename); 2988e920a95Sopenharmony_ci } 2998e920a95Sopenharmony_ci } 3008e920a95Sopenharmony_ci } 3018e920a95Sopenharmony_ci paths 3028e920a95Sopenharmony_ci} 3038e920a95Sopenharmony_ci 3048e920a95Sopenharmony_ci/// add profile cert path data 3058e920a95Sopenharmony_cipub fn add_profile_cert_path( 3068e920a95Sopenharmony_ci root_cert: &PemCollection, 3078e920a95Sopenharmony_ci cert_paths: &TrustCertPath, 3088e920a95Sopenharmony_ci) -> Result<(), ProfileError> { 3098e920a95Sopenharmony_ci let x509_store = root_cert.to_x509_store().unwrap(); 3108e920a95Sopenharmony_ci if process_profile(false, &x509_store, cert_paths.get_profile_info().as_slice()).is_err() { 3118e920a95Sopenharmony_ci return Err(ProfileError::AddCertPathError); 3128e920a95Sopenharmony_ci } 3138e920a95Sopenharmony_ci if process_profile(true, &x509_store, cert_paths.get_debug_profile_info().as_slice()).is_err() { 3148e920a95Sopenharmony_ci return Err(ProfileError::AddCertPathError); 3158e920a95Sopenharmony_ci } 3168e920a95Sopenharmony_ci Ok(()) 3178e920a95Sopenharmony_ci} 3188e920a95Sopenharmony_ci 3198e920a95Sopenharmony_cifn process_profile( 3208e920a95Sopenharmony_ci is_debug: bool, 3218e920a95Sopenharmony_ci x509_store: &X509Store, 3228e920a95Sopenharmony_ci profile_info: &[(&String, &String)], 3238e920a95Sopenharmony_ci) -> Result<(), ProfileError> { 3248e920a95Sopenharmony_ci let profiles_paths = get_profile_paths(is_debug); 3258e920a95Sopenharmony_ci for path in profiles_paths { 3268e920a95Sopenharmony_ci let mut pkcs7_data = Vec::new(); 3278e920a95Sopenharmony_ci if load_bytes_from_file(&path, &mut pkcs7_data).is_err() { 3288e920a95Sopenharmony_ci info!(LOG_LABEL, "load profile failed {}!", @public(path)); 3298e920a95Sopenharmony_ci continue; 3308e920a95Sopenharmony_ci } 3318e920a95Sopenharmony_ci info!(LOG_LABEL, "load profile success {}!", @public(path)); 3328e920a95Sopenharmony_ci let pkcs7 = match Pkcs7::from_der(&pkcs7_data) { 3338e920a95Sopenharmony_ci Ok(pk7) => pk7, 3348e920a95Sopenharmony_ci Err(_) => { 3358e920a95Sopenharmony_ci error!(LOG_LABEL, "load profile to pkcs7 obj failed {}!", @public(path)); 3368e920a95Sopenharmony_ci continue; 3378e920a95Sopenharmony_ci } 3388e920a95Sopenharmony_ci }; 3398e920a95Sopenharmony_ci if verify_signers(&pkcs7, profile_info).is_err() { 3408e920a95Sopenharmony_ci error!(LOG_LABEL, "Invalid signer profile file {}", @public(path)); 3418e920a95Sopenharmony_ci report_parse_profile_err(&path, HisyseventProfileError::VerifySigner as i32); 3428e920a95Sopenharmony_ci continue; 3438e920a95Sopenharmony_ci } 3448e920a95Sopenharmony_ci let check_udid = unsafe { !IsRdDevice() }; 3458e920a95Sopenharmony_ci let (subject, issuer, profile_type) = 3468e920a95Sopenharmony_ci match parse_pkcs7_data(&pkcs7, x509_store, Pkcs7Flags::empty(), check_udid) { 3478e920a95Sopenharmony_ci Ok(tuple) => tuple, 3488e920a95Sopenharmony_ci Err(e) => { 3498e920a95Sopenharmony_ci error!(LOG_LABEL, "Error parsing PKCS7 data: {}, profile file {}", 3508e920a95Sopenharmony_ci @public(e), @public(path)); 3518e920a95Sopenharmony_ci report_parse_profile_err(&path, HisyseventProfileError::ParsePkcs7 as i32); 3528e920a95Sopenharmony_ci continue; 3538e920a95Sopenharmony_ci } 3548e920a95Sopenharmony_ci }; 3558e920a95Sopenharmony_ci if add_cert_path_info(subject, issuer, profile_type, DEFAULT_MAX_CERT_PATH_LEN).is_err() { 3568e920a95Sopenharmony_ci error!( 3578e920a95Sopenharmony_ci LOG_LABEL, 3588e920a95Sopenharmony_ci "Failed to add profile cert path info into ioctl for {}", @public(path) 3598e920a95Sopenharmony_ci ); 3608e920a95Sopenharmony_ci report_parse_profile_err(&path, HisyseventProfileError::AddCertPath as i32); 3618e920a95Sopenharmony_ci continue; 3628e920a95Sopenharmony_ci } 3638e920a95Sopenharmony_ci } 3648e920a95Sopenharmony_ci Ok(()) 3658e920a95Sopenharmony_ci} 3668e920a95Sopenharmony_ci 3678e920a95Sopenharmony_cifn verify_udid(profile_json: &JsonValue) -> Result<(), String> { 3688e920a95Sopenharmony_ci let device_udid = get_udid()?; 3698e920a95Sopenharmony_ci info!(LOG_LABEL, "get device udid {}!", device_udid); 3708e920a95Sopenharmony_ci let device_id_type = &profile_json[PROFILE_DEBUG_INFO_KEY][PROFILE_DEVICE_ID_TYPE_KEY]; 3718e920a95Sopenharmony_ci 3728e920a95Sopenharmony_ci if let JsonValue::String(id_type) = device_id_type { 3738e920a95Sopenharmony_ci if id_type != "udid" { 3748e920a95Sopenharmony_ci return Err("Invalid device ID type".to_string()); 3758e920a95Sopenharmony_ci } 3768e920a95Sopenharmony_ci } else { 3778e920a95Sopenharmony_ci return Err("Device ID type is not a string".to_string()); 3788e920a95Sopenharmony_ci } 3798e920a95Sopenharmony_ci match &profile_json[PROFILE_DEBUG_INFO_KEY][PROFILE_DEVICE_IDS_KEY] { 3808e920a95Sopenharmony_ci JsonValue::Array(arr) => { 3818e920a95Sopenharmony_ci if arr.iter().any(|item| match item { 3828e920a95Sopenharmony_ci JsonValue::String(s) => s == &device_udid, 3838e920a95Sopenharmony_ci _ => false, 3848e920a95Sopenharmony_ci }) { 3858e920a95Sopenharmony_ci Ok(()) 3868e920a95Sopenharmony_ci } else { 3878e920a95Sopenharmony_ci Err("UDID not found in the list".to_string()) 3888e920a95Sopenharmony_ci } 3898e920a95Sopenharmony_ci } 3908e920a95Sopenharmony_ci _ => Err("Device IDs are not in an array format".to_string()), 3918e920a95Sopenharmony_ci } 3928e920a95Sopenharmony_ci} 3938e920a95Sopenharmony_ci 3948e920a95Sopenharmony_cifn validate_and_convert_inputs( 3958e920a95Sopenharmony_ci bundle_name: *const c_char, 3968e920a95Sopenharmony_ci profile: *const u8, 3978e920a95Sopenharmony_ci profile_size: u32, 3988e920a95Sopenharmony_ci) -> Result<(String, Vec<u8>), ()> { 3998e920a95Sopenharmony_ci let _bundle_name = c_char_to_string(bundle_name); 4008e920a95Sopenharmony_ci if _bundle_name.is_empty() { 4018e920a95Sopenharmony_ci error!(LOG_LABEL, "invalid profile bundle name!"); 4028e920a95Sopenharmony_ci return Err(()); 4038e920a95Sopenharmony_ci } 4048e920a95Sopenharmony_ci let profile_data = cbyte_buffer_to_vec(profile, profile_size); 4058e920a95Sopenharmony_ci Ok((_bundle_name, profile_data)) 4068e920a95Sopenharmony_ci} 4078e920a95Sopenharmony_ci 4088e920a95Sopenharmony_cifn process_data(profile_data: &[u8]) -> Result<(String, String, u32), ()> { 4098e920a95Sopenharmony_ci let store = match X509StoreBuilder::new() { 4108e920a95Sopenharmony_ci Ok(store) => store.build(), 4118e920a95Sopenharmony_ci Err(_) => { 4128e920a95Sopenharmony_ci error!(LOG_LABEL, "Failed to build X509 store"); 4138e920a95Sopenharmony_ci return Err(()); 4148e920a95Sopenharmony_ci } 4158e920a95Sopenharmony_ci }; 4168e920a95Sopenharmony_ci 4178e920a95Sopenharmony_ci let pkcs7 = match Pkcs7::from_der(profile_data) { 4188e920a95Sopenharmony_ci Ok(pk7) => pk7, 4198e920a95Sopenharmony_ci Err(_) => { 4208e920a95Sopenharmony_ci error!(LOG_LABEL, "load profile to pkcs7 obj failed"); 4218e920a95Sopenharmony_ci return Err(()); 4228e920a95Sopenharmony_ci } 4238e920a95Sopenharmony_ci }; 4248e920a95Sopenharmony_ci 4258e920a95Sopenharmony_ci match parse_pkcs7_data(&pkcs7, &store, Pkcs7Flags::NOVERIFY, false) { 4268e920a95Sopenharmony_ci Ok(tuple) => Ok(tuple), 4278e920a95Sopenharmony_ci Err(_) => { 4288e920a95Sopenharmony_ci error!(LOG_LABEL, "parse pkcs7 data error"); 4298e920a95Sopenharmony_ci Err(()) 4308e920a95Sopenharmony_ci } 4318e920a95Sopenharmony_ci } 4328e920a95Sopenharmony_ci} 4338e920a95Sopenharmony_ci 4348e920a95Sopenharmony_cifn create_bundle_path(bundle_name: &str, profile_type: u32) -> Result<String, ()> { 4358e920a95Sopenharmony_ci let bundle_path = match profile_type { 4368e920a95Sopenharmony_ci value if value == DebugCertPathType::Developer as u32 => { 4378e920a95Sopenharmony_ci fmt_store_path(DEBUG_PROFILE_STORE_EL1_PUBLIC_PREFIX, bundle_name) 4388e920a95Sopenharmony_ci } 4398e920a95Sopenharmony_ci value if value == ReleaseCertPathType::Developer as u32 => { 4408e920a95Sopenharmony_ci fmt_store_path(PROFILE_STORE_EL1_PUBLIC_PREFIX, bundle_name) 4418e920a95Sopenharmony_ci } 4428e920a95Sopenharmony_ci _ => { 4438e920a95Sopenharmony_ci error!(LOG_LABEL, "invalid profile type"); 4448e920a95Sopenharmony_ci return Err(()); 4458e920a95Sopenharmony_ci } 4468e920a95Sopenharmony_ci }; 4478e920a95Sopenharmony_ci Ok(bundle_path) 4488e920a95Sopenharmony_ci} 4498e920a95Sopenharmony_ci 4508e920a95Sopenharmony_cifn enable_key_in_profile_internal( 4518e920a95Sopenharmony_ci bundle_name: *const c_char, 4528e920a95Sopenharmony_ci profile: *const u8, 4538e920a95Sopenharmony_ci profile_size: u32, 4548e920a95Sopenharmony_ci) -> Result<(), ()> { 4558e920a95Sopenharmony_ci let (_bundle_name, profile_data) = validate_and_convert_inputs(bundle_name, profile, profile_size)?; 4568e920a95Sopenharmony_ci let (subject, issuer, profile_type) = process_data(&profile_data)?; 4578e920a95Sopenharmony_ci let bundle_path = create_bundle_path(&_bundle_name, profile_type)?; 4588e920a95Sopenharmony_ci info!(LOG_LABEL, "create bundle_path path {}!", @public(bundle_path)); 4598e920a95Sopenharmony_ci if !file_exists(&bundle_path) && create_file_path(&bundle_path).is_err() { 4608e920a95Sopenharmony_ci error!(LOG_LABEL, "create bundle_path path {} failed!", @public(bundle_path)); 4618e920a95Sopenharmony_ci return Err(()); 4628e920a95Sopenharmony_ci } 4638e920a95Sopenharmony_ci if change_default_mode_directory(&bundle_path).is_err() { 4648e920a95Sopenharmony_ci error!(LOG_LABEL, "change bundle_path mode error!"); 4658e920a95Sopenharmony_ci return Err(()); 4668e920a95Sopenharmony_ci } 4678e920a95Sopenharmony_ci let filename = fmt_store_path(&bundle_path, PROFILE_STORE_TAIL); 4688e920a95Sopenharmony_ci if write_bytes_to_file(&filename, &profile_data).is_err() { 4698e920a95Sopenharmony_ci error!(LOG_LABEL, "dump profile data error!"); 4708e920a95Sopenharmony_ci return Err(()); 4718e920a95Sopenharmony_ci } 4728e920a95Sopenharmony_ci if change_default_mode_file(&filename).is_err() { 4738e920a95Sopenharmony_ci error!(LOG_LABEL, "change profile mode error!"); 4748e920a95Sopenharmony_ci return Err(()); 4758e920a95Sopenharmony_ci } 4768e920a95Sopenharmony_ci if add_cert_path_info(subject, issuer, profile_type, DEFAULT_MAX_CERT_PATH_LEN).is_err() { 4778e920a95Sopenharmony_ci error!(LOG_LABEL, "add profile data error!"); 4788e920a95Sopenharmony_ci return Err(()); 4798e920a95Sopenharmony_ci } 4808e920a95Sopenharmony_ci info!(LOG_LABEL, "finish add cert path in ioctl!"); 4818e920a95Sopenharmony_ci Ok(()) 4828e920a95Sopenharmony_ci} 4838e920a95Sopenharmony_ci 4848e920a95Sopenharmony_cifn process_remove_bundle( 4858e920a95Sopenharmony_ci prefix: &str, 4868e920a95Sopenharmony_ci bundle_name: &str, 4878e920a95Sopenharmony_ci) -> Result<(), ()> { 4888e920a95Sopenharmony_ci let bundle_path = fmt_store_path(prefix, bundle_name); 4898e920a95Sopenharmony_ci 4908e920a95Sopenharmony_ci if !file_exists(&bundle_path) { 4918e920a95Sopenharmony_ci return Err(()); 4928e920a95Sopenharmony_ci } 4938e920a95Sopenharmony_ci 4948e920a95Sopenharmony_ci let filename = fmt_store_path(&bundle_path, PROFILE_STORE_TAIL); 4958e920a95Sopenharmony_ci let mut profile_data = Vec::new(); 4968e920a95Sopenharmony_ci if load_bytes_from_file(&filename, &mut profile_data).is_err() { 4978e920a95Sopenharmony_ci error!(LOG_LABEL, "load profile data error!"); 4988e920a95Sopenharmony_ci return Err(()); 4998e920a95Sopenharmony_ci } 5008e920a95Sopenharmony_ci 5018e920a95Sopenharmony_ci let (subject, issuer, profile_type) = process_data(&profile_data)?; 5028e920a95Sopenharmony_ci if delete_file_path(&bundle_path).is_err() { 5038e920a95Sopenharmony_ci error!(LOG_LABEL, "remove profile data error!"); 5048e920a95Sopenharmony_ci return Err(()); 5058e920a95Sopenharmony_ci } 5068e920a95Sopenharmony_ci 5078e920a95Sopenharmony_ci info!(LOG_LABEL, "remove bundle_path path {}!", @public(bundle_path)); 5088e920a95Sopenharmony_ci 5098e920a95Sopenharmony_ci if remove_cert_path_info(subject, issuer, profile_type, DEFAULT_MAX_CERT_PATH_LEN).is_err() { 5108e920a95Sopenharmony_ci error!(LOG_LABEL, "remove profile data error!"); 5118e920a95Sopenharmony_ci return Err(()); 5128e920a95Sopenharmony_ci } 5138e920a95Sopenharmony_ci 5148e920a95Sopenharmony_ci info!(LOG_LABEL, "finish remove cert path in ioctl!"); 5158e920a95Sopenharmony_ci Ok(()) 5168e920a95Sopenharmony_ci} 5178e920a95Sopenharmony_ci 5188e920a95Sopenharmony_cifn remove_key_in_profile_internal(bundle_name: *const c_char) -> Result<(), ()> { 5198e920a95Sopenharmony_ci let _bundle_name = c_char_to_string(bundle_name); 5208e920a95Sopenharmony_ci if _bundle_name.is_empty() { 5218e920a95Sopenharmony_ci error!(LOG_LABEL, "Invalid bundle name"); 5228e920a95Sopenharmony_ci return Err(()); 5238e920a95Sopenharmony_ci } 5248e920a95Sopenharmony_ci 5258e920a95Sopenharmony_ci let profile_prefix = vec![ 5268e920a95Sopenharmony_ci DEBUG_PROFILE_STORE_EL0_PREFIX, 5278e920a95Sopenharmony_ci PROFILE_STORE_EL0_PREFIX, 5288e920a95Sopenharmony_ci DEBUG_PROFILE_STORE_EL1_PREFIX, 5298e920a95Sopenharmony_ci PROFILE_STORE_EL1_PREFIX, 5308e920a95Sopenharmony_ci DEBUG_PROFILE_STORE_EL1_PUBLIC_PREFIX, 5318e920a95Sopenharmony_ci PROFILE_STORE_EL1_PUBLIC_PREFIX, 5328e920a95Sopenharmony_ci ]; 5338e920a95Sopenharmony_ci 5348e920a95Sopenharmony_ci let mut rm_succ = false; 5358e920a95Sopenharmony_ci for prefix in profile_prefix { 5368e920a95Sopenharmony_ci if process_remove_bundle(prefix, &_bundle_name).is_ok() { 5378e920a95Sopenharmony_ci rm_succ = true; 5388e920a95Sopenharmony_ci } 5398e920a95Sopenharmony_ci } 5408e920a95Sopenharmony_ci if rm_succ { 5418e920a95Sopenharmony_ci Ok(()) 5428e920a95Sopenharmony_ci } else { 5438e920a95Sopenharmony_ci error!(LOG_LABEL, "Failed to remove bundle profile info, bundleName: {}.", @public(_bundle_name)); 5448e920a95Sopenharmony_ci Err(()) 5458e920a95Sopenharmony_ci } 5468e920a95Sopenharmony_ci} 5478e920a95Sopenharmony_ci 5488e920a95Sopenharmony_cifn c_char_to_string(c_str: *const c_char) -> String { 5498e920a95Sopenharmony_ci unsafe { 5508e920a95Sopenharmony_ci if c_str.is_null() { 5518e920a95Sopenharmony_ci return String::new(); 5528e920a95Sopenharmony_ci } 5538e920a95Sopenharmony_ci let c_str = CStr::from_ptr(c_str); 5548e920a95Sopenharmony_ci c_str.to_string_lossy().to_string() 5558e920a95Sopenharmony_ci } 5568e920a95Sopenharmony_ci} 5578e920a95Sopenharmony_ci 5588e920a95Sopenharmony_cifn cbyte_buffer_to_vec(data: *const u8, size: u32) -> Vec<u8> { 5598e920a95Sopenharmony_ci unsafe { 5608e920a95Sopenharmony_ci if data.is_null() { 5618e920a95Sopenharmony_ci return Vec::new(); 5628e920a95Sopenharmony_ci } 5638e920a95Sopenharmony_ci let data_slice = std::slice::from_raw_parts(data, size as usize); 5648e920a95Sopenharmony_ci let mut result = Vec::with_capacity(size as usize); 5658e920a95Sopenharmony_ci result.extend_from_slice(data_slice); 5668e920a95Sopenharmony_ci result 5678e920a95Sopenharmony_ci } 5688e920a95Sopenharmony_ci} 569