Skip to content

Commit

Permalink
Another protection when removing signed policies
Browse files Browse the repository at this point in the history
This new protection mechanism ensures the safe removal of signed policies. To complete the process securely, a system reboot is required after the first stage. The newly implemented protection verifies that the reboot has been performed before allowing the process to proceed to the final stage.

If the user forgets to reboot or is unsure whether it’s necessary, a prompt will appear to guide them through the process. This safeguard prevents accidental errors that could lead to boot failures, making the AppControl Manager even safer and more reliable when managing Signed App Control policies.
  • Loading branch information
HotCakeX committed Jan 12, 2025
1 parent 55bb95a commit 607a156
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 58 deletions.
117 changes: 113 additions & 4 deletions AppControl Manager/Logic/Main/UserConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using AppControlManager.Logging;
Expand Down Expand Up @@ -33,7 +34,8 @@ public sealed partial class UserConfiguration(
Guid? strictKernelNoFlightRootsPolicyGUID,
DateTime? lastUpdateCheck,
DateTime? strictKernelModePolicyTimeOfDeployment,
bool? autoUpdateCheck
bool? autoUpdateCheck,
Dictionary<string, DateTime>? signedPolicyStage1RemovalTimes = null
)
{
[JsonPropertyOrder(1)]
Expand Down Expand Up @@ -66,6 +68,9 @@ public sealed partial class UserConfiguration(
[JsonPropertyOrder(10)]
public bool? AutoUpdateCheck { get; set; } = autoUpdateCheck;

[JsonPropertyOrder(11)]
public Dictionary<string, DateTime>? SignedPolicyStage1RemovalTimes { get; set; } = signedPolicyStage1RemovalTimes;



/// <summary>
Expand All @@ -82,6 +87,7 @@ public sealed partial class UserConfiguration(
/// <param name="LastUpdateCheck"></param>
/// <param name="StrictKernelModePolicyTimeOfDeployment"></param>
/// <param name="AutoUpdateCheck"></param>
/// <param name="SignedPolicyStage1RemovalTimes"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
internal static UserConfiguration Set(
Expand All @@ -94,7 +100,8 @@ internal static UserConfiguration Set(
Guid? StrictKernelNoFlightRootsPolicyGUID = null,
DateTime? LastUpdateCheck = null,
DateTime? StrictKernelModePolicyTimeOfDeployment = null,
bool? AutoUpdateCheck = null
bool? AutoUpdateCheck = null,
Dictionary<string, DateTime>? SignedPolicyStage1RemovalTimes = null
)
{
// Validate certificateCommonName
Expand Down Expand Up @@ -154,6 +161,11 @@ internal static UserConfiguration Set(
if (StrictKernelModePolicyTimeOfDeployment.HasValue) UserConfiguration.StrictKernelModePolicyTimeOfDeployment = StrictKernelModePolicyTimeOfDeployment;
if (AutoUpdateCheck.HasValue) UserConfiguration.AutoUpdateCheck = AutoUpdateCheck;

if (SignedPolicyStage1RemovalTimes is not null)
{
UserConfiguration.SignedPolicyStage1RemovalTimes = SignedPolicyStage1RemovalTimes;
}

// Write the updated properties back to the JSON file
WriteUserConfiguration(UserConfiguration);

Expand Down Expand Up @@ -186,6 +198,7 @@ internal static UserConfiguration Get()
/// <param name="LastUpdateCheck"></param>
/// <param name="StrictKernelModePolicyTimeOfDeployment"></param>
/// <param name="AutoUpdateCheck"></param>
/// <param name="SignedPolicyStage1RemovalTimes"></param>
internal static void Remove(
bool SignedPolicyPath = false,
bool UnsignedPolicyPath = false,
Expand All @@ -196,7 +209,8 @@ internal static void Remove(
bool StrictKernelNoFlightRootsPolicyGUID = false,
bool LastUpdateCheck = false,
bool StrictKernelModePolicyTimeOfDeployment = false,
bool AutoUpdateCheck = false
bool AutoUpdateCheck = false,
bool SignedPolicyStage1RemovalTimes = false
)
{
// Read the current configuration
Expand All @@ -213,13 +227,15 @@ internal static void Remove(
if (LastUpdateCheck) currentConfig.LastUpdateCheck = null;
if (StrictKernelModePolicyTimeOfDeployment) currentConfig.StrictKernelModePolicyTimeOfDeployment = null;
if (AutoUpdateCheck) currentConfig.AutoUpdateCheck = null;
if (SignedPolicyStage1RemovalTimes) currentConfig.SignedPolicyStage1RemovalTimes = null;

// Write the updated configuration back to the JSON file
WriteUserConfiguration(currentConfig);

Logger.Write("The specified properties have been removed and set to null in the UserConfigurations.json file.");
}


private static UserConfiguration ReadUserConfiguration()
{
try
Expand Down Expand Up @@ -276,7 +292,8 @@ private static UserConfiguration ParseJson(string json)
TryGetGuidProperty(root, nameof(StrictKernelNoFlightRootsPolicyGUID)),
TryGetDateTimeProperty(root, nameof(LastUpdateCheck)),
TryGetDateTimeProperty(root, nameof(StrictKernelModePolicyTimeOfDeployment)),
TryGetBoolProperty(root, nameof(AutoUpdateCheck))
TryGetBoolProperty(root, nameof(AutoUpdateCheck)),
TryGetKeyValuePairsProperty(root, nameof(SignedPolicyStage1RemovalTimes))
);

static string? TryGetStringProperty(JsonElement root, string propertyName)
Expand Down Expand Up @@ -326,6 +343,21 @@ private static UserConfiguration ParseJson(string json)
return null;
}
}

static Dictionary<string, DateTime>? TryGetKeyValuePairsProperty(JsonElement root, string propertyName)
{
try
{
return root.TryGetProperty(propertyName, out var propertyValue) && propertyValue.ValueKind == JsonValueKind.Object
? propertyValue.EnumerateObject().ToDictionary(e => e.Name, e => e.Value.GetDateTime().ToUniversalTime())
: null;
}
catch
{
return null;
}
}

}


Expand All @@ -341,4 +373,81 @@ private static void WriteUserConfiguration(UserConfiguration userConfiguration)
File.WriteAllText(GlobalVars.UserConfigJson, jsonString);
Logger.Write("The UserConfigurations.json file has been updated successfully.");
}




/// <summary>
/// Adds a new key-value pair to the SignedPolicyStage1RemovalTimes dictionary.
/// </summary>
/// <param name="key">The key to add.</param>
/// <param name="value">The value to associate with the key.</param>
internal static void Add(string key, DateTime value)
{
// Get the current user configuration
UserConfiguration currentConfig = ReadUserConfiguration();

// Initialize the dictionary if it doesn't exist
currentConfig.SignedPolicyStage1RemovalTimes ??= [];

// Add the key-value pair to the dictionary
currentConfig.SignedPolicyStage1RemovalTimes[key] = value; // This will add or update the value for the key

// Write the updated configuration back to the JSON file
WriteUserConfiguration(currentConfig);

Logger.Write($"Key-value pair added to the SignedPolicyStage1RemovalTimes: {key} = {value}");
}



/// <summary>
/// Queries the SignedPolicyStage1RemovalTimes dictionary by key and returns the corresponding value.
/// </summary>
/// <param name="key">The key to query.</param>
/// <returns>The value associated with the key, or null if the key does not exist.</returns>
internal static DateTime? Query(string key)
{
// Get the current user configuration
UserConfiguration currentConfig = ReadUserConfiguration();

// Return the value if the key exists, otherwise return null
if (currentConfig.SignedPolicyStage1RemovalTimes is not null && currentConfig.SignedPolicyStage1RemovalTimes.TryGetValue(key, out DateTime value))
{
return value;
}

// Return null if the key doesn't exist
return null;
}



/// <summary>
/// Removes a key-value pair from the SignedPolicyStage1RemovalTimes dictionary by key.
/// </summary>
/// <param name="key">The key to remove.</param>
/// <returns>True if the key was successfully removed; false if the key was not found.</returns>
internal static void RemoveKey(string key)
{
// Get the current user configuration
UserConfiguration currentConfig = ReadUserConfiguration();

// Check if the dictionary exists and contains the key
if (currentConfig.SignedPolicyStage1RemovalTimes is not null && currentConfig.SignedPolicyStage1RemovalTimes.ContainsKey(key))
{
// Remove the key-value pair
_ = currentConfig.SignedPolicyStage1RemovalTimes.Remove(key);

// Write the updated configuration back to the JSON file
WriteUserConfiguration(currentConfig);

Logger.Write($"Key '{key}' removed from the SignedPolicyStage1RemovalTimes dictionary.");
}
else
{
Logger.Write($"Key '{key}' not found in the SignedPolicyStage1RemovalTimes dictionary.");
}
}

}
Loading

0 comments on commit 607a156

Please sign in to comment.