{{Header}} {{title|title= {{project_name_long}} Windows Installer - Design Documentation }} {{#seo: |description=The Whonix Windows Installer was designed as a simple and fast way to set-up Whonix on a system running Microsoft Windows. }} <div class="mininav"> * [[File:Windows logo - 2012.svg.png|25px|link=]] [[Dev/Windows Installer]] * [[File:Windows logo - 2012.svg.png|25px|link=]] [[Dev/Windows Starter]] * [[File:Tux.png|25px|link=]] {{kicksecure_wiki |wikipage=Dev/Linux_Installer |text=Dev/Linux Installer }} </div> {{intro| The Whonix Windows Installer was designed as a simple and fast way to set-up Whonix on a system running Microsoft Windows. }} = Design / Features = * https://github.com/Whonix/Whonix-Installer * https://github.com/Whonix/Whonix-Starter WhonixStarter(.exe): * new implementation of whonix.exe in lazarus (without NET framework) * platform independent ( later linux/mac version possible ) * ui consists of two forms ( main & error ) * main form has two buttons for start/stop and manage Whonix VMs * error form pops up if virtualbox is missing WhonixStarterSetup.msi: * installs windows version of WhonixStarter * adds start menu entry * adds desktop shortcut * uninstall over Windows "Programs and Features" tool WhonixSetup(.exe): * ui consists of a main form with several pages guiding the user through the installation process * platform independent ( later linux/mac version possible ) * installs VirtualBox and WhonixOVA * executes WhonixStarterSetup.msi (Windows only) * checks installed and only reinstall missing components * does not uninstall or delete any component Challenges: * Whonix <code>.ova</code> is bigger than 2 GB. * Windows <code>.cab</code> files have a hardcoded 2 GB maximum file size. Requirements: * cross compile on Debian (source) for Windows (target) * building does not require Windows Build limitations: * needs Debian bookworm or above because of minimal wixl and lazarus version = flow chart = (1) Whonix-Starter: * <code>lazbuild</code> → <code>WhonixStarter.lpr</code> → <code>WhonixStarter.exe</code> * <code>wixl</code> → <code>WhonixStarterSetup.wxs</code> → <code>WhonixStarter.exe</code>, <code>WhonixStarterSetup.wxs</code> → <code>WhonixStarterSetup.msi</code> (2) Whonix-Installer: * <code>lazbuild</code> → <code>WhonixSetup.lpr</code> → <code>WhonixSetup.exe</code> * <code>WhonixSetup.exe</code> + append + <code>Whonix.ova</code> → <code>WhonixSetup-Xfce.exe</code> = misc = * [https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1054343 add support for "apt install fp-units-win-rtl" instead of "apt install fp-units-win-rtl-3.2.2"] = Notes = == UseVersionInfo WhonixSetup.lpi == [[File:WhonixSetupVersionInfo.png|thumb]] Can the following variables be removed if not essential? <pre> OriginalFilename="WhonixInstaller-XYZ-1.2.3.4.exe" </pre> <pre> <UseVersionInfo Value="True"/> <MajorVersionNr Value="1"/> </pre> <p> The variables aren't essential for functionality. </p> <p> For reasons of end user confidence it's recommended to keep the version and file information (<UseVersionInfo Value="True"/>). </p> <p> "OriginalFilename" could just be "WhonixInstaller.exe". ( but I like to set the same as the final filename displayed in file browser ) </p> <p> "MajorVersionNr", "MinorVersionNr", "RevisionNr", "BuildNr" is summarized as "FileVersion" by Lazarus. If we delete these values the file version will be 0.0.0.0 </p> <p> I'm not sure in this case if the version refers to the installer or the software being installed. </p> = CI = Whonix-Starter: * https://github.com/einsiedler90/Whonix-Starter/actions * https://github.com/Whonix/Whonix-Starter/actions Whonix-Installer: * https://github.com/einsiedler90/Whonix-Installer/actions * https://github.com/Whonix/Whonix-Installer/actions = code signing = == TODO == * yubikey 5 fips? == Introduction == EV (extended validation) certificate required to avoid Microsoft SmartScreen Filter warning message. * https://learn.microsoft.com/en-us/windows/win32/seccrypto/using-signtool-to-sign-a-file * https://stackoverflow.com/questions/18287960/signing-windows-application-on-linux-based-distros * https://packages.debian.org/bullseye/osslsigncode * https://issuetracker.google.com/issues/130343741 * https://www.ssl.com/guide/supported-cloud-hsms-document-signing-ev-code-signing/ * https://github.com/mtrojnar/osslsigncode/issues/34 == requirements == * EV code signing for Windows {{kicksecure_wiki |wikipage=authenticode |text=authenticode }} to avoid Microsoft SmartScreen Filter warning message. * cross signing * build scripts running on Debian Linux * build result (program) running on Windows 64 bit * avoid running proprietary closed source software on local build machine * can be fully automated using build scripts * <s>avoid hardware token (compatibility, hassle)</s> * avoid proprietary closed source device drivers * ideally avoid non-mainline Linux kernel drivers * supports signing big files == providers == thalesgroup: * asked. does not have Linux tools. Certum: * https://shop.certum.eu/open-source-code-signing.html Certum Open Source developer certificate - EV extended validation? * https://www.certum.ng/product/ev-code-signing-in-the-cloud/ * https://shop.certum.eu/ev-code-signing-in-the-cloud.html * SimplySign cloud-based solution eliminates the need for a physical card and a reader * https://www.files.certum.eu/software/SimplySignDesktop/Linux-Ubuntu/2.9.8-9.1.6.0/SimplySignDesktop-2.9.8-9.1.6.0-x86_64-prod-ubuntu.bin * €379.00 sectigo: * https://sectigostore.com/code-signing/sectigo-ev-code-signing-certificate * cloud hsm supported? * $410 certerassl: * https://certerassl.com/certera-ev-code-signing-certificate * use existing token * no cloud hsm * $309 ssl.com: * https://www.ssl.com/ev/ * $239 * A) optional proprietary eSigner CodeSignTool ** $20.00 / month (= $240 / year) or $180.00 / year ** eSigner uses ssl.com's own Cloud HSM ** actual file needs to be present to be signed ** https://www.ssl.com/guide/esigner-pricing-for-code-signing/ ** When using for example Google Cloud HSM then eSigner is optional. ** minimum price for eSigner: ** bug reports: *** [https://github.com/SSLcom/esigner-codesign/issues/4 eSigner demo missing CREDENTIAL_ID] *** [https://github.com/SSLcom/esigner-codesign/issues/7 java.io.IOException: DOS header signature not found] *** [https://github.com/SSLcom/esigner-codesign/issues/8 provide demo certificate authority file (CAfile)] * B) optional Google Cloud HSM compatibility ** https://www.ssl.com/guide/supported-cloud-hsms-document-signing-ev-code-signing/ ** <blockquote>SSL.com’s fee for Google Cloud HSM attestation is $500.00 USD.</blockquote> Google Cloud HSM; * https://github.com/GoogleCloudPlatform/kms-integrations/blob/master/kmsp11/docs/user_guide.md * https://github.com/GoogleCloudPlatform/kms-integrations * https://cloud.google.com/kms/docs/reference/pkcs11-tool * ( https://cloud.google.com/kms/docs/reference/pkcs11-nginx ) * [https://github.com/GoogleCloudPlatform/kms-integrations/blob/master/kmsp11/docs/user_guide.md <code>libkmsp11.so</code>] == Verification of Code Signing Process == === Verification of VirtualBox === VirtualBox for Windows is signed using Microsoft {{kicksecure_wiki |wikipage=authenticode |text=Authenticode }} signatures ("<code>signtool</code>"). VirtualBox's digital signature can be verified on the Linux platform using <code>osslsigncode</code>. Example: {{CodeSelect|code= osslsigncode verify -in VirtualBox-*.exe }} A script [https://gitlab.com/kicksecure/virtualbox-windows-installer-binary/-/blob/master/verify <code>verify</code>] has been added to the <code>virtualbox-windows-installer-binary</code> repository as a reminder and example how to verify the digital software signatures on the Linux platform. === Signing Whonix Windows Installer === This document is based on a case where an executable (<code>hello.exe</code>) is signed using GitHub Actions (CI) and CodeSigner. For more details on the test, please refer to this GitHub repository: https://github.com/adrelanos/codesigner-test When a file (<code>hello.exe</code>) is signed, creating <code>hello_signed.exe</code>, the goal is to ensure that no additional modifications, beyond the signing process, have occurred. These could potentially include the insertion of malicious code. Overview: * Original file: <code>hello.exe</code> * Signed file: <code>hello_signed.exe</code> * Extracted signature file: <code>hello_signature.pem</code> * File with reattached signature: <code>hello_with_signature.exe</code> * File with reattached signature and reset PE header: <code>hello_with_signature_reset_PE.exe</code> * File with removed signature: <code>hello_without_signature.exe</code> * File with removed signature and reset PE header: <code>hello_without_signature_reset_PE.exe</code> * [https://github.com/Kicksecure/developer-meta-files/blob/master/usr/bin/pe-header-to-zero <code>pe-header-to-zero</code>] To achieve this, the original file is compared with the signed file in various stages and through different methods. The key stages are as follows: 1. Extract the signature from the signed file using <code>osslsigncode</code>: {{CodeSelect|code= osslsigncode extract-signature -in hello_signed.exe -out hello_signature.pem }} 2. The original file (<code>hello.exe</code>) is then re-signed using this extracted signature to create a new file (<code>hello_with_signature.exe</code>): {{CodeSelect|code= osslsigncode attach-signature -sigin hello_signature.pem -in hello.exe -out hello_with_signature.exe }} At this point, one would expect <code>hello_signed.exe</code> to be identical to <code>hello_with_signature.exe</code>. However, it was discovered that the signing process (<code>osslsigncode attach-signature</code>) modified the PE header of the file by adding a PE checksum, thus resulting in a difference between these two files. To analyze and understand these differences, a set of tools were used, including <code>diff</code>, <code>vbindiff</code>, <code>diffoscope</code>, and <code>readpe</code>. These comparisons brought to light the change in the PE checksum. 3. In order to make a direct comparison, the PE checksum in <code>hello_with_signature.exe</code> was reset to <code>0</code>, mirroring its original state in <code>hello.exe</code> and <code>hello_signed.exe</code>. This was achieved using a Python script named <code>pe-header-to-zero</code>: {{CodeSelect|code= pe-header-to-zero hello_with_signature.exe hello_with_signature_reset_PE.exe }} After running this script, the newly created file <code>hello_with_signature_reset_PE.exe</code> was found to be an exact match to <code>hello_signed.exe</code>. 4. The script <code>pe-header-to-zero</code> was also used on <code>hello_without_signature.exe</code> to create <code>hello_without_signature_reset_PE.exe</code>: {{CodeSelect|code= pe-header-to-zero hello_without_signature.exe hello_without_signature_reset_PE.exe }} It was found that <code>hello_without_signature_reset_PE.exe</code> was an exact match to the original <code>hello.exe</code>, further validating the process. Following this thorough examination, it can be reasonably stated that the signing process did not introduce any unwanted or malicious modifications to the original executable file. All operations were performed using the <code>osslsigncode</code> tool. To install and examine PE headers, the <code>pev</code> tool was used: {{CodeSelect|code= sudo apt install pev }} To view the PE checksum, the <code>readpe</code> utility was used: {{CodeSelect|code= readpe hello_signed.exe }} {{CodeSelect|code= readpe hello_with_signature_reset_PE.exe }} {{CodeSelect|code= readpe hello_without_signature_reset_PE.exe }} = Archived Tasks = == WhonixStarter.msi execution == Happening on Windows 10. <pre> Step 9 / 9 : Installing Whonix-Starter... Execute: msiexec /i "C:\Users\user\AppData\Local\Whonix-Xfce-17.2.0.1\WhonixStarter.msi" >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Error : Whonix-Starter could not be installed. </pre> -> fixed: see https://github.com/einsiedler90/Whonix-Installer/commit/5e52d6fc436001345db896ffee2f89c8b20c0ab1 '''Debugging Attempt 1: Double Clicking WhonixStarter.msi''' While this happened, user kept the Whonix-Installer open and then attempted to manually run <code>C:\Users\user\AppData\Local\Whonix-Xfce-17.2.0.1\WhonixStarter.msi</code> for debugging reasons. Result: <pre> WhonixStarter Another installation in progress. You must complete that installation before continuing this one. Retry | Cancel </pre> What can we conclude from this? Maybe while Whonix installer is running, it cannot execute <code>msiexec /i "C:\Users\user\AppData\Local\Whonix-Xfce-17.2.0.1\WhonixStarter.msi"</code> because it is blocking itself? -> perhaps obsolete due to previous fix? Strange: execution of "msiexec" is finnished when "Whonix-Starter could not be installed." appears. ''' Debugging Attempt 2: Starting WhonixStarter.msi from Terminal ''' Starting <code>msiexec /i "C:\Users\user\AppData\Local\Whonix-Xfce-17.2.0.1\WhonixStarter.msi"</code> from terminal does not show any additional output. = TODO = == merge == Reminder: Always please merge first before developing further. == update this wiki page == Please add comments to this wiki page once any things have been changed. == document debug mode == [[File:Bildschirmfoto vom 2024-10-13 17-42-16.png|startup in debug mode]] to use the debug mode just type in "--debug" behind the executable when startup with console. == false-positive installation failure error == See screenshot provided. == tell user there is a debug mode in the show installation details box == done: https://github.com/einsiedler90/Whonix-Installer/commit/175a005ad08088039e81346ee34db191529606ec == tell user where to find the log file in the show installation details box == obsolete, as a separate log file is no longer needed at the moment. == Microsoft Visual C++ 2019 Redistributable Package Error == [[File:VirtualBox_Microsoft_Visual_C_2019_Redistributable_Package.png|Microsoft Visual C++ 2019 Redistributable Package Error]] * Integrate vc_redist.x64.exe into the installer. * Installer can assume vc_redist.x64.exe is already on the hard drive. (No automated download from the internet.) * Please check if installed.¹ * If not installed, install.¹ https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170 https://aka.ms/vs/17/release/vc_redist.x64.exe done. see: https://github.com/einsiedler90/Whonix-Installer/commit/df9ad3e91f48958fc48f30a8323e547bb4c87bd4 ¹vc_redist.x64.exe checks itself so no separate check is needed. == rename setup to installer - update #3 == file: Whonix-Installer build-dummy.sh <pre> export FILE_INSTALLER_BINARY_FINAL=~/windows-installer-dummy-temp-delete-me/WhonixSetup-$VERSION_FULL.exe </pre> Please don't name "setup" because not using that word anywhere else. fixed: see https://github.com/einsiedler90/Whonix-Installer/commit/4fea32191c48e7df75e70fda00e5d3947c8ee105 == do not delete WhonixStarter.msi after installation == A user reported that WhonixStarter.msi gets deleted once Whonix installer gets closed. If possible, please do not delete WhonixStarter.msi after installation. Why? To make this process easier to debug. --> added "--debug" command line option to solve the problem. see: https://github.com/einsiedler90/Whonix-Installer/commit/9a27e7f7194afa82da12cd4597e87144594e843e == Instructions for AI based Code Review == If the AI is talking trash, just delete it from the wiki without comment. No need to comment on AI generated text which is nonsense. Please delete this wiki chapter now. == Claude AI based Code Review of whonixinstaller_main.pas == 1) Resource management: While the code does free some resources, it's not consistent. For instance, in the FormCreate method, ResourceStream is created and freed, but in some other places like InstallationBuildIn, resources aren't always explicitly freed. 2) Potential infinite loop: In FormCreate, there's a while loop checking for disk space. If the user keeps selecting invalid directories, this could potentially become an infinite loop. 3) Unused variables: There are some unused variables in the code, like <code>filename</code> in the commented-out <code>EnsureValidExePath</code> procedure. 4) Inconsistent use of string types: The code mixes string and AnsiString types, which could lead to encoding issues. 5) Lack of input validation: When executing external commands, there's little to no validation of input parameters, which could potentially be a security risk. 6) UI responsiveness: The code uses Sleep in the SetNextStatus method, which could make the UI less responsive. Consider using a timer or async operations instead. 7) Incomplete implementation: Some methods like LabelCompleteDescClick are empty, suggesting incomplete functionality. == ChatGPT AI based Code Review of whonixinstaller_main.pas == === Thread Blocking Due to <code>Sleep</code> and <code>Application.ProcessMessages</code> === In <code>WhonixUtils.pas</code>, <code>Execute</code> uses <code>Sleep</code> and <code>Application.ProcessMessages</code> in a loop, which can lead to a blocking UI: <pre lang="pascal"> repeat Sleep(100); Application.ProcessMessages; ... until (BytesRead = 0) and not Running; </pre> '''Solution:''' Consider using a separate thread for executing processes to avoid blocking the main UI thread. '''Answer from Developer:''' Any longer loop without "Application.ProcessMessages;" lead to a blocking UI. That's what the function is there for, to keep the UI responsive if the program is only single threaded. A separate thread is an alternative solution but it takes a few hours for some restructuring. This would also allow the installer logic to be separated more cleanly from the installer GUI. Please add a TODO if you want me to implement this. === Potential Memory Leaks === There are several places where dynamically allocated resources may not be freed properly in case of an exception, especially in <code>FormCreate</code> and <code>InstallationBuildIn</code>. '''Solution:''' Use try-finally blocks to ensure that resources are properly freed: <pre lang="pascal"> ResourceStream := TResourceStream.Create(HInstance, 'LICENSE', RT_RCDATA); try MemoLicense.Lines.LoadFromStream(ResourceStream); finally ResourceStream.Free; end; </pre> '''Answer from Developer:''' In most cases with dynamic data this is correct, but this code only loads static content from the program resources (license text) which is always present (except by any errors while compile time), so I have omitted the “try finally†for shorter code. === Deprecation and Error Handling === Deprecated code comments indicate potential areas that might be out of date: <pre lang="pascal"> // deprecated??? ----------------------> if not InstallerForm.Showing then begin InstallerForm.Show; end; // ------------------------------------< </pre> '''Solution:''' Review and update the deprecated code. done. https://github.com/einsiedler90/Whonix-Installer/commit/8ec3962f94a6610436219a2666ffb4eecc62cd20 == More ChatGPT AI based Review == https://chatgpt.com/ 1) Please register a free account. 2) Write "any bugs?" followed by a copy/paste of 1 source code file. 3) Ignore wrong/useless/overboard comments and address any useful comments. == More Claude AI based Review == https://claude.ai Similar to above. == Windows_User_Interface wiki page == TODO: update/rewrite [[Dev/Windows_Starter]] = See Also = * [[Dev/Windows Installer/OLD|previous, deprecated Whonix Windows Installer]] * [[Dev/Windows_Starter]] (TODO: update) * [[Verify_the_images_using_Windows|Verify the {{project_name_short}} Windows Installer]] {{Footer}}