From 4c2c5828ae46c36d50b6e20722b41619760725ae Mon Sep 17 00:00:00 2001 From: Rans4ckeR Date: Fri, 29 Dec 2023 20:46:12 +0100 Subject: [PATCH] UI: Edit CipherSuite configuration --- .../CipherPunk.CipherSuiteInfoApi.csproj | 1 + CipherPunk.UI/CipherPunk.UI.csproj | 1 + CipherPunk.UI/Properties/GlobalUsings.cs | 1 - CipherPunk.UI/Services/UacIconService.cs | 9 +- .../BaseCipherSuitesSettingsViewModel.cs | 240 ++++++++++++++++++ .../CipherSuitesGroupPolicySettingsView.xaml | 62 +++-- ...ipherSuitesGroupPolicySettingsViewModel.cs | 130 +++------- .../CipherSuitesOsSettingsView.xaml | 60 +++-- .../CipherSuitesOsSettingsViewModel.cs | 109 +------- .../CipherSuites/CipherSuitesView.xaml | 2 +- .../EllipticCurvesOsSettingsView.xaml | 2 +- .../EllipticCurvesOsSettingsViewModel.cs | 4 +- .../EllipticCurves/EllipticCurvesView.xaml | 2 +- .../UserControls/Overview/OverviewView.xaml | 4 +- CipherPunk/CipherPunk.csproj | 1 + .../HandshakeExtensions/HandshakeExtension.cs | 6 +- .../Tls/Records/ClientHelloTlsRecord.cs | 2 +- CipherPunk/Entities/Tls/Records/TlsRecord.cs | 4 +- CipherPunk/NativeMethods.txt | 67 ++--- CipherPunk/Services/CipherSuiteService.cs | 210 +++++++-------- CipherPunk/Services/EllipticCurveService.cs | 53 ++-- CipherPunk/Services/GroupPolicyService.cs | 9 +- CipherPunk/Services/SchannelLogService.cs | 2 +- CipherPunk/Services/TlsService.cs | 11 +- 24 files changed, 569 insertions(+), 423 deletions(-) create mode 100644 CipherPunk.UI/UserControls/CipherSuites/BaseCipherSuitesSettingsViewModel.cs diff --git a/CipherPunk.CipherSuiteInfoApi/CipherPunk.CipherSuiteInfoApi.csproj b/CipherPunk.CipherSuiteInfoApi/CipherPunk.CipherSuiteInfoApi.csproj index 7810a75..c1c3d5b 100644 --- a/CipherPunk.CipherSuiteInfoApi/CipherPunk.CipherSuiteInfoApi.csproj +++ b/CipherPunk.CipherSuiteInfoApi/CipherPunk.CipherSuiteInfoApi.csproj @@ -23,6 +23,7 @@ 0.0.0.1 0.0.0.1 AnyCPU + true diff --git a/CipherPunk.UI/CipherPunk.UI.csproj b/CipherPunk.UI/CipherPunk.UI.csproj index 30adf2a..92bcb2c 100644 --- a/CipherPunk.UI/CipherPunk.UI.csproj +++ b/CipherPunk.UI/CipherPunk.UI.csproj @@ -27,6 +27,7 @@ win-x86;win-x64;win-arm64 x86;x64;ARM64 app.manifest + true diff --git a/CipherPunk.UI/Properties/GlobalUsings.cs b/CipherPunk.UI/Properties/GlobalUsings.cs index 1237bba..f50c20a 100644 --- a/CipherPunk.UI/Properties/GlobalUsings.cs +++ b/CipherPunk.UI/Properties/GlobalUsings.cs @@ -1,6 +1,5 @@ #pragma warning disable IDE0065 // Misplaced using directive #pragma warning disable SA1200 // Using directives should be placed correctly -global using CipherPunk; global using Microsoft.Extensions.Logging; #pragma warning restore SA1200 // Using directives should be placed correctly #pragma warning restore IDE0065 // Misplaced using directive \ No newline at end of file diff --git a/CipherPunk.UI/Services/UacIconService.cs b/CipherPunk.UI/Services/UacIconService.cs index 298e8df..1f9c8ea 100644 --- a/CipherPunk.UI/Services/UacIconService.cs +++ b/CipherPunk.UI/Services/UacIconService.cs @@ -24,8 +24,8 @@ public BitmapSource GetUacShieldIcon() { HRESULT shGetStockIconInfoResult = PInvoke.SHGetStockIconInfo(SHSTOCKICONID.SIID_SHIELD, SHGSI_FLAGS.SHGSI_ICON | SHGSI_FLAGS.SHGSI_SMALLICON, ref psii); - if (!shGetStockIconInfoResult.Succeeded) - throw Marshal.GetExceptionForHR(shGetStockIconInfoResult)!; + if (shGetStockIconInfoResult.Failed) + throw new Win32Exception(shGetStockIconInfoResult); bitmapSource = Imaging.CreateBitmapSourceFromHIcon(psii.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } @@ -35,9 +35,6 @@ public BitmapSource GetUacShieldIcon() destroyIconResult = PInvoke.DestroyIcon(psii.hIcon); } - if (destroyIconResult.Value is 0) - throw new Win32Exception(Marshal.GetLastWin32Error()); - - return bitmapSource; + return destroyIconResult.Value is 0 ? throw new Win32Exception(Marshal.GetLastWin32Error()) : bitmapSource; } } \ No newline at end of file diff --git a/CipherPunk.UI/UserControls/CipherSuites/BaseCipherSuitesSettingsViewModel.cs b/CipherPunk.UI/UserControls/CipherSuites/BaseCipherSuitesSettingsViewModel.cs new file mode 100644 index 0000000..a55ea33 --- /dev/null +++ b/CipherPunk.UI/UserControls/CipherSuites/BaseCipherSuitesSettingsViewModel.cs @@ -0,0 +1,240 @@ +namespace CipherPunk.UI; + +using System.Collections.ObjectModel; +using System.Windows.Media.Imaging; +using CipherPunk.CipherSuiteInfoApi; +using CommunityToolkit.Mvvm.Input; +using Windows.Win32; + +internal abstract class BaseCipherSuitesSettingsViewModel : BaseViewModel +{ + private readonly IUacIconService uacIconService; + private readonly ICipherSuiteInfoApiService cipherSuiteInfoApiService; + private readonly List onlineCipherSuiteInfos = []; + private ObservableCollection? activeCipherSuiteConfigurations; + private ObservableCollection? modifiedCipherSuiteConfigurations; + private ObservableCollection? defaultCipherSuiteConfigurations; + private BitmapSource? uacIcon; + private bool fetchOnlineInfo = true; + + protected BaseCipherSuitesSettingsViewModel( + ILogger logger, ICipherSuiteService cipherSuiteService, IUacIconService uacIconService, ICipherSuiteInfoApiService cipherSuiteInfoApiService) + : base(logger) + { + MoveCipherSuiteUpCommand = new RelayCommand(ExecuteMoveCipherSuiteUpCommand, CanExecuteMoveCipherSuiteUpCommand); + MoveCipherSuiteDownCommand = new RelayCommand(ExecuteMoveCipherSuiteDownCommand, CanExecuteMoveCipherSuiteDownCommand); + DeleteCipherSuiteCommand = new RelayCommand(ExecuteDeleteCipherSuiteCommand, CanExecuteDeleteCipherSuiteCommand); + AddCipherSuiteCommand = new RelayCommand(ExecuteAddCipherSuiteCommand, CanExecuteAddCipherSuiteCommand); + SaveCipherSuitesCommand = new AsyncRelayCommand(ExecuteSaveCipherSuitesCommandAsync, CanExecuteSaveCipherSuitesCommand); + CancelCipherSuitesCommand = new RelayCommand(ExecuteCancelCipherSuitesCommand, CanExecuteCancelCipherSuitesCommand); + ResetCipherSuitesCommand = new AsyncRelayCommand(ExecuteResetCipherSuitesCommandAsync, CanExecuteResetCipherSuitesCommand); + CipherSuiteService = cipherSuiteService; + this.uacIconService = uacIconService; + this.cipherSuiteInfoApiService = cipherSuiteInfoApiService; + + UpdateCanExecuteDefaultCommand(); + } + + public IRelayCommand MoveCipherSuiteUpCommand { get; } + + public IRelayCommand MoveCipherSuiteDownCommand { get; } + + public IRelayCommand DeleteCipherSuiteCommand { get; } + + public IRelayCommand AddCipherSuiteCommand { get; } + + public IAsyncRelayCommand SaveCipherSuitesCommand { get; } + + public IRelayCommand CancelCipherSuitesCommand { get; } + + public IAsyncRelayCommand ResetCipherSuitesCommand { get; } + + public BitmapSource UacIcon => uacIcon ??= uacIconService.GetUacShieldIcon(); + + public bool FetchOnlineInfo + { + get => fetchOnlineInfo; + set => _ = SetProperty(ref fetchOnlineInfo, value); + } + + protected ICipherSuiteService CipherSuiteService { get; } + + public ObservableCollection? ModifiedCipherSuiteConfigurations + { + get => modifiedCipherSuiteConfigurations; + private set => _ = SetProperty(ref modifiedCipherSuiteConfigurations, value); + } + + public ObservableCollection? DefaultCipherSuiteConfigurations + { + get => defaultCipherSuiteConfigurations; + private set => _ = SetProperty(ref defaultCipherSuiteConfigurations, value); + } + + protected override async Task DoExecuteDefaultCommandAsync(CancellationToken cancellationToken) + { + IList windowsDocumentationCipherSuiteConfigurations = CipherSuiteService.GetOperatingSystemDocumentationDefaultCipherSuiteList(); + IEnumerable windowsApiActiveCipherSuiteConfigurations = GetActiveCipherSuiteConfiguration(); + + if (FetchOnlineInfo) + await FetchOnlineCipherSuiteInfoAsync(windowsDocumentationCipherSuiteConfigurations, cancellationToken); + + ushort priority = ushort.MinValue; + var uiWindowsApiCipherSuiteConfigurations = windowsApiActiveCipherSuiteConfigurations.Select(q => new UiWindowsApiCipherSuiteConfiguration( + ++priority, + q.CipherSuite, + q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), + q.KeyType, + q.Certificate, + q.MaximumExchangeLength, + q.MinimumExchangeLength, + q.Exchange, + q.HashLength, + q.Hash, + q.CipherBlockLength, + q.CipherLength, + q.Cipher, + onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); + + priority = ushort.MinValue; + + var defaultUiWindowsDocumentationCipherSuiteConfigurations = windowsDocumentationCipherSuiteConfigurations.Select(q => new UiWindowsDocumentationCipherSuiteConfiguration( + ++priority, + q.CipherSuite, + q.AllowedByUseStrongCryptographyFlag, + q.EnabledByDefault, + q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), + q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), + q.ExplicitApplicationRequestOnly, + q.PreWindows10EllipticCurve, + onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); + + DefaultCipherSuiteConfigurations = new(defaultUiWindowsDocumentationCipherSuiteConfigurations); + activeCipherSuiteConfigurations = new(uiWindowsApiCipherSuiteConfigurations); + ModifiedCipherSuiteConfigurations = new(activeCipherSuiteConfigurations); + } + + protected abstract IEnumerable GetActiveCipherSuiteConfiguration(); + + protected abstract void DoExecuteSaveCipherSuitesCommand(); + + protected abstract void DoExecuteResetCipherSuitesCommand(); + + protected virtual bool CanExecuteMoveCipherSuiteUpCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => uiWindowsApiCipherSuiteConfiguration is not null && ModifiedCipherSuiteConfigurations!.IndexOf(uiWindowsApiCipherSuiteConfiguration.Value) > 0; + + protected virtual bool CanExecuteMoveCipherSuiteDownCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => uiWindowsApiCipherSuiteConfiguration is not null && ModifiedCipherSuiteConfigurations!.IndexOf(uiWindowsApiCipherSuiteConfiguration.Value) < ModifiedCipherSuiteConfigurations.Count - 1; + + protected virtual bool CanExecuteDeleteCipherSuiteCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => uiWindowsApiCipherSuiteConfiguration is not null; + + protected virtual bool CanExecuteSaveCipherSuitesCommand() + => !(activeCipherSuiteConfigurations?.SequenceEqual(ModifiedCipherSuiteConfigurations ?? []) ?? false); + + protected virtual bool CanExecuteCancelCipherSuitesCommand() + => !(activeCipherSuiteConfigurations?.SequenceEqual(ModifiedCipherSuiteConfigurations ?? []) ?? false); + + protected virtual bool CanExecuteAddCipherSuiteCommand(UiWindowsDocumentationCipherSuiteConfiguration? uiWindowsDocumentationCipherSuiteConfiguration) + => uiWindowsDocumentationCipherSuiteConfiguration is not null && ModifiedCipherSuiteConfigurations!.All(q => q.Id != uiWindowsDocumentationCipherSuiteConfiguration.Value.CipherSuite); + + protected virtual bool CanExecuteResetCipherSuitesCommand() + => true; + + private async Task FetchOnlineCipherSuiteInfoAsync(IEnumerable windowsDocumentationCipherSuiteConfigurations, CancellationToken cancellationToken) + { + CipherSuite?[] cipherSuites = await Task.WhenAll(windowsDocumentationCipherSuiteConfigurations.Select(q => cipherSuiteInfoApiService.GetCipherSuiteAsync(q.CipherSuite.ToString(), cancellationToken).AsTask())); + + onlineCipherSuiteInfos.Clear(); + onlineCipherSuiteInfos.AddRange(cipherSuites.Where(q => q is not null)); + } + + private void ExecuteMoveCipherSuiteUpCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + { + int index = ModifiedCipherSuiteConfigurations!.IndexOf(uiWindowsApiCipherSuiteConfiguration!.Value); + + ModifiedCipherSuiteConfigurations.Move(index, --index); + NotifyCanExecuteChanged(); + } + + private void ExecuteMoveCipherSuiteDownCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + { + int index = ModifiedCipherSuiteConfigurations!.IndexOf(uiWindowsApiCipherSuiteConfiguration!.Value); + + ModifiedCipherSuiteConfigurations.Move(index, ++index); + NotifyCanExecuteChanged(); + } + + private void ExecuteDeleteCipherSuiteCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + { + _ = ModifiedCipherSuiteConfigurations!.Remove(uiWindowsApiCipherSuiteConfiguration!.Value); + NotifyCanExecuteChanged(); + } + + private void ExecuteAddCipherSuiteCommand(UiWindowsDocumentationCipherSuiteConfiguration? uiWindowsDocumentationCipherSuiteConfiguration) + { + WindowsApiCipherSuiteConfiguration windowsApiCipherSuiteConfiguration = CipherSuiteService.GetOperatingSystemDefaultCipherSuiteList().Single(q => q.CipherSuite == uiWindowsDocumentationCipherSuiteConfiguration!.Value.CipherSuite); + + ModifiedCipherSuiteConfigurations!.Add(new( + (ushort)(ModifiedCipherSuiteConfigurations.Count + 1), + windowsApiCipherSuiteConfiguration.CipherSuite, + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), + windowsApiCipherSuiteConfiguration.KeyType, + windowsApiCipherSuiteConfiguration.Certificate, + windowsApiCipherSuiteConfiguration.MaximumExchangeLength, + windowsApiCipherSuiteConfiguration.MinimumExchangeLength, + windowsApiCipherSuiteConfiguration.Exchange, + windowsApiCipherSuiteConfiguration.HashLength, + windowsApiCipherSuiteConfiguration.Hash, + windowsApiCipherSuiteConfiguration.CipherBlockLength, + windowsApiCipherSuiteConfiguration.CipherLength, + windowsApiCipherSuiteConfiguration.Cipher, + onlineCipherSuiteInfos.SingleOrDefault(r => windowsApiCipherSuiteConfiguration.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)); + NotifyCanExecuteChanged(); + } + + private async Task ExecuteSaveCipherSuitesCommandAsync() + { + DoExecuteSaveCipherSuitesCommand(); + await DoExecuteDefaultCommandAsync(CancellationToken.None); + NotifyCanExecuteChanged(); + } + + private void ExecuteCancelCipherSuitesCommand() + { + ModifiedCipherSuiteConfigurations = new(activeCipherSuiteConfigurations!); + + NotifyCanExecuteChanged(); + } + + private async Task ExecuteResetCipherSuitesCommandAsync() + { + DoExecuteResetCipherSuitesCommand(); + await DoExecuteDefaultCommandAsync(CancellationToken.None); + NotifyCanExecuteChanged(); + } + + private void NotifyCanExecuteChanged() + { + MoveCipherSuiteUpCommand.NotifyCanExecuteChanged(); + MoveCipherSuiteDownCommand.NotifyCanExecuteChanged(); + SaveCipherSuitesCommand.NotifyCanExecuteChanged(); + CancelCipherSuitesCommand.NotifyCanExecuteChanged(); + AddCipherSuiteCommand.NotifyCanExecuteChanged(); + ResetCipherSuitesCommand.NotifyCanExecuteChanged(); + } +} \ No newline at end of file diff --git a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsView.xaml b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsView.xaml index 800cb3b..5af3d6d 100644 --- a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsView.xaml +++ b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsView.xaml @@ -12,13 +12,12 @@ - - + @@ -27,32 +26,63 @@ - - + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - + diff --git a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsViewModel.cs b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsViewModel.cs index 1a57a5b..2b669b6 100644 --- a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsViewModel.cs +++ b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesGroupPolicySettingsViewModel.cs @@ -1,64 +1,25 @@ namespace CipherPunk.UI; -using System.Collections.ObjectModel; -using System.Windows.Media.Imaging; using CipherPunk.CipherSuiteInfoApi; -using Windows.Win32; -internal sealed class CipherSuitesGroupPolicySettingsViewModel : BaseViewModel +internal sealed class CipherSuitesGroupPolicySettingsViewModel( + ILogger logger, + ICipherSuiteService cipherSuiteService, + IUacIconService uacIconService, + ICipherSuiteInfoApiService cipherSuiteInfoApiService, + IGroupPolicyService groupPolicyService) + : BaseCipherSuitesSettingsViewModel(logger, cipherSuiteService, uacIconService, cipherSuiteInfoApiService) { - private readonly ICipherSuiteService cipherSuiteService; - private readonly IUacIconService uacIconService; - private readonly ICipherSuiteInfoApiService cipherSuiteInfoApiService; - private readonly IGroupPolicyService groupPolicyService; - private readonly List onlineCipherSuiteInfos = []; - private ObservableCollection? activeGroupPolicyCipherSuiteConfigurations; - private ObservableCollection? defaultGroupPolicyCipherSuiteConfigurations; - private BitmapSource? uacIcon; - private bool fetchOnlineInfo = true; private string? adminMessage; - public CipherSuitesGroupPolicySettingsViewModel( - ILogger logger, ICipherSuiteService cipherSuiteService, IUacIconService uacIconService, ICipherSuiteInfoApiService cipherSuiteInfoApiService, IGroupPolicyService groupPolicyService) - : base(logger) - { - this.cipherSuiteService = cipherSuiteService; - this.uacIconService = uacIconService; - this.cipherSuiteInfoApiService = cipherSuiteInfoApiService; - this.groupPolicyService = groupPolicyService; - - UpdateCanExecuteDefaultCommand(); - } - public string? AdminMessage { get => adminMessage; private set => _ = SetProperty(ref adminMessage, value); } - public BitmapSource UacIcon => uacIcon ??= uacIconService.GetUacShieldIcon(); - - public bool FetchOnlineInfo - { - get => fetchOnlineInfo; - set => _ = SetProperty(ref fetchOnlineInfo, value); - } - - public ObservableCollection? ActiveGroupPolicyCipherSuiteConfigurations - { - get => activeGroupPolicyCipherSuiteConfigurations; - private set => _ = SetProperty(ref activeGroupPolicyCipherSuiteConfigurations, value); - } - - public ObservableCollection? DefaultGroupPolicyCipherSuiteConfigurations + protected override IEnumerable GetActiveCipherSuiteConfiguration() { - get => defaultGroupPolicyCipherSuiteConfigurations; - private set => _ = SetProperty(ref defaultGroupPolicyCipherSuiteConfigurations, value); - } - - protected override async Task DoExecuteDefaultCommandAsync(CancellationToken cancellationToken) - { - string[] windowsDefaultGroupPolicyCipherSuiteConfigurationsStrings = await groupPolicyService.GetSslCipherSuiteOrderPolicyWindowsDefaultsAsync(cancellationToken); string[] windowsActiveGroupPolicyCipherSuiteConfigurationsStrings = []; AdminMessage = null; @@ -69,59 +30,34 @@ protected override async Task DoExecuteDefaultCommandAsync(CancellationToken can } catch (UnauthorizedAccessException) { - AdminMessage = "Run as Administrator to see the Group Policy settings."; + AdminMessage = "Run as Administrator to view and modify the Group Policy settings."; } - List windowsDocumentationCipherSuiteConfigurations = cipherSuiteService.GetOperatingSystemDocumentationDefaultCipherSuiteList(); - - if (FetchOnlineInfo) - await FetchOnlineCipherSuiteInfoAsync(windowsDocumentationCipherSuiteConfigurations, cancellationToken); - - IEnumerable windowsDefaultGroupPolicyCipherSuiteConfigurations = windowsDocumentationCipherSuiteConfigurations.Where(q => windowsDefaultGroupPolicyCipherSuiteConfigurationsStrings.Contains(q.CipherSuite.ToString())); - IEnumerable windowsActiveGroupPolicyCipherSuiteConfigurations = windowsDocumentationCipherSuiteConfigurations.Where(q => windowsActiveGroupPolicyCipherSuiteConfigurationsStrings.Contains(q.CipherSuite.ToString())); - - ushort priority = 0; - var uiWindowsActiveGroupPolicyCipherSuiteConfigurations = windowsActiveGroupPolicyCipherSuiteConfigurations.Select(q => new UiWindowsDocumentationCipherSuiteConfiguration( - ++priority, - q.CipherSuite, - q.AllowedByUseStrongCryptographyFlag, - q.EnabledByDefault, - q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), - q.ExplicitApplicationRequestOnly, - q.PreWindows10EllipticCurve, - onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); - - priority = 0; - - var uiWindowsDefaultGroupPolicyCipherSuiteConfigurations = windowsDefaultGroupPolicyCipherSuiteConfigurations.Select(q => new UiWindowsDocumentationCipherSuiteConfiguration( - ++priority, - q.CipherSuite, - q.AllowedByUseStrongCryptographyFlag, - q.EnabledByDefault, - q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), - q.ExplicitApplicationRequestOnly, - q.PreWindows10EllipticCurve, - onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); - - ActiveGroupPolicyCipherSuiteConfigurations = new(uiWindowsActiveGroupPolicyCipherSuiteConfigurations); - DefaultGroupPolicyCipherSuiteConfigurations = new(uiWindowsDefaultGroupPolicyCipherSuiteConfigurations); + return CipherSuiteService.GetOperatingSystemActiveCipherSuiteList().Where(q => windowsActiveGroupPolicyCipherSuiteConfigurationsStrings.Contains(q.CipherSuite.ToString(), StringComparer.OrdinalIgnoreCase)); } - private async Task FetchOnlineCipherSuiteInfoAsync(IEnumerable windowsDocumentationCipherSuiteConfigurations, CancellationToken cancellationToken) - { - CipherSuite?[] cipherSuites = await Task.WhenAll(windowsDocumentationCipherSuiteConfigurations.Select(q => cipherSuiteInfoApiService.GetCipherSuiteAsync(q.CipherSuite.ToString(), cancellationToken).AsTask())); + protected override void DoExecuteSaveCipherSuitesCommand() => groupPolicyService.UpdateSslCipherSuiteOrderPolicy(ModifiedCipherSuiteConfigurations!.Select(q => q.Id.ToString()).ToArray()); - onlineCipherSuiteInfos.Clear(); - onlineCipherSuiteInfos.AddRange(cipherSuites.Where(q => q is not null)); - } + protected override void DoExecuteResetCipherSuitesCommand() => groupPolicyService.UpdateSslCipherSuiteOrderPolicy([]); + + protected override bool CanExecuteAddCipherSuiteCommand(UiWindowsDocumentationCipherSuiteConfiguration? uiWindowsDocumentationCipherSuiteConfiguration) + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteAddCipherSuiteCommand(uiWindowsDocumentationCipherSuiteConfiguration); + + protected override bool CanExecuteCancelCipherSuitesCommand() + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteCancelCipherSuitesCommand(); + + protected override bool CanExecuteDeleteCipherSuiteCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteDeleteCipherSuiteCommand(uiWindowsApiCipherSuiteConfiguration); + + protected override bool CanExecuteMoveCipherSuiteUpCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteMoveCipherSuiteUpCommand(uiWindowsApiCipherSuiteConfiguration); + + protected override bool CanExecuteMoveCipherSuiteDownCommand(UiWindowsApiCipherSuiteConfiguration? uiWindowsApiCipherSuiteConfiguration) + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteMoveCipherSuiteDownCommand(uiWindowsApiCipherSuiteConfiguration); + + protected override bool CanExecuteResetCipherSuitesCommand() + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteResetCipherSuitesCommand(); + + protected override bool CanExecuteSaveCipherSuitesCommand() + => string.IsNullOrWhiteSpace(AdminMessage) && base.CanExecuteSaveCipherSuitesCommand(); } \ No newline at end of file diff --git a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsView.xaml b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsView.xaml index 76bed5b..0422131 100644 --- a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsView.xaml +++ b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsView.xaml @@ -12,13 +12,12 @@ - - + @@ -26,31 +25,62 @@ - + + + + + + + + + + + + + + + + + + + - + + - - - - - - - + diff --git a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsViewModel.cs b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsViewModel.cs index 3154872..b815705 100644 --- a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsViewModel.cs +++ b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesOsSettingsViewModel.cs @@ -1,107 +1,18 @@ namespace CipherPunk.UI; -using System.Collections.ObjectModel; -using System.Windows.Media.Imaging; using CipherPunk.CipherSuiteInfoApi; -using Windows.Win32; -internal sealed class CipherSuitesOsSettingsViewModel : BaseViewModel +internal sealed class CipherSuitesOsSettingsViewModel( + ILogger logger, + ICipherSuiteService cipherSuiteService, + IUacIconService uacIconService, + ICipherSuiteInfoApiService cipherSuiteInfoApiService) + : BaseCipherSuitesSettingsViewModel(logger, cipherSuiteService, uacIconService, cipherSuiteInfoApiService) { - private readonly ICipherSuiteService cipherSuiteService; - private readonly IUacIconService uacIconService; - private readonly ICipherSuiteInfoApiService cipherSuiteInfoApiService; - private readonly List onlineCipherSuiteInfos = []; - private ObservableCollection? activeCipherSuiteConfigurations; - private ObservableCollection? osDefaultCipherSuiteConfigurations; - private BitmapSource? uacIcon; - private bool fetchOnlineInfo = true; + protected override IEnumerable GetActiveCipherSuiteConfiguration() + => CipherSuiteService.GetOperatingSystemActiveCipherSuiteList(); - public CipherSuitesOsSettingsViewModel(ILogger logger, ICipherSuiteService cipherSuiteService, IUacIconService uacIconService, ICipherSuiteInfoApiService cipherSuiteInfoApiService) - : base(logger) - { - this.cipherSuiteService = cipherSuiteService; - this.uacIconService = uacIconService; - this.cipherSuiteInfoApiService = cipherSuiteInfoApiService; + protected override void DoExecuteSaveCipherSuitesCommand() => CipherSuiteService.UpdateCipherSuiteOrder(ModifiedCipherSuiteConfigurations!.Select(q => q.Id).ToArray()); - UpdateCanExecuteDefaultCommand(); - } - - public BitmapSource UacIcon => uacIcon ??= uacIconService.GetUacShieldIcon(); - - public bool FetchOnlineInfo - { - get => fetchOnlineInfo; - set => _ = SetProperty(ref fetchOnlineInfo, value); - } - - public ObservableCollection? ActiveCipherSuiteConfigurations - { - get => activeCipherSuiteConfigurations; - private set => _ = SetProperty(ref activeCipherSuiteConfigurations, value); - } - - public ObservableCollection? OsDefaultCipherSuiteConfigurations - { - get => osDefaultCipherSuiteConfigurations; - private set => _ = SetProperty(ref osDefaultCipherSuiteConfigurations, value); - } - - protected override async Task DoExecuteDefaultCommandAsync(CancellationToken cancellationToken) - { - List windowsDocumentationCipherSuiteConfigurations = cipherSuiteService.GetOperatingSystemDocumentationDefaultCipherSuiteList(); - List windowsApiActiveCipherSuiteConfigurations = cipherSuiteService.GetOperatingSystemActiveCipherSuiteList(); - - if (FetchOnlineInfo) - await FetchOnlineCipherSuiteInfoAsync(windowsDocumentationCipherSuiteConfigurations, cancellationToken); - - ushort priority = 0; - var uiWindowsApiCipherSuiteConfigurations = windowsApiActiveCipherSuiteConfigurations.Select(q => new UiWindowsApiCipherSuiteConfiguration( - ++priority, - q.CipherSuite, - q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), - q.KeyType, - q.Certificate, - q.MaximumExchangeLength, - q.MinimumExchangeLength, - q.Exchange, - q.HashLength, - q.Hash, - q.CipherBlockLength, - q.CipherLength, - q.Cipher, - onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); - - priority = 0; - - var uiWindowsDocumentationCipherSuiteConfigurations = windowsDocumentationCipherSuiteConfigurations.Select(q => new UiWindowsDocumentationCipherSuiteConfiguration( - ++priority, - q.CipherSuite, - q.AllowedByUseStrongCryptographyFlag, - q.EnabledByDefault, - q.Protocols.Contains(SslProviderProtocolId.SSL2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.SSL3_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_0_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_1_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_2_PROTOCOL_VERSION), - q.Protocols.Contains(SslProviderProtocolId.TLS1_3_PROTOCOL_VERSION), - q.ExplicitApplicationRequestOnly, - q.PreWindows10EllipticCurve, - onlineCipherSuiteInfos.SingleOrDefault(r => q.CipherSuite.ToString().Equals(r!.Value.IanaName, StringComparison.OrdinalIgnoreCase), null)?.Security)).ToList(); - - ActiveCipherSuiteConfigurations = new(uiWindowsApiCipherSuiteConfigurations); - OsDefaultCipherSuiteConfigurations = new(uiWindowsDocumentationCipherSuiteConfigurations); - } - - private async Task FetchOnlineCipherSuiteInfoAsync(IEnumerable windowsDocumentationCipherSuiteConfigurations, CancellationToken cancellationToken) - { - CipherSuite?[] cipherSuites = await Task.WhenAll(windowsDocumentationCipherSuiteConfigurations.Select(q => cipherSuiteInfoApiService.GetCipherSuiteAsync(q.CipherSuite.ToString(), cancellationToken).AsTask())); - - onlineCipherSuiteInfos.Clear(); - onlineCipherSuiteInfos.AddRange(cipherSuites.Where(q => q is not null)); - } + protected override void DoExecuteResetCipherSuitesCommand() => CipherSuiteService.ResetCipherSuiteListToOperatingSystemDefault(); } \ No newline at end of file diff --git a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesView.xaml b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesView.xaml index 533fb2f..56bcded 100644 --- a/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesView.xaml +++ b/CipherPunk.UI/UserControls/CipherSuites/CipherSuitesView.xaml @@ -16,7 +16,7 @@ - + diff --git a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsView.xaml b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsView.xaml index df0437c..ffc14e7 100644 --- a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsView.xaml +++ b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsView.xaml @@ -19,7 +19,7 @@ - + diff --git a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsViewModel.cs b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsViewModel.cs index dcc7ec9..e1e07e0 100644 --- a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsViewModel.cs +++ b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesOsSettingsViewModel.cs @@ -49,7 +49,7 @@ protected override async Task DoExecuteDefaultCommandAsync(CancellationToken can List windowsApiAvailableEllipticCurveConfigurations = ellipticCurveService.GetOperatingSystemAvailableEllipticCurveList(); List windowsDocumentationEllipticCurveConfiguration = ellipticCurveService.GetOperatingSystemDefaultEllipticCurveList(); - ushort priority = 0; + ushort priority = ushort.MinValue; var uiWindowsApiEllipticCurveConfigurations = windowsApiActiveEllipticCurveConfigurations.Select(q => new UiWindowsApiEllipticCurveConfiguration( ++priority, q.pszOid, @@ -64,7 +64,7 @@ protected override async Task DoExecuteDefaultCommandAsync(CancellationToken can q.dwBitLength, string.Join(",", q.CngAlgorithms))).ToList(); - priority = 0; + priority = ushort.MinValue; var uiWindowsDocumentationEllipticCurveConfiguration = windowsDocumentationEllipticCurveConfiguration.Select(q => new UiWindowsDocumentationEllipticCurveConfiguration( ++priority, diff --git a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesView.xaml b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesView.xaml index 6536bc8..e6ab403 100644 --- a/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesView.xaml +++ b/CipherPunk.UI/UserControls/EllipticCurves/EllipticCurvesView.xaml @@ -16,7 +16,7 @@ - + diff --git a/CipherPunk.UI/UserControls/Overview/OverviewView.xaml b/CipherPunk.UI/UserControls/Overview/OverviewView.xaml index 9419c55..6ba9f29 100644 --- a/CipherPunk.UI/UserControls/Overview/OverviewView.xaml +++ b/CipherPunk.UI/UserControls/Overview/OverviewView.xaml @@ -44,7 +44,7 @@ - + @@ -59,7 +59,7 @@ - + diff --git a/CipherPunk/CipherPunk.csproj b/CipherPunk/CipherPunk.csproj index c0510f2..8b11c68 100644 --- a/CipherPunk/CipherPunk.csproj +++ b/CipherPunk/CipherPunk.csproj @@ -34,6 +34,7 @@ README.md true AnyCPU + true diff --git a/CipherPunk/Entities/Tls/HandshakeExtensions/HandshakeExtension.cs b/CipherPunk/Entities/Tls/HandshakeExtensions/HandshakeExtension.cs index 4ee7aef..e60a29d 100644 --- a/CipherPunk/Entities/Tls/HandshakeExtensions/HandshakeExtension.cs +++ b/CipherPunk/Entities/Tls/HandshakeExtensions/HandshakeExtension.cs @@ -14,7 +14,7 @@ public static List GetExtensions(ReadOnlySpan data) { var handshakeExtensions = new List(); int index = 0; - //ushort handshakeExtensionsLength = BinaryPrimitives.ReverseEndianness(BitConverter.ToUInt16(data.TakeBytes(ref index, 2))); + ////ushort handshakeExtensionsLength = BinaryPrimitives.ReverseEndianness(BitConverter.ToUInt16(data.TakeBytes(ref index, 2))); while (index < data.Length) { @@ -37,7 +37,7 @@ public static List GetExtensions(ReadOnlySpan data) keyShares.Add(new(tlsSupportedGroup, publicKey)); } - handshakeExtensions.Add(new KeyShareExtension(keyShares.ToArray())); + handshakeExtensions.Add(new KeyShareExtension([.. keyShares])); break; case TlsExtensionType.supported_versions: extensionEndIndex = index + tlsExtensionLength; @@ -50,7 +50,7 @@ public static List GetExtensions(ReadOnlySpan data) tlsVersions.Add(tlsVersion); } - handshakeExtensions.Add(new SupportedVersionsExtension(tlsVersions.ToArray())); + handshakeExtensions.Add(new SupportedVersionsExtension([.. tlsVersions])); break; default: index += tlsExtensionLength; diff --git a/CipherPunk/Entities/Tls/Records/ClientHelloTlsRecord.cs b/CipherPunk/Entities/Tls/Records/ClientHelloTlsRecord.cs index 53d8451..0e0d4b8 100644 --- a/CipherPunk/Entities/Tls/Records/ClientHelloTlsRecord.cs +++ b/CipherPunk/Entities/Tls/Records/ClientHelloTlsRecord.cs @@ -73,7 +73,7 @@ public ClientHelloTlsRecord( if (tlsCertificateCompressionAlgorithms?.Length > 0) HandshakeExtensions.Add(new CompressCertificateHandshakeExtension(tlsCertificateCompressionAlgorithms)); - // "psk_key_exchange_modes" is REQUIRED for PSK key agreement. + //// "psk_key_exchange_modes" is REQUIRED for PSK key agreement. var padding = new PaddingHandshakeExtension(512 - (1 + HandshakeMessageLength.Length + HandshakeMessageNumberOfBytes)); // + 1 for size of TlsHandshakeHeaderMessageType diff --git a/CipherPunk/Entities/Tls/Records/TlsRecord.cs b/CipherPunk/Entities/Tls/Records/TlsRecord.cs index 3806743..bd543ef 100644 --- a/CipherPunk/Entities/Tls/Records/TlsRecord.cs +++ b/CipherPunk/Entities/Tls/Records/TlsRecord.cs @@ -75,8 +75,6 @@ protected TlsRecord(TlsVersion tlsVersion, TlsContentType tlsContentType, TlsHan public List HandshakeExtensions { get; protected set; } - protected abstract byte[] GetRecordTypeBytes(); - public static TlsRecord Parse(ReadOnlySpan data) { var tlsRecordHeader = new TlsRecordHeader(data); @@ -144,4 +142,6 @@ public byte[] GetMessageBytes() return [.. result]; } + + protected abstract byte[] GetRecordTypeBytes(); } \ No newline at end of file diff --git a/CipherPunk/NativeMethods.txt b/CipherPunk/NativeMethods.txt index c508456..fc802cc 100644 --- a/CipherPunk/NativeMethods.txt +++ b/CipherPunk/NativeMethods.txt @@ -1,45 +1,46 @@ -BCryptAddContextFunction +ALG_CLASS_* +ALG_SID_* +ALG_TYPE_* +BCRYPT_* +BCRYPT_ECC_CURVE_NAMES +BCRYPT_ECCKEY_BLOB +BCryptAddContextFunction +BCryptCloseAlgorithmProvider +BCryptDestroyKey BCryptEnumContextFunctions BCryptEnumContexts BCryptFreeBuffer +BCryptGenerateKeyPair +BCryptGetProperty +BCryptOpenAlgorithmProvider BCryptRemoveContextFunction BCryptResolveProviders -NCryptOpenStorageProvider -NCryptEnumAlgorithms -NCRYPT_KEY_HANDLE -IGroupPolicyObject -CoInitializeEx +BCryptSetProperty +CALG_* +CLSID_GroupPolicyObject CoCreateInstance +CoInitializeEx CoUninitialize -RegCreateKeyEx -RegOpenKeyEx -RegDeleteValue -RegSetKeyValue -RegGetValue -CryptEnumOIDInfo -BCRYPT_ECCKEY_BLOB +CRYPT_* CRYPT_INTEGER_BLOB -NTE_NO_MORE_ITEMS -szOID_ECC_CURVE_* -CLSID_GroupPolicyObject -NCryptProviderName -BCryptGetProperty -BCryptOpenAlgorithmProvider -BCryptCloseAlgorithmProvider -BCRYPT_ECC_CURVE_NAMES +CryptEnumOIDInfo CryptFindOIDInfo -BCryptGenerateKeyPair -BCryptSetProperty -BCryptDestroyKey -ECC_CURVE_TYPE_ENUM ECC_CURVE_ALG_ID_ENUM -ALG_CLASS_* -ALG_TYPE_* -ALG_SID_* -CALG_* -CRYPT_* -BCRYPT_* -NCRYPT_* +ECC_CURVE_TYPE_ENUM HKEY_* +IGroupPolicyObject +NCRYPT_* +NCRYPT_KEY_HANDLE +NCryptEnumAlgorithms +NCryptOpenStorageProvider +NCryptProviderName +NTE_NO_MORE_ITEMS +RegCreateKeyEx +RegDeleteValue +RegGetValue REGISTRY_EXTENSION_GUID -WER_REPORT_INFORMATION \ No newline at end of file +RegOpenKeyEx +RegSetKeyValue +STATUS_ACCESS_DENIED +szOID_ECC_CURVE_* +WER_REPORT_INFORMATION diff --git a/CipherPunk/Services/CipherSuiteService.cs b/CipherPunk/Services/CipherSuiteService.cs index 076a59e..785f78b 100644 --- a/CipherPunk/Services/CipherSuiteService.cs +++ b/CipherPunk/Services/CipherSuiteService.cs @@ -44,8 +44,7 @@ public string[] GetLocalCngConfigurationContextIdentifiers() } finally { - if (ppBuffer is not null) - PInvoke.BCryptFreeBuffer(ppBuffer); + PInvoke.BCryptFreeBuffer(ppBuffer); } } @@ -87,16 +86,12 @@ public List GetOperatingSystemActiveCipherSu for (uint i = uint.MinValue; i < cryptContextFunctions.cFunctions; i++) { string? function = cryptContextFunctions.rgpszFunctions[i].ToString(); - WindowsApiCipherSuiteConfiguration? cipherSuite = defaultCipherSuiteConfigurations.SingleOrDefault(q => function.Equals(q.CipherSuiteName, StringComparison.OrdinalIgnoreCase)); + WindowsApiCipherSuiteConfiguration cipherSuite = defaultCipherSuiteConfigurations.SingleOrDefault(q => function.Equals(q.CipherSuiteName, StringComparison.OrdinalIgnoreCase)); - if (cipherSuite is null) - { - // todo - } + if (cipherSuite == default) + throw new(function); else - { - cipherSuiteConfigurations.Add(cipherSuite.Value); - } + cipherSuiteConfigurations.Add(cipherSuite); } return cipherSuiteConfigurations; @@ -119,6 +114,7 @@ public List GetOperatingSystemDefaultCipherS NCRYPT_SSL_CIPHER_SUITE* ppCipherSuite = null; void* ppEnumState = null; CRYPT_PROVIDER_REFS* ppBuffer = null; + NCryptFreeObjectSafeHandle? phSslProvider = null; try { @@ -146,116 +142,112 @@ public List GetOperatingSystemDefaultCipherS ppBuffer = null; - HRESULT sslOpenProviderResult = PInvoke.SslOpenProvider(out NCryptFreeObjectSafeHandle phSslProvider, pszProvider!); + HRESULT sslOpenProviderResult = PInvoke.SslOpenProvider(out phSslProvider, pszProvider!); + + if (sslOpenProviderResult.Failed) + throw new Win32Exception(sslOpenProviderResult); + + HRESULT? sslEnumCipherSuitesResult = null; - if (sslOpenProviderResult.Succeeded) + while (sslEnumCipherSuitesResult?.Value != HRESULT.NTE_NO_MORE_ITEMS) { - HRESULT? sslEnumCipherSuitesResult = null; + sslEnumCipherSuitesResult = PInvoke.SslEnumCipherSuites(phSslProvider, null, out ppCipherSuite, ref ppEnumState); - while (sslEnumCipherSuitesResult?.Value != HRESULT.NTE_NO_MORE_ITEMS) + if (sslEnumCipherSuitesResult.Value.Succeeded) { - sslEnumCipherSuitesResult = PInvoke.SslEnumCipherSuites(phSslProvider, null, out ppCipherSuite, ref ppEnumState); + NCRYPT_SSL_CIPHER_SUITE ncryptSslCipherSuite = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(ppCipherSuite), 1)[0]; + SslProviderCipherSuiteId dwCipherSuite = ncryptSslCipherSuite.dwCipherSuite; + SslProviderProtocolId dwProtocol = ncryptSslCipherSuite.dwProtocol; + WindowsApiCipherSuiteConfiguration? windowsApiCipherSuiteConfiguration = cipherSuiteConfigurations.SingleOrDefault(q => q!.Value.CipherSuite == dwCipherSuite, null); - if (sslEnumCipherSuitesResult.Value.Succeeded) + if (windowsApiCipherSuiteConfiguration.HasValue) { - NCRYPT_SSL_CIPHER_SUITE ncryptSslCipherSuite = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(ppCipherSuite), 1)[0]; - SslProviderCipherSuiteId dwCipherSuite = ncryptSslCipherSuite.dwCipherSuite; - SslProviderProtocolId dwProtocol = ncryptSslCipherSuite.dwProtocol; - WindowsApiCipherSuiteConfiguration? windowsApiCipherSuiteConfiguration = cipherSuiteConfigurations.SingleOrDefault(q => q!.Value.CipherSuite == dwCipherSuite, null); - - if (windowsApiCipherSuiteConfiguration.HasValue) - { - windowsApiCipherSuiteConfiguration.Value.Protocols.Add(dwProtocol); - - continue; - } - - var providerProtocolIds = new List { ncryptSslCipherSuite.dwProtocol }; - string? keyExchangeAlgorithm = null; - uint? minimumKeyExchangeKeyLengthBits = null; - uint? maximumKeyExchangeKeyLengthBits = null; - string? hash = null; - uint? hashLengthBytes = null; - string? serverCertificateKeyType = null; - SslProviderKeyTypeId? keyType = null; - string? szExchange = ncryptSslCipherSuite.szExchange.ToString(); - - if (!string.IsNullOrWhiteSpace(szExchange)) - { - keyExchangeAlgorithm = szExchange; - minimumKeyExchangeKeyLengthBits = ncryptSslCipherSuite.dwMinExchangeLen; - maximumKeyExchangeKeyLengthBits = ncryptSslCipherSuite.dwMaxExchangeLen; - } - - string? szHash = ncryptSslCipherSuite.szHash.ToString(); - - if (!string.IsNullOrWhiteSpace(szHash)) - { - hash = szHash; - hashLengthBytes = ncryptSslCipherSuite.dwHashLen; - } - - string? szCertificate = ncryptSslCipherSuite.szCertificate.ToString(); - - if (!string.IsNullOrWhiteSpace(szCertificate)) - serverCertificateKeyType = szCertificate; - - SslProviderKeyTypeId dwKeyType = ncryptSslCipherSuite.dwKeyType; - - if (dwKeyType is not 0) - keyType = dwKeyType; - - var cipherSuiteConfiguration = new WindowsApiCipherSuiteConfiguration - { - Protocols = providerProtocolIds, - BaseCipherSuite = ncryptSslCipherSuite.dwBaseCipherSuite, - Certificate = serverCertificateKeyType, - Cipher = ncryptSslCipherSuite.szCipher.ToString(), - CipherBlockLength = ncryptSslCipherSuite.dwCipherBlockLen, - CipherLength = ncryptSslCipherSuite.dwCipherLen, - CipherSuite = dwCipherSuite, - Exchange = keyExchangeAlgorithm, - Hash = hash, - HashLength = hashLengthBytes, - Image = pszImage, - KeyType = keyType, - MaximumExchangeLength = maximumKeyExchangeKeyLengthBits, - MinimumExchangeLength = minimumKeyExchangeKeyLengthBits, - Provider = pszProvider, - CipherSuiteName = ncryptSslCipherSuite.szCipherSuite.ToString() - }; - - cipherSuiteConfigurations.Add(cipherSuiteConfiguration); - - if (ppCipherSuite is not null) - { - HRESULT sslFreeBufferResult = PInvoke.SslFreeBuffer(ppCipherSuite); - - ppCipherSuite = null; - - if (sslFreeBufferResult.Failed) - throw Marshal.GetExceptionForHR(sslFreeBufferResult)!; - } + windowsApiCipherSuiteConfiguration.Value.Protocols.Add(dwProtocol); + + continue; } - else if (sslEnumCipherSuitesResult.Value.Value != HRESULT.NTE_NO_MORE_ITEMS) + + var providerProtocolIds = new List { ncryptSslCipherSuite.dwProtocol }; + string? keyExchangeAlgorithm = null; + uint? minimumKeyExchangeKeyLengthBits = null; + uint? maximumKeyExchangeKeyLengthBits = null; + string? hash = null; + uint? hashLengthBytes = null; + string? serverCertificateKeyType = null; + SslProviderKeyTypeId? keyType = null; + string? szExchange = ncryptSslCipherSuite.szExchange.ToString(); + + if (!string.IsNullOrWhiteSpace(szExchange)) { - throw Marshal.GetExceptionForHR(sslEnumCipherSuitesResult.Value)!; + keyExchangeAlgorithm = szExchange; + minimumKeyExchangeKeyLengthBits = ncryptSslCipherSuite.dwMinExchangeLen; + maximumKeyExchangeKeyLengthBits = ncryptSslCipherSuite.dwMaxExchangeLen; } - } - if (ppEnumState is not null) - { - HRESULT sslFreeBufferResult = PInvoke.SslFreeBuffer(ppEnumState); + string? szHash = ncryptSslCipherSuite.szHash.ToString(); + + if (!string.IsNullOrWhiteSpace(szHash)) + { + hash = szHash; + hashLengthBytes = ncryptSslCipherSuite.dwHashLen; + } + + string? szCertificate = ncryptSslCipherSuite.szCertificate.ToString(); - ppEnumState = null; + if (!string.IsNullOrWhiteSpace(szCertificate)) + serverCertificateKeyType = szCertificate; - if (sslFreeBufferResult.Failed) - throw Marshal.GetExceptionForHR(sslFreeBufferResult)!; + SslProviderKeyTypeId dwKeyType = ncryptSslCipherSuite.dwKeyType; + + if (dwKeyType is not 0) + keyType = dwKeyType; + + var cipherSuiteConfiguration = new WindowsApiCipherSuiteConfiguration + { + Protocols = providerProtocolIds, + BaseCipherSuite = ncryptSslCipherSuite.dwBaseCipherSuite, + Certificate = serverCertificateKeyType, + Cipher = ncryptSslCipherSuite.szCipher.ToString(), + CipherBlockLength = ncryptSslCipherSuite.dwCipherBlockLen, + CipherLength = ncryptSslCipherSuite.dwCipherLen, + CipherSuite = dwCipherSuite, + Exchange = keyExchangeAlgorithm, + Hash = hash, + HashLength = hashLengthBytes, + Image = pszImage, + KeyType = keyType, + MaximumExchangeLength = maximumKeyExchangeKeyLengthBits, + MinimumExchangeLength = minimumKeyExchangeKeyLengthBits, + Provider = pszProvider, + CipherSuiteName = ncryptSslCipherSuite.szCipherSuite.ToString() + }; + + cipherSuiteConfigurations.Add(cipherSuiteConfiguration); + + if (ppCipherSuite is not null) + { + HRESULT sslFreeBufferResult = PInvoke.SslFreeBuffer(ppCipherSuite); + + ppCipherSuite = null; + + if (sslFreeBufferResult.Failed) + throw new Win32Exception(sslFreeBufferResult); + } + } + else if (sslEnumCipherSuitesResult != HRESULT.NTE_NO_MORE_ITEMS) + { + throw new Win32Exception(sslEnumCipherSuitesResult.Value); } } - else + + if (ppEnumState is not null) { - throw Marshal.GetExceptionForHR(sslOpenProviderResult)!; + HRESULT sslFreeBufferResult = PInvoke.SslFreeBuffer(ppEnumState); + + ppEnumState = null; + + if (sslFreeBufferResult.Failed) + throw new Win32Exception(sslFreeBufferResult); } } finally @@ -268,6 +260,8 @@ public List GetOperatingSystemDefaultCipherS if (ppEnumState is not null) _ = PInvoke.SslFreeBuffer(ppEnumState); + + phSslProvider?.Dispose(); } } @@ -298,6 +292,9 @@ public void RemoveCipherSuite(string cipherSuite) { NTSTATUS status = PInvoke.BCryptRemoveContextFunction(BCRYPT_TABLE.CRYPT_LOCAL, LocalCngSslContextName, BCRYPT_INTERFACE.NCRYPT_SCHANNEL_INTERFACE, cipherSuite); + if (status == NTSTATUS.STATUS_ACCESS_DENIED) + throw new UnauthorizedAccessException(); + if (status.SeverityCode is not NTSTATUS.Severity.Success) throw new Win32Exception(status); } @@ -311,6 +308,9 @@ public void AddCipherSuite(string cipherSuite, bool top = true) NTSTATUS status = PInvoke.BCryptAddContextFunction( BCRYPT_TABLE.CRYPT_LOCAL, LocalCngSslContextName, BCRYPT_INTERFACE.NCRYPT_SCHANNEL_INTERFACE, cipherSuite, (uint)(top ? PriorityListPosition.CRYPT_PRIORITY_TOP : PriorityListPosition.CRYPT_PRIORITY_BOTTOM)); + if (status == NTSTATUS.STATUS_ACCESS_DENIED) + throw new UnauthorizedAccessException(); + if (status.SeverityCode is not NTSTATUS.Severity.Success) throw new Win32Exception(status); } diff --git a/CipherPunk/Services/EllipticCurveService.cs b/CipherPunk/Services/EllipticCurveService.cs index d798ffb..0dbdb03 100644 --- a/CipherPunk/Services/EllipticCurveService.cs +++ b/CipherPunk/Services/EllipticCurveService.cs @@ -35,7 +35,7 @@ public List GetOperatingSystemAvailableEll HRESULT sslEnumProtocolProvidersStatus = PInvoke.SslEnumProtocolProviders(out uint pdwProviderCount, out ppProviderList); if (sslEnumProtocolProvidersStatus.Failed) - throw Marshal.GetExceptionForHR(sslEnumProtocolProvidersStatus)!; + throw new Win32Exception(sslEnumProtocolProvidersStatus); for (uint i = uint.MinValue; i < pdwProviderCount; i++) { @@ -46,8 +46,8 @@ public List GetOperatingSystemAvailableEll using (phSslProvider) { - if (!sslOpenProviderResult.Succeeded) - throw Marshal.GetExceptionForHR(sslOpenProviderResult)!; + if (sslOpenProviderResult.Failed) + throw new Win32Exception(sslOpenProviderResult); } uint pcbBuffer = 0U; @@ -196,25 +196,25 @@ public List GetOperatingSystemAvailableEll } else { - // The CRYPT_*_ALG_OID_GROUP_ID's have an Algid. The CRYPT_RDN_ATTR_OID_GROUP_ID - // has a dwLength. The CRYPT_EXT_OR_ATTR_OID_GROUP_ID, - // CRYPT_ENHKEY_USAGE_OID_GROUP_ID, CRYPT_POLICY_OID_GROUP_ID or - // CRYPT_TEMPLATE_OID_GROUP_ID don't have a dwValue. - // - // CRYPT_PUBKEY_ALG_OID_GROUP_ID has the following optional ExtraInfo: - // DWORD[0] - Flags. CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG can be set to - // inhibit the reformatting of the signature before - // CryptVerifySignature is called or after CryptSignHash - // is called. CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG can - // be set to include the public key algorithm's parameters - // in the PKCS7's digestEncryptionAlgorithm's parameters. - // CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG can be set to omit - // NULL parameters when encoding. - // - // For the ECC named curve public keys - // DWORD[1] - BCRYPT_ECCKEY_BLOB dwMagic field value - // DWORD[2] - dwBitLength. Where BCRYPT_ECCKEY_BLOB's - // cbKey = dwBitLength / 8 + ((dwBitLength % 8) ? 1 : 0) + //// The CRYPT_*_ALG_OID_GROUP_ID's have an Algid. The CRYPT_RDN_ATTR_OID_GROUP_ID + //// has a dwLength. The CRYPT_EXT_OR_ATTR_OID_GROUP_ID, + //// CRYPT_ENHKEY_USAGE_OID_GROUP_ID, CRYPT_POLICY_OID_GROUP_ID or + //// CRYPT_TEMPLATE_OID_GROUP_ID don't have a dwValue. + //// + //// CRYPT_PUBKEY_ALG_OID_GROUP_ID has the following optional ExtraInfo: + //// DWORD[0] - Flags. CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG can be set to + //// inhibit the reformatting of the signature before + //// CryptVerifySignature is called or after CryptSignHash + //// is called. CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG can + //// be set to include the public key algorithm's parameters + //// in the PKCS7's digestEncryptionAlgorithm's parameters. + //// + //// NULL parameters when encoding. + //// + //// For the ECC named curve public keys + //// DWORD[1] - BCRYPT_ECCKEY_BLOB dwMagic field value + //// DWORD[2] - dwBitLength. Where BCRYPT_ECCKEY_BLOB's + //// cbKey = dwBitLength / 8 + ((dwBitLength % 8) ? 1 : 0) CRYPT_OID_INFO cryptOidInfo = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(cryptOidInfoPointer), 1)[0]; uint cbSize = cryptOidInfo.cbSize; string? pszOid = cryptOidInfo.pszOID.ToString(); @@ -225,13 +225,13 @@ public List GetOperatingSystemAvailableEll var algId = (CALG)anonymous.Algid; // The CRYPT_*_ALG_OID_GROUP_ID's have an Algid var flags = (CRYPT_OID_FLAG)extraInfo.cbData; - // if (extraInfo.pbData is not null) - // { + //// if (extraInfo.pbData is not null) + //// { BCRYPT_ECCKEY_BLOB eccKeyStruct = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(extraInfo.pbData), 1)[0]; uint dwMagic = eccKeyStruct.dwMagic; var bcryptMagic = (BCRYPT_MAGIC)eccKeyStruct.cbKey; uint dwBitLength = (uint)Marshal.ReadInt32((nint)extraInfo.pbData, sizeof(BCRYPT_ECCKEY_BLOB)); - // } + //// } string? pwszCNGAlgid = Marshal.PtrToStringAuto(cryptOidInfo.pwszCNGAlgid); string? pwszCNGExtraAlgid = Marshal.PtrToStringAuto(cryptOidInfo.pwszCNGExtraAlgid); // CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM = "CryptOIDInfoECCParameters" @@ -256,8 +256,7 @@ public List GetOperatingSystemAvailableEll if (ppProviderList is not null) _ = PInvoke.SslFreeBuffer(ppProviderList); - if (ppBuffer is not null) - PInvoke.BCryptFreeBuffer(ppBuffer); + PInvoke.BCryptFreeBuffer(ppBuffer); } } diff --git a/CipherPunk/Services/GroupPolicyService.cs b/CipherPunk/Services/GroupPolicyService.cs index d7ca8ed..f2cd35d 100644 --- a/CipherPunk/Services/GroupPolicyService.cs +++ b/CipherPunk/Services/GroupPolicyService.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using System.Globalization; -using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Xml; using System.Xml.Linq; @@ -99,12 +98,12 @@ private static void UpdateOrderPolicy(string valueData, string valueName, REG_VA HRESULT coInitializeExResult = PInvoke.CoInitializeEx(COINIT.COINIT_APARTMENTTHREADED); if (coInitializeExResult.Failed) - throw Marshal.GetExceptionForHR(coInitializeExResult)!; + throw new Win32Exception(coInitializeExResult); HRESULT coCreateInstanceResult = PInvoke.CoCreateInstance(PInvoke.CLSID_GroupPolicyObject, null, CLSCTX.CLSCTX_INPROC_SERVER, out IGroupPolicyObject ppv); if (coCreateInstanceResult.Failed) - throw Marshal.GetExceptionForHR(coCreateInstanceResult)!; + throw new Win32Exception(coCreateInstanceResult); ppv.OpenLocalMachineGPO(GPO_OPEN_FLAGS.GPO_OPEN_LOAD_REGISTRY); @@ -159,12 +158,12 @@ private static void UpdateOrderPolicy(string valueData, string valueName, REG_VA HRESULT coInitializeExResult = PInvoke.CoInitializeEx(COINIT.COINIT_APARTMENTTHREADED); if (coInitializeExResult.Failed) - throw Marshal.GetExceptionForHR(coInitializeExResult)!; + throw new Win32Exception(coInitializeExResult); HRESULT coCreateInstanceResult = PInvoke.CoCreateInstance(PInvoke.CLSID_GroupPolicyObject, null, CLSCTX.CLSCTX_INPROC_SERVER, out IGroupPolicyObject ppv); if (coCreateInstanceResult.Failed) - throw Marshal.GetExceptionForHR(coCreateInstanceResult)!; + throw new Win32Exception(coCreateInstanceResult); ppv.OpenLocalMachineGPO(GPO_OPEN_FLAGS.GPO_OPEN_LOAD_REGISTRY); diff --git a/CipherPunk/Services/SchannelLogService.cs b/CipherPunk/Services/SchannelLogService.cs index 9d23a6f..71a83ea 100644 --- a/CipherPunk/Services/SchannelLogService.cs +++ b/CipherPunk/Services/SchannelLogService.cs @@ -86,6 +86,6 @@ public List GetSchannelLogs() } } - return schannelEventLogEntries.Where(q => !result.Select(r => r.ProcessId).Contains(q.ProcessId)).Select(q => q.SchannelLog).Concat(result).OrderByDescending(q => q.TimeGenerated).ToList(); + return [.. schannelEventLogEntries.Where(q => !result.Select(r => r.ProcessId).Contains(q.ProcessId)).Select(q => q.SchannelLog).Concat(result).OrderByDescending(q => q.TimeGenerated)]; } } \ No newline at end of file diff --git a/CipherPunk/Services/TlsService.cs b/CipherPunk/Services/TlsService.cs index 275153c..af0dced 100644 --- a/CipherPunk/Services/TlsService.cs +++ b/CipherPunk/Services/TlsService.cs @@ -129,7 +129,7 @@ private static async ValueTask GetIpEndPointAsync(string hostName, C ? Enum.GetValuesAsUnderlyingType().Cast().ToArray() : Enum.GetValuesAsUnderlyingType().Cast().Select(Convert.ToUInt32).ToArray(); - return (await Task.WhenAll(sslProviderCipherSuiteIds.Select(q => SendClientHelloAsync(endpoint, hostName, tlsVersion, tlsCompressionMethodIdentifiers, tlsEllipticCurvesPointFormats, tlsSignatureSchemes, tlsSupportedGroups, tlsPreSharedKeysKeyExchangeModes, keyShares, tlsCertificateCompressionAlgorithms, q, cancellationToken).AsTask()))).ToList(); + return [.. await Task.WhenAll(sslProviderCipherSuiteIds.Select(q => SendClientHelloAsync(endpoint, hostName, tlsVersion, tlsCompressionMethodIdentifiers, tlsEllipticCurvesPointFormats, tlsSignatureSchemes, tlsSupportedGroups, tlsPreSharedKeysKeyExchangeModes, keyShares, tlsCertificateCompressionAlgorithms, q, cancellationToken).AsTask()))]; } private static async ValueTask<(uint CipherSuiteId, bool Supported, string? ErrorReason)> SendClientHelloAsync( @@ -258,13 +258,14 @@ private static async ValueTask> SendClientHelloAsync(Memory c // https://tls12.xargs.org/ // https://wiki.osdev.org/TLS_Handshake using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - CancellationToken timeoutCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, new CancellationTokenSource(10000).Token).Token; + using var timeoutCancellationTokenSource = new CancellationTokenSource(10000); + using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellationTokenSource.Token); - await socket.ConnectAsync(endPoint, timeoutCancellationToken); + await socket.ConnectAsync(endPoint, linkedCancellationTokenSource.Token); - _ = await socket.SendAsync(clientHelloBytes, timeoutCancellationToken); + _ = await socket.SendAsync(clientHelloBytes, linkedCancellationTokenSource.Token); - int receivedBytes = await socket.ReceiveAsync(buffer, timeoutCancellationToken); + int receivedBytes = await socket.ReceiveAsync(buffer, linkedCancellationTokenSource.Token); return buffer[..receivedBytes]; }