-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented more guardrails for signed scenarios (#492)
The app no longer allows the wrong certificate or common name to be used during signed policy deployment, re-deployment or removal. Such possible user accidents are caught very early on and communicated to the user with proper and clear messages so user can fix the mistake quickly. The goal is to never let AppControl Manager to be used even intentionally to cause boot failure when dealing with signed policies. Deployment of signed policies is very much recommended over unsigned ones, check this article to see why: https://github.com/HotCakeX/Harden-Windows-Security/wiki/The-Strength-of-Signed-App-Control-Policies AppControl Manager is the only app that's currently available that makes it the safest way to interact with signed policies and it keeps getting better quickly. The content dialogs that ask for user input for signing scenarios have better visuals now, and the focus is by default on the Verify button, which makes it easier and clearer what needs to be done. It also means you can press the enter key on the keyboard quickly to confirm the actions without using mouse. Improved DataGrid experience when removing items in MDE Advanced Hunting and Event Logs pages. Bumped version from 1.8.0.0 to 1.8.1.0
- Loading branch information
Showing
13 changed files
with
282 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
AppControl Manager/Logic/IntelGathering/InferCertificatePresence.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.Cryptography.X509Certificates; | ||
using AppControlManager.Logging; | ||
using AppControlManager.SiPolicy; | ||
|
||
namespace AppControlManager.Logic.IntelGathering; | ||
|
||
internal static class CertificatePresence | ||
{ | ||
|
||
/// <summary> | ||
/// Takes in a policy object and certificate .cer file path and ensures the certificate's details is added to the policy as UpdatePolicySigner | ||
/// It also checks to see whether user selected certificate matches the user selected certificate common name. | ||
/// The reason we don't need to check signature of the deployed signed cip files in the EFI partition is because | ||
/// The user-selected XML policy's ID is already checked against the deployed signed policies and that provides the necessary signing details in the XML. | ||
/// </summary> | ||
/// <param name="policyObject"></param> | ||
/// <param name="certificatePath"></param> | ||
/// <param name="certCN"></param> | ||
/// <returns></returns> | ||
internal static bool InferCertificatePresence(SiPolicy.SiPolicy policyObject, string certificatePath, string certCN) | ||
{ | ||
|
||
// Create a certificate object from the .cer file | ||
X509Certificate2 CertObject = X509CertificateLoader.LoadCertificateFromFile(certificatePath); | ||
|
||
// Get the TBS of the certificate | ||
string CertTBS = CertificateHelper.GetTBSCertificate(CertObject); | ||
|
||
// Get the Common Name of the certificate | ||
string CertCommonName = CryptoAPI.GetNameString(CertObject.Handle, CryptoAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE, null, false); | ||
|
||
|
||
// Make sure the certificate that user selected matches the user-selected certificate Common Name | ||
if (!string.Equals(certCN, CertCommonName, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
Logger.Write($"The selected common name is {certCN} but the common name of the certificate you selected is {CertCommonName} which doesn't match it."); | ||
return false; | ||
} | ||
|
||
// Get the ID of all of the UpdatePolicySigners elements | ||
IEnumerable<string> updatePolicySignerIDs = policyObject.UpdatePolicySigners.Select(x => x.SignerId); | ||
|
||
// Get all of the <Signer> elements from the policy | ||
Dictionary<string, Signer> signerDictionary = []; | ||
foreach (Signer signer in policyObject.Signers) | ||
{ | ||
_ = signerDictionary.TryAdd(signer.ID, signer); | ||
} | ||
|
||
|
||
// Loop over each updatePolicySignerID in the policy | ||
foreach (string updatePolicySigner in updatePolicySignerIDs) | ||
{ | ||
// Try to find a signer that is for UpdatePolicySigners | ||
if (signerDictionary.TryGetValue(updatePolicySigner, out Signer? signerForUpdateSigner)) | ||
{ | ||
// If signer is TBS Signer | ||
if (signerForUpdateSigner.CertRoot.Type is CertEnumType.TBS) | ||
{ | ||
// Get the string value of the CertRoot which is the TBS Hash | ||
string certRootTBS = Convert.ToHexString(signerForUpdateSigner.CertRoot.Value); | ||
|
||
// Compare the selected certificate's TBS hash with the TBS hash of the signer which is the cert Root value | ||
// Also compare the Signer's name with the selected certificate's Common Name | ||
if (string.Equals(CertTBS, certRootTBS, StringComparison.OrdinalIgnoreCase) && string.Equals(CertCommonName, signerForUpdateSigner.Name, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
|
||
Logger.Write("No UpdatePolicySigner found with the same TBS hash and Common Name as the selected certificate in the policy XML file you selected."); | ||
|
||
return false; | ||
} | ||
|
||
|
||
|
||
/// <summary> | ||
/// Gets the path to a .cer certificate file and a certificate common name | ||
/// Makes sure the common name belongs to the certificate file | ||
/// </summary> | ||
/// <param name="certificatePath"></param> | ||
/// <param name="certCN"></param> | ||
/// <returns></returns> | ||
internal static bool VerifyCertAndCNMatch(string certificatePath, string certCN) | ||
{ | ||
// Create a certificate object from the .cer file | ||
X509Certificate2 CertObject = X509CertificateLoader.LoadCertificateFromFile(certificatePath); | ||
|
||
// Get the Common Name of the certificate | ||
string CertCommonName = CryptoAPI.GetNameString(CertObject.Handle, CryptoAPI.CERT_NAME_SIMPLE_DISPLAY_TYPE, null, false); | ||
|
||
// Make sure the certificate that user selected matches the user-selected certificate Common Name | ||
if (!string.Equals(certCN, CertCommonName, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
Logger.Write($"The selected common name is {certCN} but the common name of the certificate you selected is {CertCommonName} which doesn't match it."); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
} | ||
|
Oops, something went wrong.