diff --git a/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/NuGetSdkResolver.cs b/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/NuGetSdkResolver.cs index 2c0055cdda8..199af66a1c0 100644 --- a/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/NuGetSdkResolver.cs +++ b/src/NuGet.Core/Microsoft.Build.NuGetSdkResolver/NuGetSdkResolver.cs @@ -15,6 +15,7 @@ using NuGet.Credentials; using NuGet.LibraryModel; using NuGet.Packaging; +using NuGet.Packaging.Signing; using NuGet.Versioning; namespace Microsoft.Build.NuGetSdkResolver @@ -146,6 +147,10 @@ public static SdkResult GetSdkResult(SdkReference sdk, object nuGetVersion, SdkR { DefaultCredentialServiceUtility.SetupDefaultCredentialService(logger, nonInteractive: !context.Interactive); +#if !NETFRAMEWORK + X509TrustStore.InitializeForDotNetSdk(logger); +#endif + // Asynchronously run the restore without a commit which find the package on configured feeds, download, and unzip it without generating any other files // This must be run in its own task because legacy project system evaluates projects on the UI thread which can cause RunWithoutCommit() to deadlock // https://developercommunity.visualstudio.com/content/problem/311379/solution-load-never-completes-when-project-contain.html diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommand.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommand.cs index 2366fb1918e..41d770b98db 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommand.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommand.cs @@ -6,6 +6,7 @@ using System.IO; using Microsoft.Extensions.CommandLineUtils; using NuGet.Common; +using NuGet.Packaging.Signing; namespace NuGet.CommandLine.XPlat { @@ -101,6 +102,9 @@ public static void Register(CommandLineApplication app, Func getLogger, PackageId = id.Values[0] }; var msBuild = new MSBuildAPIUtility(logger); + + X509TrustStore.InitializeForDotNetSdk(logger); + var addPackageRefCommandRunner = getCommandRunner(); return addPackageRefCommandRunner.ExecuteCommand(packageRefArgs, msBuild); }); diff --git a/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs b/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs index 6136a5506e0..ec086d21330 100644 --- a/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs +++ b/src/NuGet.Core/NuGet.Packaging/PackageArchiveReader.cs @@ -524,7 +524,7 @@ public override bool CanVerifySignedPackages(SignedPackageVerifierSettings verif // Please note: Linux/MAC case sensitive for env var name. string signVerifyEnvVariable = _environmentVariableReader.GetEnvironmentVariable("DOTNET_NUGET_SIGNATURE_VERIFICATION"); - bool canVerify = RuntimeEnvironmentHelper.IsLinux; + bool canVerify = false; if (!string.IsNullOrEmpty(signVerifyEnvVariable)) { diff --git a/src/NuGet.Core/NuGet.Packaging/Signing/TrustStore/X509TrustStore.cs b/src/NuGet.Core/NuGet.Packaging/Signing/TrustStore/X509TrustStore.cs index 4acb76f4829..4fc11405873 100644 --- a/src/NuGet.Core/NuGet.Packaging/Signing/TrustStore/X509TrustStore.cs +++ b/src/NuGet.Core/NuGet.Packaging/Signing/TrustStore/X509TrustStore.cs @@ -71,7 +71,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log if (SystemCertificateBundleX509ChainFactory.TryCreate( out SystemCertificateBundleX509ChainFactory systemBundleFactory)) { - logger.LogVerbose( + logger.LogInformation( string.Format( CultureInfo.CurrentCulture, Strings.ChainBuilding_UsingSystemCertificateBundle, @@ -84,7 +84,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory, fallbackCertificateBundleFile?.FullName)) { - logger.LogVerbose( + logger.LogInformation( string.Format( CultureInfo.CurrentCulture, Strings.ChainBuilding_UsingFallbackCertificateBundle, @@ -93,7 +93,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log return fallbackBundleFactory; } - logger.LogVerbose(Strings.ChainBuilding_UsingNoCertificateBundle); + logger.LogInformation(Strings.ChainBuilding_UsingNoCertificateBundle); return new NoCertificateBundleX509ChainFactory(); } @@ -104,7 +104,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log out FallbackCertificateBundleX509ChainFactory fallbackBundleFactory, fallbackCertificateBundleFile?.FullName)) { - logger.LogVerbose( + logger.LogInformation( string.Format( CultureInfo.CurrentCulture, Strings.ChainBuilding_UsingFallbackCertificateBundle, @@ -113,7 +113,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log return fallbackBundleFactory; } - logger.LogVerbose(Strings.ChainBuilding_UsingNoCertificateBundle); + logger.LogInformation(Strings.ChainBuilding_UsingNoCertificateBundle); return new NoCertificateBundleX509ChainFactory(); } @@ -125,7 +125,7 @@ internal static IX509ChainFactory CreateX509ChainFactoryForDotNetSdk(ILogger log // Non-private for testing purposes only internal static IX509ChainFactory CreateX509ChainFactory(ILogger logger) { - logger.LogVerbose(Strings.ChainBuilding_UsingDefaultTrustStore); + logger.LogInformation(Strings.ChainBuilding_UsingDefaultTrustStore); return new DotNetDefaultTrustStoreX509ChainFactory(); } diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs index f46a2f198b3..42aeb037f91 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetAddPackageTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using FluentAssertions; +using NuGet.Common; using NuGet.Packaging; using NuGet.Packaging.Core; using NuGet.ProjectModel; @@ -613,5 +614,75 @@ await SimpleTestPackageUtility.CreateFolderFeedV3Async( Assert.Contains($"Installed {packageX} {version} from {packageSource2}", result.AllOutput); Assert.Contains($"NU1100: Unable to resolve '{packageZ} (>= {version})' for 'net5.0'", result.AllOutput); } + + [Fact] + public void AddPkg_WhenSourceIsSignedPackageWithExpiredCertificatesAndWithTimestamps_Success() + { + using (SimpleTestPathContext pathContext = new()) + { + var projectName = "project"; + var targetFrameworks = "net6.0"; + SimpleTestProjectContext projectA = XPlatTestUtils.CreateProject(projectName, pathContext, targetFrameworks); + + // This package is important because: + // * it has no package dependencies and thus simplifies the test scenario + // * it is a signed package and thus verifies signed package verification, if enabled + // * the author- and repository-signing certificates have expired + // * the author and repository timestamps may be untrusted on Linux/macOS if a valid certificate bundle isn't found + PackageIdentity package = new("NuGet.Versioning", new NuGetVersion("5.0.0")); + DirectoryInfo packageSourceDirectory = new(Path.Combine(pathContext.WorkingDirectory, "PackageSource")); + var packageFileName = $"{package.Id.ToLowerInvariant()}.{package.Version}.nupkg"; + + CopyResourceToDirectory(packageFileName, packageSourceDirectory); + + string projectDirectory = Path.Combine(pathContext.SolutionRoot, projectName); + string projectFilePath = Path.Combine(projectDirectory, $"{projectName}.csproj"); + + CommandRunnerResult result = _fixture.RunDotnet( + projectDirectory, + $"add {projectFilePath} package {package.Id} -s {packageSourceDirectory.FullName} -v {package.Version}", + ignoreExitCode: true); + + result.Success.Should().BeTrue(because: result.AllOutput); + + if (RuntimeEnvironmentHelper.IsWindows) + { + result.AllOutput.Should() + .Contain( + Strings.ChainBuilding_UsingDefaultTrustStore, + because: result.AllOutput); + } + else + { + result.AllOutput.Should() + .ContainAny( + new string[] { + "X.509 certificate chain validation will use the fallback certificate bundle at ", + "X.509 certificate chain validation will use the system certificate bundle at " + }, + because: result.AllOutput); + } + + LockFileTarget ridlessTarget = projectA.AssetsFile.Targets + .Where(e => string.IsNullOrEmpty(e.RuntimeIdentifier)) + .Single(); + + ridlessTarget.Libraries.Should().Contain(e => e.Type == "package" && e.Name == package.Id); + ridlessTarget.Libraries.Should().Contain(e => e.Version.Equals(package.Version)); + } + } + + private void CopyResourceToDirectory(string resourceName, DirectoryInfo directory) + { + string fullResourceName = $"Dotnet.Integration.Test.compiler.resources.{resourceName}"; + string destinationFilePath = Path.Combine(directory.FullName, resourceName); + + directory.Create(); + + using (Stream stream = GetType().Assembly.GetManifestResourceStream(fullResourceName)) + { + stream.CopyToFile(destinationFilePath); + } + } } } diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/X509TrustStoreTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/X509TrustStoreTests.cs index 038cc5d4a85..0e86e6c0063 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/X509TrustStoreTests.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/X509TrustStoreTests.cs @@ -29,8 +29,8 @@ public X509TrustStoreTests(MsbuildIntegrationTestFixture msbuildFixture, ITestOu FallbackCertificateBundleX509ChainFactory.SubdirectoryName, FallbackCertificateBundleX509ChainFactory.FileName)); - _logger.LogInformation($"Expected fallback certificate bundle file path: {_fallbackCertificateBundle.FullName}"); - _logger.LogInformation($"Fallback certificate bundle file exists: {_fallbackCertificateBundle.Exists}"); + _logger.LogVerbose($"Expected fallback certificate bundle file path: {_fallbackCertificateBundle.FullName}"); + _logger.LogVerbose($"Fallback certificate bundle file exists: {_fallbackCertificateBundle.Exists}"); } [PlatformFact(Platform.Windows)] @@ -44,8 +44,8 @@ public void CreateX509ChainFactoryForDotNetSdk_OnWindowsAlways_ReturnsInstance() // 1 message from the API under test and 2 messages from this test class's constructor Assert.Equal(3, _logger.Messages.Count); - Assert.Equal(1, _logger.VerboseMessages.Count); - Assert.True(_logger.VerboseMessages.TryDequeue(out string actualMessage)); + Assert.Equal(1, _logger.InformationMessages.Count); + Assert.True(_logger.InformationMessages.TryPeek(out string actualMessage)); Assert.Equal(Strings.ChainBuilding_UsingDefaultTrustStore, actualMessage); } @@ -75,8 +75,8 @@ public void CreateX509ChainFactoryForDotNetSdk_OnLinuxAlways_ReturnsInstance() // 1 message from the API under test and 2 messages from this test class's constructor Assert.Equal(3, _logger.Messages.Count); - Assert.Equal(1, _logger.VerboseMessages.Count); - Assert.True(_logger.VerboseMessages.TryDequeue(out string actualMessage)); + Assert.Equal(1, _logger.InformationMessages.Count); + Assert.True(_logger.InformationMessages.TryPeek(out string actualMessage)); string expectedMessage; @@ -114,8 +114,8 @@ public void CreateX509ChainFactoryForDotNetSdk_OnMacOsAlways_ReturnsInstance() // 1 message from the API under test and 2 messages from this test class's constructor Assert.Equal(3, _logger.Messages.Count); - Assert.Equal(1, _logger.VerboseMessages.Count); - Assert.True(_logger.VerboseMessages.TryDequeue(out string actualMessage)); + Assert.Equal(1, _logger.InformationMessages.Count); + Assert.True(_logger.InformationMessages.TryPeek(out string actualMessage)); Assert.Equal(expectedMessage, actualMessage); } diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/compiler/resources/nuget.versioning.5.0.0.nupkg b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/compiler/resources/nuget.versioning.5.0.0.nupkg new file mode 100644 index 00000000000..752d3ddd0ad Binary files /dev/null and b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/compiler/resources/nuget.versioning.5.0.0.nupkg differ diff --git a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TrustStore/X509TrustStoreTests.cs b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TrustStore/X509TrustStoreTests.cs index a17efcdeabf..d2f144cc659 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TrustStore/X509TrustStoreTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Packaging.FuncTest/SigningTests/TrustStore/X509TrustStoreTests.cs @@ -47,8 +47,8 @@ public void CreateX509ChainFactory_Always_ReturnsInstance() Assert.IsType(factory); Assert.Equal(1, _logger.Messages.Count); - Assert.Equal(1, _logger.VerboseMessages.Count); - Assert.True(_logger.VerboseMessages.TryDequeue(out string actualMessage)); + Assert.Equal(1, _logger.InformationMessages.Count); + Assert.True(_logger.InformationMessages.TryDequeue(out string actualMessage)); Assert.Equal(Strings.ChainBuilding_UsingDefaultTrustStore, actualMessage); } } diff --git a/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Test/NuGetSdkResolver_Tests.cs b/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Test/NuGetSdkResolver_Tests.cs index 9382a3edd20..d734930404d 100644 --- a/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Test/NuGetSdkResolver_Tests.cs +++ b/test/NuGet.Core.Tests/Microsoft.Build.NuGetSdkResolver.Test/NuGetSdkResolver_Tests.cs @@ -5,7 +5,6 @@ using System.IO; using FluentAssertions; using Microsoft.Build.Framework; -using Moq; using NuGet.Packaging; using NuGet.Test.Utility; using NuGet.Versioning; @@ -77,6 +76,29 @@ public void Resolve_WhenPackageExists_ReturnsSucceededSdkResult() result.Version.Should().Be(sdkReference.Version); result.Errors.Should().BeEmpty(); result.Warnings.Should().BeEmpty(); + + bool wasMessageFound = false; + + foreach ((string Message, MessageImportance _) in sdkResolverContext.MockSdkLogger.LoggedMessages) + { + // On Linux and macOS the message will be: + // + // X.509 certificate chain validation will not have any trusted roots. + // Chain building will fail with an untrusted status. + // + // This is because this test is not a .NET SDK test but a unit test. + if (Message.Contains("X.509 certificate chain validation will")) + { + wasMessageFound = true; + break; + } + } + +#if NETFRAMEWORK + wasMessageFound.Should().BeFalse(); +#else + wasMessageFound.Should().BeTrue(); +#endif } } diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs index ff338c73f6d..a1010cf476c 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageArchiveReaderTests.cs @@ -1976,23 +1976,19 @@ private static byte[] CreateNonEmptyZipArchive() } #endif - [PlatformFact(Platform.Windows, Platform.Linux)] - public void CanVerifySignedPackages_OnWindowsAndLinux_ReturnsValueBasedOnOperatingSystemAndFramework() + [Fact] + public void CanVerifySignedPackages_Always_ReturnsValueBasedOnOperatingSystemAndFramework() { // Arrange using (var test = TestPackagesCore.GetPackageContentReaderTestPackage()) using (var packageArchiveReader = new PackageArchiveReader(test)) { + bool expectedResult = CanVerifySignedPackages(); + // Act - var result = packageArchiveReader.CanVerifySignedPackages(null); - // Assert -#if IS_SIGNING_SUPPORTED - // Verify package signature when signing is supported - Assert.True(result); -#else - // Cannot verify package signature when signing is not supported - Assert.False(result); -#endif + bool actualResult = packageArchiveReader.CanVerifySignedPackages(null); + + Assert.Equal(expectedResult, actualResult); } } @@ -2011,23 +2007,6 @@ public void CanVerifySignedPackages_OnMacOs_ReturnsValueBasedOnOperatingSystemAn } } - [Fact] - public void CanVerifySignedPackages_ReturnsValueBasedOnOperatingSystemAndFramework_Fails() - { - // Arrange - using (var test = TestPackagesCore.GetPackageContentReaderTestPackage()) - using (var packageArchiveReader = new PackageArchiveReader(test)) - { - bool expectedResult = CanVerifySignedPackages(); - - // Act - bool actualResult = packageArchiveReader.CanVerifySignedPackages(null); - - // Assert - Assert.Equal(expectedResult, actualResult); - } - } - [Theory] [InlineData("TRUE")] [InlineData("True")] @@ -2123,7 +2102,7 @@ public void CanVerifySignedPackages_ReturnsValueBasedOnOperatingSystemAndFramewo private static bool CanVerifySignedPackages() { - return (RuntimeEnvironmentHelper.IsWindows || RuntimeEnvironmentHelper.IsLinux) && + return RuntimeEnvironmentHelper.IsWindows && #if IS_SIGNING_SUPPORTED true; #else