Skip to content

Commit

Permalink
Merge pull request #3123 from vexx32/tls-security-protocols
Browse files Browse the repository at this point in the history
(#2902) Use .NET recommended practices for TLS protocol handling
  • Loading branch information
gep13 authored Apr 19, 2023
2 parents ced3b70 + 17bf150 commit b18c480
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 56 deletions.
1 change: 1 addition & 0 deletions src/chocolatey/chocolatey.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@
<Compile Include="infrastructure\logging\LogMessage.cs" />
<Compile Include="infrastructure\logging\LogSinkLog.cs" />
<Compile Include="infrastructure\registration\AssemblyResolution.cs" />
<Compile Include="infrastructure\registration\HttpsSecurity.cs" />
<Compile Include="infrastructure\rules\IMetadataRule.cs" />
<Compile Include="infrastructure\rules\RuleResult.cs" />
<Compile Include="infrastructure\rules\RuleType.cs" />
Expand Down
6 changes: 3 additions & 3 deletions src/chocolatey/infrastructure.app/runners/GenericRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public void Run(ChocolateyConfiguration config, Container container, bool isCons
}

FailOnMissingOrInvalidLicenseIfFeatureSet(config);
SecurityProtocol.SetProtocol(provideWarning: true);
HttpsSecurity.Reset();
EventManager.Publish(new PreRunMessage(config));

try
Expand Down Expand Up @@ -230,7 +230,7 @@ public IEnumerable<T> List<T>(ChocolateyConfiguration config, Container containe
}

FailOnMissingOrInvalidLicenseIfFeatureSet(config);
SecurityProtocol.SetProtocol(provideWarning: true);
HttpsSecurity.Reset();
EventManager.Publish(new PreRunMessage(config));

try
Expand Down Expand Up @@ -266,7 +266,7 @@ public IEnumerable<T> List<T>(ChocolateyConfiguration config, Container containe
public int Count(ChocolateyConfiguration config, Container container, bool isConsole, Action<ICommand> parseArgs)
{
FailOnMissingOrInvalidLicenseIfFeatureSet(config);
SecurityProtocol.SetProtocol(provideWarning: true);
HttpsSecurity.Reset();

var command = FindCommand(config, container, isConsole, parseArgs) as IListCommand;
if (command == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ public bool RunAction(ChocolateyConfiguration configuration, PackageResult packa
if (configuration.Features.UsePowerShellHost)
{
RemoveAssemblyResolver();
HttpsSecurity.Reset();
}

if (result.StandardErrorWritten && configuration.Features.FailOnStandardError)
Expand Down Expand Up @@ -540,7 +541,7 @@ public void PreparePowerShellEnvironment(IPackageSearchMetadata package, Chocola
}
}

SecurityProtocol.SetProtocol(provideWarning: false);
HttpsSecurity.Reset();
}

private ResolveEventHandler _handler = null;
Expand Down
63 changes: 63 additions & 0 deletions src/chocolatey/infrastructure/registration/HttpsSecurity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace chocolatey.infrastructure.registration
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

internal static class HttpsSecurity
{
/// <summary>
/// Resets the <see cref="ServicePointManager.SecurityProtocol"/> and <see cref="ServicePointManager.ServerCertificateValidationCallback"/> for HTTPS connections
/// in order to ensure that PowerShell scripts we run can't have a persistent effect on these settings across the whole process after they're done running.
/// </summary>
internal static void Reset()
{
// SystemDefault is used because:
// 1. Most supported operating systems default to / require TLS 1.2 anyway.
// 2. Explicitly *enabling* any less secure protocols leaves us open to TLS downgrade attacks.
// https://en.wikipedia.org/wiki/Downgrade_attack
// 3. Always *requiring* TLS 1.2 or higher on any OS version may cause issues with some folks' internal
// networks which may have older infrastructure that doesn't support it, and they won't have a way
// to make Chocolately CLI work with that infrastructure if we're forcing a TLS version they can't
// support.
// 4. Thus, the only sensible solution (since we don't want to add a configuration value for this) is
// to take the OS-level setting and use that, because if folks set their system up to use certain
// TLS versions, we should probably follow suit, regardless of what their OS version may be.
//
// See https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls for more information
// and best practices recommendation from the .NET team.
if (ServicePointManager.SecurityProtocol != SecurityProtocolType.SystemDefault)
{
"chocolatey".Log().Warn(
"{0} was set to {1}, resetting to SystemDefault.",
nameof(ServicePointManager.SecurityProtocol),
ServicePointManager.SecurityProtocol);

ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
}

try
{
// We reset this to ensure that if a package overrides this callback during its script runs, it doesn't affect the rest of
// the actions we need to take for the duration of this process (other packages we're installing, etc.) Setting this to
// null restores the default behaviour of certificate validation instead of whatever custom behaviour has been injected.
if (ServicePointManager.ServerCertificateValidationCallback != null)
{
"chocolatey".Log().Warn(
"{0} was set to '{1}' Removing.",
nameof(ServicePointManager.ServerCertificateValidationCallback),
ServicePointManager.ServerCertificateValidationCallback);

ServicePointManager.ServerCertificateValidationCallback = null;
}
}
catch (Exception ex)
{
"chocolatey".Log().Warn("Error resetting ServerCertificateValidationCallback: {0}".FormatWith(ex.Message));
}
}
}
}
54 changes: 2 additions & 52 deletions src/chocolatey/infrastructure/registration/SecurityProtocol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,62 +21,12 @@ namespace chocolatey.infrastructure.registration
using app.configuration;
using logging;

[Obsolete("This type is deprecated and will be removed in v3.")]
public sealed class SecurityProtocol
{
private const int Tls11 = 768;
private const int Tls12 = 3072;

public static void SetProtocol(bool provideWarning)
{
try
{
// TODO: Streamline this method now that we are building against .NET 4.8

// We can't address the protocols directly when built with .NET
// Framework 4.0. However if someone is running .NET 4.5 or
// greater, they have in-place upgrades for System.dll, which
// will allow us to set these protocols directly.
const SecurityProtocolType tls11 = (SecurityProtocolType)Tls11;
const SecurityProtocolType tls12 = (SecurityProtocolType)Tls12;
ServicePointManager.SecurityProtocol = tls12 | tls11 | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
}
catch (Exception)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
//todo: #2585 provide this warning with the ability to opt out of seeing it again so we can move it up to more prominent visibility and not just the verbose log
if (provideWarning)
{
"chocolatey".Log().Warn(ChocolateyLoggers.Verbose,
@" !!WARNING!!
Choco prefers to use TLS v1.2 if it is available, but this client is
running on .NET 4.0, which uses an older SSL. It's using TLS 1.0 or
earlier, which makes it susceptible to BEAST and also doesn't
implement the 1/n-1 record splitting mitigation for Cipher-Block
Chaining. Upgrade to at least .NET 4.5 at your earliest convenience.
For more information you should visit https://www.howsmyssl.com/");
}
}

try
{
if (ServicePointManager.ServerCertificateValidationCallback != null)
{
"chocolatey".Log().Warn("ServerCertificateValidationCallback was set to '{0}' Removing.".FormatWith(System.Net.ServicePointManager.ServerCertificateValidationCallback));
ServicePointManager.ServerCertificateValidationCallback = null;
}
}
catch (Exception ex)
{
"chocolatey".Log().Warn("Error resetting ServerCertificateValidationCallback: {0}".FormatWith(ex.Message));
}
}


#pragma warning disable IDE1006
[Obsolete("This overload is deprecated and will be removed in v3.")]
public static void set_protocol(ChocolateyConfiguration config, bool provideWarning)
=> SetProtocol(provideWarning);
=> HttpsSecurity.Reset();
#pragma warning restore IDE1006
}
}

0 comments on commit b18c480

Please sign in to comment.