Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signing: enable signed package verification on Linux by default in .NET 6 SDK #4706

Merged
merged 1 commit into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/NuGet.Core/NuGet.Build.Tasks/BuildTasksUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Credentials;
using NuGet.Packaging.Signing;
using NuGet.ProjectModel;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
Expand All @@ -25,7 +26,6 @@
using System.Xml.Linq;
using NuGet.Packaging;
using NuGet.Packaging.PackageExtraction;
using NuGet.Packaging.Signing;
using NuGet.PackageManagement;
using NuGet.ProjectManagement;
using NuGet.Shared;
Expand Down Expand Up @@ -191,6 +191,8 @@ public static async Task<bool> RestoreAsync(
UserAgent.SetUserAgentString(new UserAgentStringBuilder("NuGet Desktop MSBuild Task"));
#endif

X509TrustStore.InitializeForDotNetSdk(log);

var restoreSummaries = new List<RestoreSummary>();
var providerCache = new RestoreCommandProvidersCache();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ internal static void Register(CommandLineApplication app,

setLogLevel(XPlatUtility.MSBuildVerbosityToNuGetLogLevel(verbosity.Value()));

X509TrustStore.InitializeForDotNetSdk(args.Logger);

ISignCommandRunner runner = getCommandRunner();
int result = await runner.ExecuteCommandAsync(args);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.CommandLineUtils;
using NuGet.Commands;
Expand Down Expand Up @@ -267,6 +266,12 @@ private static async Task<int> ExecuteCommand(TrustCommand action,

setLogLevel(XPlatUtility.MSBuildVerbosityToNuGetLogLevel(verbosity.Value()));

// Add is the only action which does certificate chain building.
if (trustedSignersArgs.Action == TrustedSignersAction.Add)
{
X509TrustStore.InitializeForDotNetSdk(logger);
}

#pragma warning disable CS0618 // Type or member is obsolete
var sourceProvider = new PackageSourceProvider(settings, enablePackageSourcesChangedEvent: false);
#pragma warning restore CS0618 // Type or member is obsolete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using NuGet.Commands;
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Packaging.Signing;
using static NuGet.Commands.VerifyArgs;

namespace NuGet.CommandLine.XPlat
Expand Down Expand Up @@ -64,6 +65,8 @@ internal static void Register(CommandLineApplication app,
args.Settings = XPlatUtility.ProcessConfigFile(configFile.Value());
setLogLevel(XPlatUtility.MSBuildVerbosityToNuGetLogLevel(verbosity.Value()));

X509TrustStore.InitializeForDotNetSdk(args.Logger);

var runner = getCommandRunner();
var verifyTask = runner.ExecuteCommandAsync(args);
await verifyTask;
Expand Down
16 changes: 9 additions & 7 deletions src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -524,19 +524,21 @@ public override bool CanVerifySignedPackages(SignedPackageVerifierSettings verif
// Please note: Linux/MAC case sensitive for env var name.
string signVerifyEnvVariable = _environmentVariableReader.GetEnvironmentVariable("DOTNET_NUGET_SIGNATURE_VERIFICATION");

// Not opt-out option, only opt-in feature.
bool canVerify = RuntimeEnvironmentHelper.IsLinux;

if (!string.IsNullOrEmpty(signVerifyEnvVariable))
{
if (signVerifyEnvVariable.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase))
if (string.Equals(bool.TrueString, signVerifyEnvVariable, StringComparison.OrdinalIgnoreCase))
{
return true;
canVerify = true;
}
else if (string.Equals(bool.FalseString, signVerifyEnvVariable, StringComparison.OrdinalIgnoreCase))
{
canVerify = false;
}

// other values are unsupported
return false;
}

return false;
return canVerify;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

[assembly: CLSCompliant(true)]

[assembly: InternalsVisibleTo("Dotnet.Integration.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("NuGet.Packaging.FuncTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("NuGet.Packaging.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("NuGet.Commands.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Signing.X509TrustStore
static NuGet.Packaging.Signing.X509TrustStore.InitializeForDotNetSdk(NuGet.Common.ILogger logger) -> void
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Signing.X509TrustStore
static NuGet.Packaging.Signing.X509TrustStore.InitializeForDotNetSdk(NuGet.Common.ILogger logger) -> void
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Licenses.NuGetLicenseExpressionParsingException.NuGetLicenseExpressionParsingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) -> void
NuGet.Packaging.Signing.X509TrustStore
static NuGet.Packaging.Signing.X509TrustStore.InitializeForDotNetSdk(NuGet.Common.ILogger logger) -> void
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#if NET5_0_OR_GREATER

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace NuGet.Packaging.Signing
{
internal abstract class CertificateBundleX509ChainFactory : IX509ChainFactory
{
public X509Certificate2Collection Certificates { get; }
public string FilePath { get; }

protected CertificateBundleX509ChainFactory(X509Certificate2Collection certificates, string filePath = null)
{
Certificates = certificates;
FilePath = filePath;
}

public X509Chain Create()
{
X509Chain x509Chain = new();

x509Chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;

if (Certificates is not null && Certificates.Count > 0)
{
x509Chain.ChainPolicy.CustomTrustStore.AddRange(Certificates);
}

return x509Chain;
}

protected static bool TryImportFromPemFile(string filePath, out X509Certificate2Collection certificates)
{
certificates = new X509Certificate2Collection();

try
{
certificates.ImportFromPemFile(filePath);

return true;
}
catch (Exception ex) when
(
ex is CryptographicException ||
ex is FileNotFoundException ||
ex is DirectoryNotFoundException
)
{
certificates.Clear();
}

return false;
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Security.Cryptography.X509Certificates;

namespace NuGet.Packaging.Signing
{
internal sealed class DotNetDefaultTrustStoreX509ChainFactory : IX509ChainFactory
{
public X509Chain Create()
{
return new X509Chain();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#if NET5_0_OR_GREATER

using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading;

namespace NuGet.Packaging.Signing
{
internal sealed class FallbackCertificateBundleX509ChainFactory : CertificateBundleX509ChainFactory
{
// These constants are dictated by the .NET SDK.
internal const string SubdirectoryName = "trustedroots";
internal const string FileName = "codesignctl.pem";

private static readonly Lazy<string> ThisAssemblyDirectoryPath = new(GetThisAssemblyDirectoryPath, LazyThreadSafetyMode.ExecutionAndPublication);

private FallbackCertificateBundleX509ChainFactory(X509Certificate2Collection certificates, string filePath)
: base(certificates, filePath)
{
}

internal static bool TryCreate(out FallbackCertificateBundleX509ChainFactory factory, string fileName = FileName)
{
factory = null;

string fullFilePath = Path.Combine(
ThisAssemblyDirectoryPath.Value,
SubdirectoryName,
fileName ?? FileName);

if (TryImportFromPemFile(fullFilePath, out X509Certificate2Collection certificates))
{
factory = new FallbackCertificateBundleX509ChainFactory(certificates, fullFilePath);

return true;
}

return false;
}

private static string GetThisAssemblyDirectoryPath()
{
string location = typeof(FallbackCertificateBundleX509ChainFactory).Assembly.Location;
FileInfo thisAssembly = new(location);

return thisAssembly.DirectoryName;
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Security.Cryptography.X509Certificates;

namespace NuGet.Packaging.Signing
{
internal interface IX509ChainFactory
{
X509Chain Create();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#if NET5_0_OR_GREATER

using System.Security.Cryptography.X509Certificates;

namespace NuGet.Packaging.Signing
{
internal sealed class NoCertificateBundleX509ChainFactory : CertificateBundleX509ChainFactory
{
internal NoCertificateBundleX509ChainFactory()
: base(new X509Certificate2Collection())
{
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#if NET5_0_OR_GREATER

using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;

namespace NuGet.Packaging.Signing
{
internal sealed class SystemCertificateBundleX509ChainFactory : CertificateBundleX509ChainFactory
{
internal static readonly IReadOnlyList<string> ProbePaths = new[]
{
"/etc/pki/ca-trust/extracted/pem/objsign-ca-bundle.pem"
};

private SystemCertificateBundleX509ChainFactory(X509Certificate2Collection certificates, string filePath)
: base(certificates, filePath)
{
}

internal static bool TryCreate(out SystemCertificateBundleX509ChainFactory factory)
{
return TryCreate(ProbePaths, out factory);
}

// For testing purposes only.
internal static bool TryCreate(IReadOnlyList<string> probePaths, out SystemCertificateBundleX509ChainFactory factory)
{
factory = null;

foreach (string probePath in probePaths)
{
if (TryImportFromPemFile(probePath, out X509Certificate2Collection certificates)
&& certificates.Count > 0)
{
factory = new SystemCertificateBundleX509ChainFactory(certificates, probePath);

return true;
}
}

return false;
}
}
}

#endif
Loading