-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
add signature VerifySigning for dotnet tools #39268
add signature VerifySigning for dotnet tools #39268
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some scenarios to test (manually):
- Can you install a non-Microsoft tool from NuGet.org?
- Can you install a locally-built tool (which won't be signed at all)?
src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
Outdated
Show resolved
Hide resolved
src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
Outdated
Show resolved
Hide resolved
Thank you very much for the review! For the two manual test questions:
Yes, for example,
No, from manual test, locally built tools cannot be installed because the signing is not validated. I think this is not the expected behavior and will need a work-around about this. |
Yes, I think we would want to use the same type of logic that NuGet uses for PackageReferences to determine whether we need to verify whether the package is signed. |
{ | ||
if (!_firstPartyNuGetPackageSigningVerifier.Verify(new FilePath(nupkgPath), | ||
out string commandOutput)) | ||
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the default behavior be the same as https://github.com/dotnet/sdk/pull/31868/files, driven by the same environment variable?
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||
if (!_isNuGetTool) | ||
{ | ||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as https://github.com/dotnet/sdk/pull/39268/files#r1586876370
private static bool NuGetVerify(FilePath nupkgToVerify, out string commandOutput) | ||
{ | ||
var args = new[] { "verify", "--all", nupkgToVerify.Value }; | ||
var command = new DotNetCommandFactory(alwaysRunOutOfProc: true) | ||
.Create("nuget", args); | ||
|
||
var commandResult = command.CaptureStdOut().Execute(); | ||
commandOutput = commandResult.StdOut + Environment.NewLine + commandResult.StdErr; | ||
return commandResult.ExitCode == 0; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we leverage the existing logic instead of code duplication?
sdk/src/Cli/dotnet/NugetPackageDownloader/FirstPartyNuGetPackageSigningVerifier.cs
Line 36 in 4544337
public bool Verify(FilePath nupkgToVerify, out string commandOutput) |
@@ -157,18 +154,48 @@ private void VerifySigning(string nupkgPath) | |||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this is the correct location to add the comment. It could be possible that I don't have a good understanding of the code in this repo. I think we should set verifySignatures
to true
when trying to execute the dotnet tool install
command.
If we don't set verifySignatures = true
, then I think this if
block will cause the control to return immediately, thereby skipping signature verification.
nugetPackageDownloader ??= new NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreAction, verbosityOptions: _verbosity);
Suggestion is to pass the optional parameter `verifySignatures = true` here also.
@@ -54,7 +54,8 @@ public void GivenNugetConfigInstallSucceeds(bool testMockBehaviorIsInSync) | |||
verbosity: TestVerbosity, | |||
versionRange: VersionRange.Parse(TestPackageVersion), | |||
targetFramework: _testTargetframework, | |||
isGlobalTool: true); | |||
isGlobalTool: true, | |||
verifySignatures: false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a test that does verify signatures?
c681a27
to
aaeccf3
Compare
src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
Outdated
Show resolved
Hide resolved
src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
Outdated
Show resolved
Hide resolved
This test can no longer work. The sign check only happens when a nuget package source says the nuget package should be signed, and the only way to make that happen in a test is to download the package from an https resource, which generally isn't a good idea in the middle of a test regardless and certainly isn't a good idea if we need to find a package that should be signed but isn't (i.e., may be malicious). I propose replacing this test with manual tests.
Yes, I believe so. I reran the failing leg, and it failed again, so I think it's a real failure. It seems to be because a package is very out-of-date, so I think the right answer is just to update to a later package. The failing tests are for unlisted packages, though, and I'm not sure how to find them. @joeloff, is there a way to find a more up-to-date unlisted package we can use for those tests? |
if ((!_shouldUsePackageSourceMapping && !_firstPartyNuGetPackageSigningVerifier.Verify(new FilePath(nupkgPath), out commandOutput)) || | ||
(_shouldUsePackageSourceMapping && !FirstPartyNuGetPackageSigningVerifier.NuGetVerify(new FilePath(nupkgPath), out commandOutput, _currentWorkingDirectory))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between _firstPartyNuGetPackageSigningVerifier.Verify
and FirstPartyNuGetPackageSigningVerifier.NuGetVerify
? That's not obvious to me and it seems like a comment explaining would be helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They certainly look the same. I can add a comment. It's whether or not it should additionally check that it's a first-party binary or not.
@@ -89,7 +94,7 @@ public ToolInstallGlobalOrToolPathCommand( | |||
NoCache: (parseResult.GetValue(ToolCommandRestorePassThroughOptions.NoCacheOption) || parseResult.GetValue(ToolCommandRestorePassThroughOptions.NoHttpCacheOption)), | |||
IgnoreFailedSources: parseResult.GetValue(ToolCommandRestorePassThroughOptions.IgnoreFailedSourcesOption), | |||
Interactive: parseResult.GetValue(ToolCommandRestorePassThroughOptions.InteractiveRestoreOption)); | |||
nugetPackageDownloader ??= new NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreAction, verbosityOptions: _verbosity); | |||
nugetPackageDownloader ??= new NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreAction, verbosityOptions: _verbosity, verifySignatures: true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like _verifySignatures
isn't being used here. Shouldn't it be?
nugetPackageDownloader ??= new NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreAction, verbosityOptions: _verbosity, verifySignatures: true); | |
nugetPackageDownloader ??= new NuGetPackageDownloader(tempDir, verboseLogger: new NullLogger(), restoreActionConfig: restoreAction, verbosityOptions: _verbosity, verifySignatures: _verifySignatures ?? true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This NuGetPackageDownloader is only used to find the app host, so I didn't think I needed to change this, but when I dug a little deeper just now, it does download the app host, so I think that if someone has a feed with a malicious version of the app host that returns faster than nuget.org, that could be bad, so I think you're right. Good catch.
Edit: I missed that it was changed here to unconditionally be true. Since this should always be a Microsoft package, I think it should always be signed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessarily, what happens when you're using a daily build of .NET and pulling the apphost from the dotnet-public feed? Those would neither have repository signatures and the package would also not have publisher signatures from Microsoft.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Note that verifySignatures was not available here before the test change, so if the consensus is that it is needed for that nugetPackageDownloader, then we need to keep (at least part of) the test changes as well.
@@ -54,7 +54,8 @@ public void GivenNugetConfigInstallSucceeds(bool testMockBehaviorIsInSync) | |||
verbosity: TestVerbosity, | |||
versionRange: VersionRange.Parse(TestPackageVersion), | |||
targetFramework: _testTargetframework, | |||
isGlobalTool: true); | |||
isGlobalTool: true, | |||
verifySignatures: false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need all these test changes to specify verifySignatures = false? It seems to me like in the tests there won't be a RepositorySignatureResource
or it won't specify AllRepositorySigned
, so the downloader won't verify the signatures anyway and we shouldn't need all these test changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short answer: yes.
You can see the full list of changes needed for the test in 131cff5
You are generally correct that we won't verify signatures anyway in tests, but there are two tests that were different: the tests for unlisted packages. Since local feeds can't provide unlisted packages, JL03-Yue used the package the customer provided in writing tests to ensure that dotnet tool restore can find unlisted packages if necessary, and it turns out that package does claim to be signed, but the signature isn't valid, and it fails the test.
I have to admit that it took a lot of changes to thread through verifySignatures: false to a point where it could actually affect the test, and even after I got that part to work, the tests still needed more changes to find the right rid graph json, etc. If we don't want all those changes, the only alternative proposals I'm aware of are to either find another unlisted package that's signed correctly (but I/standup yesterday didn't know how to do that) or disable the test. marcpopMSFT sounded like he was most in favor of disabling the tests and avoiding all the other changes. If that's your preference as well, I can revert those last two commits and just disable them.
Fixes dotnet#37469 Add signature verifications for NuGet Tools
</data> | ||
<data name="NuGetPackageShouldNotBeSigned" xml:space="preserve"> | ||
<value>Skipping signature verification for NuGet package "{0}" because it comes from a source that does not require signature validation.</value> | ||
</data> | ||
<data name="SkipNuGetpackageSigningValidationmacOSLinux" xml:space="preserve"> | ||
<value>Skip NuGet package signing validation. NuGet signing validation is not available on Linux or macOS https://aka.ms/workloadskippackagevalidation .</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This aka.ms link points to an announcement which doesn't apply to more recent versions of .NET.
Signed package verification is supported on Linux. See https://learn.microsoft.com/en-us/dotnet/core/tools/nuget-signed-package-verification#linux.
Fixes dotnet#37469 Add signature verifications for NuGet Tools
#37469
Add signature verifications for NuGet Tools