From ab07eb6f4a7df73aac12f295fb5b6775c1f14961 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 6 Apr 2024 16:22:59 +0800 Subject: [PATCH] Fix. Remove strange cert dir created by 1.2.3 (#7620) * Fix. Remove strange cert dir created by 1.2.3 1. Remove `install_cert()`. 2. https://github.com/rustdesk/rustdesk/discussions/6444#discussioncomment-9017532 Signed-off-by: fufesou * comments Signed-off-by: fufesou --------- Signed-off-by: fufesou --- build.rs | 4 +- src/core_main.rs | 20 -- src/platform/windows.rs | 261 +---------------------- src/platform/windows_delete_test_cert.cc | 261 +++++++++++++++++++++++ 4 files changed, 269 insertions(+), 277 deletions(-) create mode 100644 src/platform/windows_delete_test_cert.cc diff --git a/build.rs b/build.rs index 47526d639..d332a43a2 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,11 @@ #[cfg(windows)] fn build_windows() { let file = "src/platform/windows.cc"; - cc::Build::new().file(file).compile("windows"); + let file2 = "src/platform/windows_delete_test_cert.cc"; + cc::Build::new().file(file).file(file2).compile("windows"); println!("cargo:rustc-link-lib=WtsApi32"); println!("cargo:rerun-if-changed={}", file); + println!("cargo:rerun-if-changed={}", file2); } #[cfg(target_os = "macos")] diff --git a/src/core_main.rs b/src/core_main.rs index caac2ca99..2d36097eb 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -208,31 +208,11 @@ pub fn core_main() -> Option> { .show() .ok(); return None; - } else if args[0] == "--install-cert" { - #[cfg(windows)] - hbb_common::allow_err!(crate::platform::windows::install_cert( - crate::platform::windows::DRIVER_CERT_FILE - )); - if args.len() > 1 && args[1] == "silent" { - return None; - } - #[cfg(all(windows, feature = "virtual_display_driver"))] - if crate::virtual_display_manager::is_virtual_display_supported() { - hbb_common::allow_err!(crate::virtual_display_manager::install_update_driver()); - } - return None; } else if args[0] == "--uninstall-cert" { #[cfg(windows)] hbb_common::allow_err!(crate::platform::windows::uninstall_cert()); return None; } else if args[0] == "--install-idd" { - #[cfg(windows)] - { - // It's ok to install cert multiple times. - hbb_common::allow_err!(crate::platform::windows::install_cert( - crate::platform::windows::DRIVER_CERT_FILE - )); - } #[cfg(all(windows, feature = "virtual_display_driver"))] if crate::virtual_display_manager::is_virtual_display_supported() { hbb_common::allow_err!(crate::virtual_display_manager::install_update_driver()); diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 0659422ef..2100c1144 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1187,17 +1187,6 @@ if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name} ); let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_string(); - let install_cert = if options.contains("driverCert") { - let s = format!(r#""{}" --install-cert"#, src_exe); - if silent { - format!("{} silent", s) - } else { - s - } - } else { - "".to_owned() - }; - // potential bug here: if run_cmd cancelled, but config file is changed. if let Some(lic) = get_license() { Config::set_option("key".into(), lic.key); @@ -1241,7 +1230,6 @@ cscript \"{uninstall_shortcut}\" copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\" {dels} {import_config} -{install_cert} {after_install} {sleep} ", @@ -1958,251 +1946,20 @@ pub fn user_accessible_folder() -> ResultType { Ok(dir) } -#[inline] -pub fn install_cert(cert_file: &str) -> ResultType<()> { - let exe_file = std::env::current_exe()?; - if let Some(cur_dir) = exe_file.parent() { - allow_err!(cert::install_cert(cur_dir.join(cert_file))); - } else { - bail!( - "Invalid exe parent for {}", - exe_file.to_string_lossy().as_ref() - ); - } - Ok(()) -} - #[inline] pub fn uninstall_cert() -> ResultType<()> { cert::uninstall_cert() } mod cert { - use hbb_common::{bail, log, ResultType}; - use std::{ffi::OsStr, io::Error, os::windows::ffi::OsStrExt, path::Path, str::from_utf8}; - use winapi::{ - shared::{ - minwindef::{BYTE, DWORD, FALSE, TRUE}, - ntdef::NULL, - }, - um::{ - wincrypt::{ - CertAddEncodedCertificateToStore, CertCloseStore, CertDeleteCertificateFromStore, - CertEnumCertificatesInStore, CertNameToStrA, CertOpenStore, CryptHashCertificate, - ALG_ID, CALG_SHA1, CERT_ID_SHA1_HASH, CERT_STORE_ADD_REPLACE_EXISTING, - CERT_STORE_PROV_SYSTEM_W, CERT_SYSTEM_STORE_LOCAL_MACHINE, CERT_X500_NAME_STR, - PCCERT_CONTEXT, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING, - }, - winreg::HKEY_LOCAL_MACHINE, - }, - }; - use winreg::{ - enums::{KEY_WRITE, REG_BINARY}, - RegKey, - }; + use hbb_common::ResultType; - const ROOT_CERT_STORE_PATH: &str = - "SOFTWARE\\Microsoft\\SystemCertificates\\ROOT\\Certificates\\"; - const THUMBPRINT_ALG: ALG_ID = CALG_SHA1; - const THUMBPRINT_LEN: DWORD = 20; - const CERT_ISSUER_1: &str = "CN=\"WDKTestCert admin,133225435702113567\"\0"; - const CERT_ENCODING_TYPE: DWORD = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; - - lazy_static::lazy_static! { - static ref CERT_STORE_LOC: Vec = OsStr::new("ROOT\0").encode_wide().collect::>(); + extern "C" { + fn DeleteRustDeskTestCertsW(); } - - #[inline] - unsafe fn compute_thumbprint(pb_encoded: *const BYTE, cb_encoded: DWORD) -> (Vec, String) { - let mut size = THUMBPRINT_LEN; - let mut thumbprint = [0u8; THUMBPRINT_LEN as usize]; - if CryptHashCertificate( - 0, - THUMBPRINT_ALG, - 0, - pb_encoded, - cb_encoded, - thumbprint.as_mut_ptr(), - &mut size, - ) == TRUE - { - ( - thumbprint.to_vec(), - hex::encode(thumbprint).to_ascii_uppercase(), - ) - } else { - (thumbprint.to_vec(), "".to_owned()) - } - } - - #[inline] - unsafe fn open_reg_cert_store() -> ResultType { - let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); - Ok(hklm.open_subkey_with_flags(ROOT_CERT_STORE_PATH, KEY_WRITE)?) - } - - // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gpef/6a9e35fa-2ac7-4c10-81e1-eabe8d2472f1 - fn create_cert_blob(thumbprint: Vec, encoded: Vec) -> Vec { - let mut blob = Vec::new(); - - let mut property_id = (CERT_ID_SHA1_HASH as u32).to_le_bytes().to_vec(); - let mut pro_reserved = [0x01, 0x00, 0x00, 0x00].to_vec(); - let mut pro_length = (THUMBPRINT_LEN as u32).to_le_bytes().to_vec(); - let mut pro_val = thumbprint; - blob.append(&mut property_id); - blob.append(&mut pro_reserved); - blob.append(&mut pro_length); - blob.append(&mut pro_val); - - let mut blob_reserved = [0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00].to_vec(); - let mut blob_length = (encoded.len() as u32).to_le_bytes().to_vec(); - let mut blob_val = encoded; - blob.append(&mut blob_reserved); - blob.append(&mut blob_length); - blob.append(&mut blob_val); - - blob - } - - pub fn install_cert>(path: P) -> ResultType<()> { - let mut cert_bytes = std::fs::read(path)?; - install_cert_reg(&mut cert_bytes)?; - install_cert_add_cert_store(&mut cert_bytes)?; - Ok(()) - } - - fn install_cert_reg(cert_bytes: &mut [u8]) -> ResultType<()> { - unsafe { - let thumbprint = compute_thumbprint(cert_bytes.as_mut_ptr(), cert_bytes.len() as _); - log::debug!("Thumbprint of cert {}", &thumbprint.1); - - let reg_cert_key = open_reg_cert_store()?; - let (cert_key, _) = reg_cert_key.create_subkey(&thumbprint.1)?; - let data = winreg::RegValue { - vtype: REG_BINARY, - bytes: create_cert_blob(thumbprint.0, cert_bytes.to_vec()), - }; - cert_key.set_raw_value("Blob", &data)?; - } - Ok(()) - } - - fn install_cert_add_cert_store(cert_bytes: &mut [u8]) -> ResultType<()> { - unsafe { - let store_handle = CertOpenStore( - CERT_STORE_PROV_SYSTEM_W, - 0, - 0, - CERT_SYSTEM_STORE_LOCAL_MACHINE, - CERT_STORE_LOC.as_ptr() as _, - ); - if store_handle.is_null() { - bail!( - "Error opening certificate store: {}", - Error::last_os_error() - ); - } - - // Create the certificate context - let cert_context = winapi::um::wincrypt::CertCreateCertificateContext( - CERT_ENCODING_TYPE, - cert_bytes.as_ptr(), - cert_bytes.len() as DWORD, - ); - if cert_context.is_null() { - bail!( - "Error creating certificate context: {}", - Error::last_os_error() - ); - } - - if FALSE - == CertAddEncodedCertificateToStore( - store_handle, - CERT_ENCODING_TYPE, - (*cert_context).pbCertEncoded, - (*cert_context).cbCertEncoded, - CERT_STORE_ADD_REPLACE_EXISTING, - std::ptr::null_mut(), - ) - { - log::error!( - "Failed to call CertAddEncodedCertificateToStore: {}", - Error::last_os_error() - ); - } else { - log::info!("Add cert to store successfully"); - } - - CertCloseStore(store_handle, 0); - } - Ok(()) - } - - fn get_thumbprints_to_rm() -> ResultType> { - let issuers_to_rm = [CERT_ISSUER_1]; - - let mut thumbprints = Vec::new(); - let mut buf = [0u8; 1024]; - - unsafe { - let store_handle = CertOpenStore( - CERT_STORE_PROV_SYSTEM_W, - 0, - 0, - CERT_SYSTEM_STORE_LOCAL_MACHINE, - CERT_STORE_LOC.as_ptr() as _, - ); - if store_handle.is_null() { - bail!( - "Error opening certificate store: {}", - Error::last_os_error() - ); - } - - let mut cert_ctx: PCCERT_CONTEXT = CertEnumCertificatesInStore(store_handle, NULL as _); - while !cert_ctx.is_null() { - // https://stackoverflow.com/a/66432736 - let cb_size = CertNameToStrA( - (*cert_ctx).dwCertEncodingType, - &mut ((*(*cert_ctx).pCertInfo).Issuer) as _, - CERT_X500_NAME_STR, - buf.as_mut_ptr() as _, - buf.len() as _, - ); - if cb_size != 1 { - if let Ok(issuer) = from_utf8(&buf[..cb_size as _]) { - for iss in issuers_to_rm.iter() { - if issuer == *iss { - let (_, thumbprint) = compute_thumbprint( - (*cert_ctx).pbCertEncoded, - (*cert_ctx).cbCertEncoded, - ); - if !thumbprint.is_empty() { - thumbprints.push(thumbprint); - } - // Delete current cert context and re-enumerate. - CertDeleteCertificateFromStore(cert_ctx); - cert_ctx = CertEnumCertificatesInStore(store_handle, NULL as _); - } - } - } - } - cert_ctx = CertEnumCertificatesInStore(store_handle, cert_ctx); - } - CertCloseStore(store_handle, 0); - } - - Ok(thumbprints) - } - pub fn uninstall_cert() -> ResultType<()> { - let thumbprints = get_thumbprints_to_rm()?; - let reg_cert_key = unsafe { open_reg_cert_store()? }; - log::info!("Found {} certs to remove", thumbprints.len()); - for thumbprint in thumbprints.iter() { - // Deleting cert from registry may fail, because the CertDeleteCertificateFromStore() is called before. - let _ = reg_cert_key.delete_subkey(thumbprint); + unsafe { + DeleteRustDeskTestCertsW(); } Ok(()) } @@ -2449,14 +2206,6 @@ pub fn try_kill_broker() { #[cfg(test)] mod tests { use super::*; - #[test] - fn test_install_cert() { - println!( - "install driver cert: {:?}", - cert::install_cert("RustDeskIddDriver.cer") - ); - } - #[test] fn test_uninstall_cert() { println!("uninstall driver certs: {:?}", cert::uninstall_cert()); diff --git a/src/platform/windows_delete_test_cert.cc b/src/platform/windows_delete_test_cert.cc new file mode 100644 index 000000000..8c5dc057a --- /dev/null +++ b/src/platform/windows_delete_test_cert.cc @@ -0,0 +1,261 @@ +// https://github.com/rustdesk/rustdesk/discussions/6444#discussioncomment-9010062 + +#include +#include +#include + +//************************************************************* +// +// RegDelnodeRecurseW() +// +// Purpose: Deletes a registry key and all its subkeys / values. +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// bOneLevel - Delete lpSubKey and its first level subdirectory +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +// Note: If bOneLevel is TRUE, only current key and its first level subkeys are deleted. +// The first level subkeys are deleted only if they do not have subkeys. +// +// If some subkeys have subkeys, but the previous empty subkeys are deleted. +// It's ok for the certificates, because the empty subkeys are not used +// and they can be created automatically. +// +//************************************************************* + +BOOL RegDelnodeRecurseW(HKEY hKeyRoot, LPWSTR lpSubKey, BOOL bOneLevel) +{ + LPWSTR lpEnd; + LONG lResult; + DWORD dwSize; + WCHAR szName[MAX_PATH]; + HKEY hKey; + FILETIME ftWrite; + + // First, see if we can delete the key without having + // to recurse. + + lResult = RegDeleteKeyW(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) + return TRUE; + + lResult = RegOpenKeyExW(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) + { + if (lResult == ERROR_FILE_NOT_FOUND) { + //printf("Key not found.\n"); + return TRUE; + } + else { + //printf("Error opening key.\n"); + return FALSE; + } + } + + // Check for an ending slash and add one if it is missing. + + lpEnd = lpSubKey + lstrlenW(lpSubKey); + + if (*(lpEnd - 1) != L'\\') + { + *lpEnd = L'\\'; + lpEnd++; + *lpEnd = L'\0'; + } + + // Enumerate the keys + + dwSize = MAX_PATH; + lResult = RegEnumKeyExW(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + if (lResult == ERROR_SUCCESS) + { + do { + + *lpEnd = L'\0'; + StringCchCatW(lpSubKey, MAX_PATH * 2, szName); + + if (bOneLevel) { + lResult = RegDeleteKeyW(hKeyRoot, lpSubKey); + if (lResult != ERROR_SUCCESS) { + return FALSE; + } + } + else { + if (!RegDelnodeRecurseW(hKeyRoot, lpSubKey, bOneLevel)) { + break; + } + } + + dwSize = MAX_PATH; + + lResult = RegEnumKeyExW(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + } while (lResult == ERROR_SUCCESS); + } + + lpEnd--; + *lpEnd = L'\0'; + + RegCloseKey(hKey); + + // Try again to delete the key. + + lResult = RegDeleteKeyW(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) + return TRUE; + + return FALSE; +} + +//************************************************************* +// +// RegDelnodeW() +// +// Purpose: Deletes a registry key and all its subkeys / values. +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// bOneLevel - Delete lpSubKey and its first level subdirectory +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +//************************************************************* + +BOOL RegDelnodeW(HKEY hKeyRoot, LPCWSTR lpSubKey, BOOL bOneLevel) +{ + //return FALSE; // For Testing + + WCHAR szDelKey[MAX_PATH * 2]; + + StringCchCopyW(szDelKey, MAX_PATH * 2, lpSubKey); + return RegDelnodeRecurseW(hKeyRoot, szDelKey, bOneLevel); + +} + +//************************************************************* +// +// DeleteRustDeskTestCertsW_SingleHive() +// +// Purpose: Deletes RustDesk Test certificates and wrong key stores +// +// Parameters: RootKey - Root key +// Prefix - SID if RootKey=HKEY_USERS +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +//************************************************************* + +BOOL DeleteRustDeskTestCertsW_SingleHive(HKEY RootKey, LPWSTR Prefix = NULL) { + // WDKTestCert to be removed from all stores + LPCWSTR lpCertFingerPrint = L"D1DBB672D5A500B9809689CAEA1CE49E799767F0"; + + // Wrong key stores to be removed completely + LPCSTR RootName = "ROOT"; + LPWSTR SubKeyPrefix = (LPWSTR)RootName; // sic! Convert of ANSI to UTF-16 + + LPWSTR lpSystemCertificatesPath = (LPWSTR)malloc(512 * sizeof(WCHAR)); + if (lpSystemCertificatesPath == 0) return FALSE; + if (Prefix == NULL) { + wsprintfW(lpSystemCertificatesPath, L"Software\\Microsoft\\SystemCertificates"); + } + else { + wsprintfW(lpSystemCertificatesPath, L"%s\\Software\\Microsoft\\SystemCertificates", Prefix); + } + + HKEY hRegSystemCertificates; + LONG res = RegOpenKeyExW(RootKey, lpSystemCertificatesPath, NULL, KEY_ALL_ACCESS, &hRegSystemCertificates); + if (res != ERROR_SUCCESS) + return FALSE; + + for (DWORD Index = 0; ; Index++) { + LPWSTR SubKeyName = (LPWSTR)malloc(255 * sizeof(WCHAR)); + if (SubKeyName == 0) break; + DWORD cName = 255; + LONG res = RegEnumKeyExW(hRegSystemCertificates, Index, SubKeyName, &cName, NULL, NULL, NULL, NULL); + if ((res != ERROR_SUCCESS) || (SubKeyName == NULL)) + break; + + // Remove test certificate + LPWSTR Complete = (LPWSTR)malloc(512 * sizeof(WCHAR)); + if (Complete == 0) break; + wsprintfW(Complete, L"%s\\%s\\Certificates\\%s", lpSystemCertificatesPath, SubKeyName, lpCertFingerPrint); + std::wcout << "Try delete from: " << SubKeyName << std::endl; + RegDelnodeW(RootKey, Complete, FALSE); + free(Complete); + + if ((SubKeyName[0] == SubKeyPrefix[0]) && (SubKeyName[1] == SubKeyPrefix[1])) { + // "Chinese Characters" key begins with "ROOT" encoded as UTF-16 + LPWSTR Complete = (LPWSTR)malloc(512 * sizeof(WCHAR)); + if (Complete == 0) break; + wsprintfW(Complete, L"%s\\%s", lpSystemCertificatesPath, SubKeyName); + if (RegDelnodeW(RootKey, Complete, TRUE)) { + //std::wcout << "Rogue Key Deleted! \"" << Complete << "\"" << std::endl; // TODO: Why does this break the console? + std::wcout << "Rogue key is deleted!" << std::endl; + Index--; // Because index has moved due to the deletion + } else { + std::wcout << "Rogue key deletion failed!" << std::endl; + } + free(Complete); + } + + free(SubKeyName); + } + RegCloseKey(hRegSystemCertificates); + return TRUE; +} + +//************************************************************* +// +// DeleteRustDeskTestCertsW() +// +// Purpose: Deletes RustDesk Test certificates and wrong key stores +// +// Parameters: None +// +// Return: None +// +//************************************************************* + +extern "C" void DeleteRustDeskTestCertsW() { + // Current user + std::wcout << "*** Current User" << std::endl; + DeleteRustDeskTestCertsW_SingleHive(HKEY_CURRENT_USER); + + // Local machine (requires admin rights) + std::wcout << "*** Local Machine" << std::endl; + DeleteRustDeskTestCertsW_SingleHive(HKEY_LOCAL_MACHINE); + + // Iterate through all users (requires admin rights) + LPCWSTR lpRoot = L""; + HKEY hRegUsers; + LONG res = RegOpenKeyExW(HKEY_USERS, lpRoot, NULL, KEY_READ, &hRegUsers); + if (res != ERROR_SUCCESS) return; + for (DWORD Index = 0; ; Index++) { + LPWSTR SubKeyName = (LPWSTR)malloc(255 * sizeof(WCHAR)); + if (SubKeyName == 0) break; + DWORD cName = 255; + LONG res = RegEnumKeyExW(hRegUsers, Index, SubKeyName, &cName, NULL, NULL, NULL, NULL); + if ((res != ERROR_SUCCESS) || (SubKeyName == NULL)) + break; + std::wcout << "*** User: " << SubKeyName << std::endl; + DeleteRustDeskTestCertsW_SingleHive(HKEY_USERS, SubKeyName); + } + RegCloseKey(hRegUsers); +} + +// int main() +// { +// DeleteRustDeskTestCertsW(); +// return 0; +// }